ONO.speed - Stake Smooth Speed Hack

Smooth, optimized speed scaling (rAF delta), timers auto-on, CSS snap for near-instant animations. Collapsible advanced options. Max speed capped at 9.9x.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name          ONO.speed -  Stake Smooth Speed Hack
// @namespace     https://github.com/cutiejf/stakespeed/blob/main/ono.speed
// @version       3.0.1
// @description   Smooth, optimized speed scaling (rAF delta), timers auto-on, CSS snap for near-instant animations. Collapsible advanced options. Max speed capped at 9.9x.
// @author        jayfantz
// @match         https://stake.com/*
// @grant         none
// ==/UserScript==
(function () {
    'use strict';

    // ---------------- State / Config
    let speed = 1.0;
    const bootTime = performance.now();
    let scaledTimeOffset = 0;

    const MAX_SPEED = 9.9;
    const MAX_Z_INDEX = '2147483647';
    const BORDER_PURPLE = '#7340a3';

    const hooks = {
        requestAnimationFrame: true,
        setTimeout: true,
        setInterval: true,
        css: true,
        time: false,
        date: false,
        gsap: null,
        pixi: null,
        three: null,
        anime: null,
        velocity: null,
    };
    const CSS_SNAP_S = 0.015;
    const MIN_TIMEOUT_MS = 0;
    const MIN_INTERVAL_MS = 1;

    // ---------------- Colors
const C = {
  deepNavy:      '#0f212e',   // background / footer base
  darkPill:      '#1f3341',   // main panel body
  darkerButton:  '#0c1a25',   // inner button tone or accent divs
  midGray:       '#55646e',   // borders, lines, text subtle
  lightGray:     '#909ba1',   // primary text
  actionGreen:   '#107721',   // buttons, highlights, icons
  shadow:        '#263a46'    // shadow / glow edge
};


    // ---------------- Keep native refs
    const native = {
        setTimeout: window.setTimeout.bind(window),
        setInterval: window.setInterval.bind(window),
        requestAnimationFrame: window.requestAnimationFrame.bind(window),
        performance: window.performance,
        Date: window.Date,
    };

    // --- Helper function to format speed ---
    function formatSpeed(s) {
        // Bold the number AND the 'x' multiplier
        return `<b style="font-size: 18px;">${s.toFixed(1)}</b> <b style="font-style: italic;">x</b>`;
    }

    // --- Core Styling for Shadow DOM (Must be self-contained) ---
const globalStyle = `
  * {
    box-sizing: border-box !important;
    font-family: Inter, system-ui, -apple-system, Segoe UI, Arial, sans-serif !important;
    color: ${C.lightGray} !important;
    margin: 0 !important;
    line-height: 1.2 !important;
    user-select: none !important;
  }

  #gauge-wrapper {
    position: fixed;
    top: 40px;
    left: 40px;
    z-index: ${MAX_Z_INDEX};
    cursor: default;
  }

  #gauge {
    background: ${C.darkPill};
    border: 3px solid ${C.midGray};
    border-radius: 18px;
    display: flex;
    flex-direction: column;
    cursor: move;
    box-shadow:
    inset 0 1px 3px rgba(255,255,255,0.06),
    inset 0 -2px 5px rgba(0,0,0,0.6),
    0 0 22px ${C.shadow}bb,
    0 0 30px rgba(15,33,46,0.45);
  }

#gauge-header {
  display: flex;
  align-items: center;
  padding: 8px 10px 6px 12px !important;
  gap: 8px;
  box-shadow:         inset 0 2px 4px rgba(0,0,0,0.75),  /* deep inner top shadow */
    inset 0 2px 4px rgba(255,255,255,0.05); /* subtle lower light */
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
}

  #gauge-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: ${C.deepNavy};
    border-top: 1px solid ${C.midGray};
    border-bottom-left-radius: 14px;
    border-bottom-right-radius: 14px;
    padding: 8px 18px !important;
  }

  #gauge-footer span {
    font-size: 11px !important;
    color: ${C.lightGray}cc !important;
    font-weight: 700 !important;
  }

  #footer-arrow {
    cursor: pointer !important;
    font-size: 16px !important;
    color: ${C.actionGreen} !important;
    font-weight: bold !important;
  }

  button {
    background: none !important;
    border: none !important;
    color: ${C.actionGreen} !important;
    font-size: 24px !important;
    font-weight: bold !important;
    line-height: 1 !important;
    cursor: pointer !important;
    padding: 0 2px !important;
  }

  #spd {
    min-width: 48px;
    text-align: center;
    line-height: 1;
    white-space: nowrap;
  }

  #spd b {
    font-weight: bold !important;
    font-size: 18px !important;
    color: ${C.lightGray} !important;
    line-height: 1 !important;
  }

  #panel {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    background: ${C.darkPill};
    border: 3px solid ${C.midGray};
    border-radius: 16px;
    padding: 10px 16px !important;
    display: none;
    flex-direction: column;
    font-size: 14px;
    min-width: 280px;
    cursor: default;
    box-shadow:
      0 6px 14px rgba(0,0,0,0.55),
      inset 0 0 0 6px ${C.deepNavy},
      inset 0 2px 4px rgba(255,255,255,0.08);
  }

  #panel .section-title {
    margin-top: 8px !important;
    margin-bottom: 4px !important;
    color: ${C.lightGray} !important;
    opacity: .85 !important;
    font-weight: 600 !important;
    border-bottom: 1px solid ${C.midGray} !important;
    padding-bottom: 4px !important;
  }

  .toggle-row {
    display: grid;
    grid-template-columns: 1fr 46px;
    align-items: center;
    margin: 6px 0 !important;
    gap: 10px;
  }

  .toggle-label-bold {
    font-weight: bold !important;
  }

  .toggle-label-desc {
    color: ${C.lightGray}99 !important;
    font-size: 11px !important;
    font-style: italic !important;
    margin-top: 2px !important;
  }

  .collapsible-toggle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: 8px 0 !important;
    padding: 4px 0 !important;
    border-top: 1px solid ${C.midGray};
    color: ${C.actionGreen} !important;
    font-weight: bold !important;
    cursor: pointer;
    font-size: 14px !important;
  }
.warning-text {
    font-size: 9.5px !important;
    color: #ff4444 !important;
    opacity: 0.85;
    margin: 2px 0 6px 0 !important;
    line-height: 1.25 !important;
    letter-spacing: 0.1px;
    text-shadow: 0 0 4px rgba(255, 60, 60, 0.25);
font-weight: 700 !important;
  }

  .collapsible-arrow {
    transition: transform 0.2s;
  }

  .toggle-switch {
    width:46px;height:24px;
    border-radius:20px;
    background:${C.deepNavy};
    border:1px solid ${C.lightGray};
    position:relative;
    cursor:pointer;
    transition:background .2s,border .2s;
  }

  .knob {
    width:20px;height:20px;
    border-radius:50%;
    background:${C.darkPill};
    position:absolute;top:1px;left:1px;
    transition:left .2s, background .2s, box-shadow .2s;
    box-shadow:0 0 6px ${C.shadow};
  }
`;


    // ---------------- UI (Rebuilt inside Shadow DOM) ----------------

    // 1. Create the container (host) for the Shadow DOM
    const shadowHost = document.createElement('div');
    shadowHost.id = 'shadow-host';
    document.documentElement.appendChild(shadowHost);

    // 2. Attach the Shadow DOM
    const shadowRoot = shadowHost.attachShadow({ mode: 'open' });

    // 3. Inject global style into the Shadow DOM
    const styleElement = document.createElement('style');
    styleElement.textContent = globalStyle;
    shadowRoot.appendChild(styleElement);

    // 4. Create the gauge wrapper inside the shadow root
    const gaugeWrapper = document.createElement('div');
    gaugeWrapper.id = 'gauge-wrapper';
    shadowRoot.appendChild(gaugeWrapper);

    const gauge = document.createElement('div');
    gauge.id = 'gauge';
    gaugeWrapper.appendChild(gauge);

    // Create inner elements
    const gaugeHeader = document.createElement('div');
    gaugeHeader.id = 'gauge-header';
    gaugeHeader.innerHTML = `
        <button id="dec">–</button>
        <span id="spd">${formatSpeed(speed)}</span>
        <button id="inc">+</button>
    `;
    gauge.appendChild(gaugeHeader);

    const gaugeFooter = document.createElement('div');
    gaugeFooter.id = 'gauge-footer';
    gaugeFooter.innerHTML = `
        <span>ONO.speed</span>
        <span id="footer-arrow">▼</span>
    `;
    gauge.appendChild(gaugeFooter);

    const panel = document.createElement('div');
    panel.id = 'panel';
    gaugeWrapper.appendChild(panel);


    // --- Descriptions and UI Functions (Re-scoped for Shadow DOM) ---
    const hookDescriptions = {
        requestAnimationFrame: 'Smooth frame-by-frame animation loops',
        setTimeout: 'One-time function delays',
        setInterval: 'Recurring function delays',
        css: 'Browser-native UI movement and styling',
        time: 'Affects high-precision timing for games/physics',
        date: 'Affects login sessions, expiration, and notifications',
        gsap: 'Greensock\'s industry-standard animation engine',
        pixi: 'PIXI.js 2D game loop',
        three: 'THREE.js 3D scene timing',
        anime: 'Anime.js animation library',
        velocity: 'Velocity.js animation library',
    };

    function makeToggleRow(labelText, key, initial) {
        const row = document.createElement('div');
        row.className = 'toggle-row';

        const labelContainer = document.createElement('div');
        labelContainer.innerHTML = `
            <div class="toggle-label-bold">${labelText}</div>
            <div class="toggle-label-desc">${hookDescriptions[key] || ''}</div>
        `;

        const toggle = document.createElement('div');
        toggle.className = 'toggle-switch';
        const toggleWrapper = document.createElement('div');
        toggleWrapper.style = 'justify-self: end;';

        const knob = document.createElement('div');
        knob.className = 'knob';
        toggle.appendChild(knob);
        toggleWrapper.appendChild(toggle);

const setVisual = (on) => {
  knob.style.left = on ? '25px' : '1px';
  knob.style.background = on ? C.actionGreen : '#1c3b4a'; // lighter navy off
  knob.style.boxShadow = on
    ? `0 0 6px ${C.actionGreen}99`
    : `0 0 4px ${C.shadow}55`;
  toggle.style.border = `1px solid ${on ? C.actionGreen : C.midGray}`;
  toggle.style.background = on ? C.darkPill : '#152a37'; // softer off tone
};



        hooks[key] = initial;
        setVisual(!!initial);
        toggle.addEventListener('click', (e) => {
            e.stopPropagation();
            hooks[key] = !hooks[key];
            setVisual(hooks[key]);
            updateHooks();
        });

        row.append(labelContainer, toggleWrapper);
        return row;
    }

    function section(title) {
        const t = document.createElement('div');
        t.textContent = title;
        t.className = 'section-title';
        panel.appendChild(t);
    }

    function createCollapsibleToggle(panelElement, labelText) {
        const toggleRow = document.createElement('div');
        toggleRow.className = 'collapsible-toggle';
        toggleRow.innerHTML = `
            <span>${labelText}</span>
            <span class="collapsible-arrow">▼</span>
        `;

        const arrowEl = toggleRow.querySelector('.collapsible-arrow');
        panelElement.style.display = 'none';
        arrowEl.style.transform = 'rotate(-90deg)';

        toggleRow.onclick = (e) => {
            e.stopPropagation();
            const isVisible = panelElement.style.display !== 'none';
            panelElement.style.display = isVisible ? 'none' : 'flex';
            arrowEl.style.transform = isVisible ? 'rotate(-90deg)' : 'rotate(0deg)';
        };

        return toggleRow;
    }

    // --- UI Layout Injection (into Shadow DOM) ---

    section('Core JS Timing');
    panel.append(
        makeToggleRow('requestAnimationFrame', 'requestAnimationFrame', hooks.requestAnimationFrame),
        makeToggleRow('setTimeout', 'setTimeout', hooks.setTimeout),
        makeToggleRow('setInterval', 'setInterval', hooks.setInterval),
    );

    // --- Global Clocks Section (Collapsible) ---
    const clockPanel = document.createElement('div');
    clockPanel.style.display = 'flex';
    clockPanel.style.flexDirection = 'column';

    panel.appendChild(createCollapsibleToggle(clockPanel, 'More Clocks (Caution)'));

    const warningText = document.createElement('div');
    warningText.className = 'warning-text';
    warningText.innerHTML = `
        *Caution:* Global clock overrides can lead to session errors or delayed notifications.
    `;
    clockPanel.appendChild(warningText);

    clockPanel.append(
        makeToggleRow('performance.now()', 'time', hooks.time),
        makeToggleRow('Date.now() / new Date()', 'date', hooks.date),
    );
    panel.appendChild(clockPanel);

    // --- CSS & Libraries Section ---
    section('CSS & Libraries');
    panel.append(
        makeToggleRow('CSS Animations/Transitions', 'css', hooks.css),
    );

    // --- Libraries Section (Collapsible) ---
    const libPanel = document.createElement('div');
    libPanel.style.display = 'flex';
    libPanel.style.flexDirection = 'column';

    panel.appendChild(createCollapsibleToggle(libPanel, 'More Libraries'));

    const libRows = {
        gsap: makeToggleRow('GSAP (globalTimeline)', 'gsap', false),
        pixi: makeToggleRow('PIXI (Ticker)', 'pixi', false),
        three: makeToggleRow('THREE.js (Clock)', 'three', false),
        anime: makeToggleRow('Anime.js', 'anime', false),
        velocity: makeToggleRow('Velocity.js', 'velocity', false),
    };
    // Need unique IDs for library rows to detect library presence later
    libRows.gsap.id = 'lib-gsap';
    libRows.pixi.id = 'lib-pixi';
    libRows.three.id = 'lib-three';
    libRows.anime.id = 'lib-anime';
    libRows.velocity.id = 'lib-velocity';

    libPanel.append(libRows.gsap, libRows.pixi, libRows.three, libRows.anime, libRows.velocity);
    panel.appendChild(libPanel);

    // ---------------- Dragging (Re-scoped to Shadow DOM) ----------------
    let dx, dy;

    gauge.addEventListener('mousedown', (e) => {
        // Find if the click target is any interactive element inside the gauge or panel
        const interactiveTarget = e.target.closest('button, #footer-arrow, .knob, .collapsible-toggle');
        const isInsidePanel = panel.contains(e.target);

        // Drag exclusion checks
        if (interactiveTarget || isInsidePanel) {
            return;
        }

        e.preventDefault();
        e.stopPropagation();

        // Temporarily set the body cursor to 'move' for continuous feedback
        document.body.style.cursor = 'move';

        // Calculate offset relative to the Shadow DOM host/page
        const gaugeRect = gaugeWrapper.getBoundingClientRect();
        dx = e.pageX - gaugeRect.left;
        dy = e.pageY - gaugeRect.top;

        const move = (ev)=>{
            gaugeWrapper.style.left = ev.pageX - dx + 'px';
            gaugeWrapper.style.top = ev.pageY - dy + 'px';
        };

        const up = ()=>{
            document.removeEventListener('mousemove', move);
            document.removeEventListener('mouseup', up);

            // Restore body cursor
            document.body.style.cursor = 'default';
        };

        document.addEventListener('mousemove', move);
        document.addEventListener('mouseup', up);
    });

    const spdEl = shadowRoot.querySelector('#spd');
    const footerArrow = shadowRoot.querySelector('#footer-arrow');

    // Panel toggle function
    const togglePanel = (e) => {
        e.stopPropagation();
        const isVisible = panel.style.display === 'flex';
        panel.style.display = isVisible ? 'none' : 'flex';
        footerArrow.textContent = isVisible ? '▼' : '▲'; // Change arrow text
    };

    // Attach click handlers
    shadowRoot.querySelector('#inc').onclick = () => setSpeed(speed + 0.1);
    shadowRoot.querySelector('#dec').onclick = () => setSpeed(Math.max(0.1, speed - 0.1));
    footerArrow.onclick = togglePanel;

    // ---------------- Core / Helper Functions (Unchanged) ----------------
    function setSpeed(target) {
        let newSpeed = Math.max(0.1, target);
        newSpeed = Math.min(MAX_SPEED, newSpeed);

        const currentTime = performance.now();
        const realDelta = currentTime - bootTime;
        const currentScaledTime = realDelta * speed + scaledTimeOffset;

        speed = newSpeed;
        scaledTimeOffset = currentScaledTime - (currentTime - bootTime) * speed;

        spdEl.innerHTML = formatSpeed(speed);
        afterSpeedChange();
    }

    function afterSpeedChange() {
        if (hooks.css) applyCSSScaling();
        applyLibScaling();
        updateHooks();
    }

    function getVirtualTime() {
        return (performance.now() - bootTime) * speed + scaledTimeOffset;
    }

    // ---------------- Core Hooks ----------------
    let rafLast = 0;
    let rafVirtual = 0;

    function enableVirtualRAF() {
        window.requestAnimationFrame = cb => {
            native.requestAnimationFrame(now => {
                if (rafLast === 0) {
                    rafLast = now;
                    rafVirtual = getVirtualTime();
                }
                const delta = now - rafLast;
                rafLast = now;
                rafVirtual += delta * speed;
                cb(rafVirtual);
            });
        };
    }

    function disableVirtualRAF() {
        window.requestAnimationFrame = native.requestAnimationFrame;
        rafLast = 0;
        rafVirtual = 0;
    }

    function enableVirtualTime() {
        window.performance.now = () => getVirtualTime();
    }

    function disableVirtualTime() {
        window.performance.now = native.performance.now.bind(native.performance);
    }

    function enableVirtualDate() {
        const nativeDate = native.Date;
        const nativeNow = nativeDate.now;
        const realDateBoot = nativeNow();
        const performanceBoot = performance.now();

        function ScaledDate(...args) {
            if (!new.target) {
                return new nativeDate(realDateBoot + getVirtualTime() - performanceBoot).toString();
            }
            if (args.length === 0) {
                const offset = getVirtualTime() - performanceBoot;
                return new nativeDate(realDateBoot + offset);
            }
            return new nativeDate(...args);
        }
        ScaledDate.now = () => realDateBoot + getVirtualTime() - performanceBoot;
        Object.assign(ScaledDate, nativeDate);
        window.Date = ScaledDate;
    }

    function disableVirtualDate() {
        window.Date = native.Date;
    }

    function updateHooks() {
        if (hooks.setTimeout) {
            window.setTimeout = (fn, t, ...a) => {
                const base = Number.isFinite(t) ? (t ?? 0) : 0;
                const scaled = Math.max(MIN_TIMEOUT_MS, Math.round(base / speed));
                return native.setTimeout(fn, scaled, ...a);
            };
        } else {
            window.setTimeout = native.setTimeout;
        }

        if (hooks.setInterval) {
            window.setInterval = (fn, t, ...a) => {
                const base = Number.isFinite(t) ? (t ?? 0) : 0;
                const scaled = Math.max(MIN_INTERVAL_MS, Math.round(base / speed));
                return native.setInterval(fn, scaled, ...a);
            };
        } else {
            window.setInterval = native.setInterval;
        }

        if (hooks.requestAnimationFrame) enableVirtualRAF(); else disableVirtualRAF();
        if (hooks.time) enableVirtualTime(); else disableVirtualTime();
        if (hooks.date) enableVirtualDate(); else disableVirtualDate();
        if (hooks.css) applyCSSScaling(); else restoreCSSDurations();
    }

    // ---------------- CSS scaling ----------------
    const cssCache = new Map();
    let cssObserver = null;

    function cacheDurations(el) {
        if (el.nodeType !== 1) return;
        try {
            // Note: getComputedStyle still works on host elements, even from Shadow DOM.
            const st = getComputedStyle(el);
            const anim = st.animationDuration;
            const trans = st.transitionDuration;
            if (!anim && !trans) return;
            const rec = cssCache.get(el) || {};
            if (!rec.anim && anim && anim !== '0s') rec.anim = anim.split(',').map(s => parseFloat(s) || 0);
            if (!rec.trans && trans && trans !== '0s') rec.trans = trans.split(',').map(s => parseFloat(s) || 0);
            if (rec.anim || rec.trans) cssCache.set(el, rec);
        } catch { /* cross-origin/shadow DOM */ }
    }

    function scaleSecondsArray(arr, scale) {
        return arr.map(v => {
            const out = v * scale;
            return (out <= CSS_SNAP_S) ? '0.001s' : out.toFixed(4) + 's';
        }).join(', ');
    }

    function applyScaleToEl(el, scale) {
        const rec = cssCache.get(el);
        if (!rec || !el.style) return;
        if (rec.anim)  el.style.animationDuration  = scaleSecondsArray(rec.anim,  scale);
        if (rec.trans) el.style.transitionDuration = scaleSecondsArray(rec.trans, scale);
    }

    function scanAndCacheTree(root = document.body) {
        if (root.nodeType !== 1) return;
        cacheDurations(root);
        // Note: Querying the host DOM from Shadow DOM still works.
        root.querySelectorAll('*').forEach(cacheDurations);
    }

    function applyScaleTree(root, scale) {
        if (root.nodeType !== 1) return;
        applyScaleToEl(root, scale);
        root.querySelectorAll('*').forEach(el => applyScaleToEl(el, scale));
    }

    function applyCSSScaling() {
        const scale = 1 / speed;
        if (!cssObserver) {
            scanAndCacheTree(document.documentElement);
            cssObserver = new MutationObserver(muts => {
                for (const m of muts) {
                    if (m.type === 'childList') {
                        m.addedNodes.forEach(n => {
                            if (n.nodeType === 1) {
                                scanAndCacheTree(n);
                                applyScaleTree(n, scale);
                            }
                        });
                    }
                }
            });
            cssObserver.observe(document.documentElement, { childList: true, subtree: true });
        }
        cssCache.forEach((_, el) => applyScaleToEl(el, scale));
    }

    function restoreCSSDurations() {
        cssCache.forEach((rec, el) => {
            if (!el || !el.style) return;
            if (rec.anim)  el.style.animationDuration  = rec.anim.map(v => v + 's').join(', ');
            if (rec.trans) el.style.transitionDuration = rec.trans.map(v => v + 's').join(', ');
        });
        if (cssObserver) {
            cssObserver.disconnect();
            cssObserver = null;
        }
    }
    // ---------------- Library hooks ----------------
    let threePatched = false;
    let pixiPatched = false;

    function applyLibScaling() {
        if (window.gsap) {
            try {
                if (hooks.gsap) window.gsap.globalTimeline.timeScale(speed);
                else window.gsap.globalTimeline.timeScale(1);
            } catch {}
        }
        if (window.PIXI && window.PIXI.Ticker) {
            try {
                if (hooks.pixi) {
                    if (window.PIXI.Ticker.shared) window.PIXI.Ticker.shared.speed = speed;
                    if (window.PIXI.Ticker.system) window.PIXI.Ticker.system.speed = speed;
                    if (!pixiPatched) { pixiPatched = true; }
                } else {
                    if (window.PIXI.Ticker.shared) window.PIXI.Ticker.shared.speed = 1;
                    if (window.PIXI.Ticker.system) window.PIXI.Ticker.system.speed = 1;
                }
            } catch {}
        }
        if (window.THREE && window.THREE.Clock) {
            try {
                const C = window.THREE.Clock;
                if (!threePatched) {
                    if (!C.prototype.___nativeGetDelta) {
                        C.prototype.___nativeGetDelta = C.prototype.getDelta;
                        C.prototype.getDelta = function () {
                            const d = this.___nativeGetDelta();
                            return hooks.three ? d * speed : d;
                        };
                    }
                    if (!C.prototype.___nativeGetElapsedTime) {
                        C.prototype.___nativeGetElapsedTime = C.prototype.getElapsedTime;
                        C.prototype.getElapsedTime = function () {
                            const e = this.___nativeGetElapsedTime();
                            return hooks.three ? e * speed : e;
                        };
                    }
                    threePatched = true;
                }
            } catch {}
        }
        if (window.anime) {
            try { window.anime.speed = hooks.anime ? speed : 1; } catch {}
        }
        if (window.Velocity) {
            try { window.Velocity.mock = hooks.velocity ? (1 / speed) : false; } catch {}
        }
    }

    const libDetectAndInit = () => {
        // Querying the main window for library objects still works
        const present = { gsap:  !!(window.gsap), pixi:  !!(window.PIXI && window.PIXI.Ticker), three: !!(window.THREE && window.THREE.Clock), anime: !!(window.anime), velocity: !!(window.Velocity) };
        for (const k of Object.keys(present)) {
            if (hooks[k] === null) hooks[k] = present[k];
            // Re-select elements using the shadowRoot
            const rowMap = {
                gsap: shadowRoot.querySelector('#lib-gsap'),
                pixi: shadowRoot.querySelector('#lib-pixi'),
                three: shadowRoot.querySelector('#lib-three'),
                anime: shadowRoot.querySelector('#lib-anime'),
                velocity: shadowRoot.querySelector('#lib-velocity')
            };
            // Note: The logic below assumes the element and its class structure exist
            if (rowMap[k]) {
                const boldLabel = rowMap[k].querySelector('.toggle-label-bold');
                if (boldLabel) boldLabel.style.opacity = present[k] ? '1' : '.55';
            }
        }
        applyLibScaling();
    };
    native.setInterval(libDetectAndInit, 1500);
    libDetectAndInit();

    // ---------------- Init
    function boot() {
        const initialPerformanceNow = native.performance.now();
        scaledTimeOffset = initialPerformanceNow - initialPerformanceNow * speed;
        updateHooks();
    }
    boot();
})();