Disable animations

Speed up browsing by reducing animation and transition delays

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name        Disable animations
// @description Speed up browsing by reducing animation and transition delays
// @version     2026.04.12
// @author      Claude Opus 4.6
// @grant       none
// @inject-into auto
// @run-at      document-start
// @match       *://*/*
// @namespace https://greasyfork.org/users/1519047
// ==/UserScript==

(function() {
    'use strict';

    var TRANSITION_CAP_S = 0.01;
    var ANIMATION_CAP_S = 0.001;

    // --- Patch Web Animations API (Element.animate) ---
    var origAnimate = Element.prototype.animate;
    if (origAnimate) {
        Element.prototype.animate = function(keyframes, options) {
            if (typeof options === 'number') {
                options = 1;
            } else if (options && typeof options === 'object') {
                if (options.duration > 1) options.duration = 1;
                if (options.delay) options.delay = 0;
                if (options.iterations === Infinity) options.iterations = 1;
            }
            return origAnimate.call(this, keyframes, options);
        };
    }

    // --- Duration clamping utility ---
    var clampDurations = function(raw, cap) {
        var parts = raw.split(',');
        var changed = false;
        var clamped = parts.map(function(part) {
            var val = parseFloat(part);
            if (val <= 0 || isNaN(val)) return part.trim();
            changed = true;
            return Math.min(val, cap) + 's';
        });
        return changed ? clamped.join(', ') : null;
    };

    // --- Check if any value in a comma-separated list is "infinite" or a large number ---
    // Threshold of 2 catches "infinite" and high iteration counts while allowing
    // deliberate 1- or 2-iteration animations (e.g. attention pulses) to complete normally.
    var hasInfiniteIteration = function(raw) {
        var parts = raw.split(',');
        for (var i = 0; i < parts.length; i++) {
            var val = parts[i].trim();
            if (val === 'infinite') return true;
            var num = parseFloat(val);
            if (!isNaN(num) && num > 2) return true;
        }
        return false;
    };

    // --- RAF batching for processElement to avoid layout thrashing ---
    var pendingSet = new Set();
    var pendingList = [];
    var rafScheduled = false;
    var processing = false;

    var scheduleProcess = function(el) {
        if (pendingSet.has(el)) return;
        pendingSet.add(el);
        pendingList.push(el);
        if (!rafScheduled) {
            rafScheduled = true;
            requestAnimationFrame(function() {
                processing = true;
                for (var i = 0; i < pendingList.length; i++) {
                    processElement(pendingList[i]);
                }
                processing = false;
                pendingSet.clear();
                pendingList.length = 0;
                rafScheduled = false;
            });
        }
    };

    var scheduleTree = function(root) {
        if (root.nodeType !== 1) return;
        scheduleProcess(root);
        if (root.querySelectorAll) {
            var nodes = root.querySelectorAll('*');
            for (var i = 0; i < nodes.length; i++) {
                scheduleProcess(nodes[i]);
            }
        }
    };

    // --- Process a single element ---
    var processElement = function(el) {
        if (el.nodeType !== 1) return;

        var computed = getComputedStyle(el);

        // Clamp transition durations
        var tDur = computed.transitionDuration;
        if (tDur && tDur !== '0s') {
            var tClamped = clampDurations(tDur, TRANSITION_CAP_S);
            if (tClamped) {
                el.style.setProperty('transition-duration', tClamped, 'important');
                el.style.setProperty('transition-delay', '0s', 'important');
            }
        }

        // Clamp animation durations and stop infinite loops
        var aDur = computed.animationDuration;
        if (aDur && aDur !== '0s') {
            var aClamped = clampDurations(aDur, ANIMATION_CAP_S);
            if (aClamped) {
                el.style.setProperty('animation-duration', aClamped, 'important');
                el.style.setProperty('animation-delay', '0s', 'important');

                // Only force iteration-count and fill-mode on infinite/looping animations
                var iterCount = computed.animationIterationCount;
                if (iterCount && hasInfiniteIteration(iterCount)) {
                    el.style.setProperty('animation-iteration-count', '1', 'important');
                    el.style.setProperty('animation-fill-mode', 'both', 'important');
                }
            }
        }
    };

    // --- Initial synchronous pass + observer ---
    var processTree = function(root) {
        processElement(root);
        if (root.querySelectorAll) {
            var nodes = root.querySelectorAll('*');
            for (var i = 0; i < nodes.length; i++) {
                processElement(nodes[i]);
            }
        }
    };

    var startObserver = function() {
        // Synchronous first pass so existing elements are clamped immediately
        processTree(document.documentElement);

        new MutationObserver(function(mutations) {
            for (var i = 0; i < mutations.length; i++) {
                var mutation = mutations[i];
                if (mutation.type === 'childList') {
                    var added = mutation.addedNodes;
                    for (var j = 0; j < added.length; j++) {
                        if (added[j].nodeType === 1) scheduleTree(added[j]);
                    }
                } else if (mutation.type === 'attributes' && !processing) {
                    // Re-process elements whose class or style changed,
                    // since new animations/transitions may have been applied.
                    // Guard with `processing` to avoid infinite loops from
                    // our own style.setProperty calls triggering style mutations.
                    scheduleProcess(mutation.target);
                }
            }
        }).observe(document.documentElement, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['class', 'style']
        });
    };

    // --- jQuery patching ---
    var patchjQuery = function(jq) {
        if (!jq || !jq.fx || jq.fx._animDisablerPatched) return;
        jq.fx._animDisablerPatched = true;

        jq.fx.speeds = { slow: 1, fast: 1, _default: 1 };

        if (jq.fn && jq.fn.animate && !jq.fn.animate._patched) {
            var origAnim = jq.fn.animate;
            jq.fn.animate = function(prop, speed) {
                var args = Array.prototype.slice.call(arguments);
                if (typeof speed === 'object' && speed !== null) {
                    args[1].duration = 1;
                } else {
                    args[1] = 1;
                }
                return origAnim.apply(this, args);
            };
            jq.fn.animate._patched = true;
        }

        ['fadeTo', 'fadeIn', 'fadeOut', 'fadeToggle',
         'slideUp', 'slideDown', 'slideToggle'].forEach(function(method) {
            if (jq.fn[method] && !jq.fn[method]._patched) {
                var orig = jq.fn[method];
                jq.fn[method] = function() {
                    var args = Array.prototype.slice.call(arguments);
                    args[0] = 1;
                    return orig.apply(this, args);
                };
                jq.fn[method]._patched = true;
            }
        });
    };

    // --- Patch GSAP if present ---
    var patchGSAP = function() {
        try {
            if (window.gsap) {
                window.gsap.globalTimeline.timeScale(1000);
            } else if (window.TweenMax) {
                window.TweenMax.globalTimeScale(1000);
            }
            if (window.wrappedJSObject) {
                if (window.wrappedJSObject.gsap) {
                    window.wrappedJSObject.gsap.globalTimeline.timeScale(1000);
                } else if (window.wrappedJSObject.TweenMax) {
                    window.wrappedJSObject.TweenMax.globalTimeScale(1000);
                }
            }
        } catch (e) {
            console.debug('Animation disabler (GSAP):', e);
        }
    };

    var disableJSAnimations = function() {
        try {
            [window.jQuery, window.$,
             window.wrappedJSObject?.jQuery,
             window.wrappedJSObject?.$].forEach(patchjQuery);

            if (window.Velocity) window.Velocity.mock = true;
            if (window.wrappedJSObject?.Velocity) window.wrappedJSObject.Velocity.mock = true;

            patchGSAP();

            if (!window.jQuery && !window.$) {
                var check = setInterval(function() {
                    if (window.jQuery || window.$) {
                        patchjQuery(window.jQuery);
                        patchjQuery(window.$);
                        clearInterval(check);
                    }
                }, 100);
                setTimeout(function() { clearInterval(check); }, 10000);
            }
        } catch (e) {
            console.debug('Animation disabler:', e);
        }
    };

    // --- Initialization ---
    var init = function() {
        startObserver();
        disableJSAnimations();
    };

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

    // Re-check JS animation libraries after full page load,
    // as some are loaded asynchronously via script tags.
    window.addEventListener('load', disableJSAnimations);
})();