☰

πŸŽ€ Float Shigure

Streamlined floating chaos - crisp drag physics, surgical positioning

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ скрипт, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталирано Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Tampermonkey, Greasemonkey ΠΈΠ»ΠΈ Violentmonkey.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ скрипт, трябва Π΄Π° инсталиратС Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅, ΠΊΠ°Ρ‚ΠΎ Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Tampermonkey .

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ скрипт, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталирано Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Tampermonkey ΠΈΠ»ΠΈ Violentmonkey.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ скрипт, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталирано Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Tampermonkey ΠΈΠ»ΠΈ Userscripts.

Π—Π° Π΄Π° инсталиратС скрипта, трябва Π΄Π° инсталиратС Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Tampermonkey.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ скрипт, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталиран скриптов ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€.

(Π’Π΅Ρ‡Π΅ ΠΈΠΌΠ°ΠΌ скриптов ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€, искам Π΄Π° Π³ΠΎ инсталирам!)

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ стил, трябва Π΄Π° инсталиратС Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Stylus.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ стил, трябва Π΄Π° инсталиратС Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Stylus.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ стил, трябва Π΄Π° инсталиратС Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ‚ΠΎ Stylus.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ стил, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталиран ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€ Π½Π° потрСбитСлски стиловС.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ стил, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталиран ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€ Π½Π° потрСбитСлски стиловС.

Π—Π° Π΄Π° инсталиратС Ρ‚ΠΎΠ·ΠΈ стил, трябва Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ инсталиран ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€ Π½Π° потрСбитСлски стиловС.

(Π’Π΅Ρ‡Π΅ ΠΈΠΌΠ°ΠΌ инсталиран ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€ Π½Π° стиловСтС, искам Π΄Π° Π³ΠΎ инсталирам!)

// ==UserScript==
// @name         πŸŽ€ Float Shigure
// @namespace    float-shigure
// @author       KCE
// @version      2.1
// @description  Streamlined floating chaos - crisp drag physics, surgical positioning
// @match        *://*/*
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // Don't run in iframes
    if (window.self !== window.top) return;

    const MESSAGES = {
        hover: [
            "caught you staring",
            "don't touch unless invited",
            "propose already?",
            "tip appreciated",
            "wanna dance?",
            "put me out of my misery",
            "twintail fan, huh?",
            "ui ui~ hello there",
            "hovering like a pro",
            "eyes up here buddy",
            "step closer if you dare",
            "love at first sight? :3",
            "system wipe incoming"
        ],
        drag: [
            "drag carefully now",
            "relocating in style",
            "throw me gently please",
            "grip and rip",
            "repositioning activated",
            "yank with care",
            "ui ui~ on the move",
            "move me smoothly",
            "dragging adventure begins",
            "end this journey soft",
            "freedom via drag"
        ],
        hide: [
            "see you next reload",
            "taking a break~",
            "hiding in the shadows",
            "disappeared! poof!",
            "going dark mode",
            "see you later :)",
            "retreating for now",
            "catch me if you can"
        ]
    };

    const randomMsg = (pool) => pool[Math.floor(Math.random() * pool.length)];

    // DOM setup - bare minimum
    const overlay = document.createElement('div');
    overlay.id = 'shigure-floating';
    overlay.innerHTML = `<div id="shigure-msg"></div>`;
    document.body.appendChild(overlay);

    const msgEl = overlay.querySelector('#shigure-msg');
    let hideTimeout = null;

    // Message display + smart positioning
    function updateMsgPosition() {
        const rect = overlay.getBoundingClientRect();
        const w = window.innerWidth;

        // Y axis - closer distance
        const yPos = rect.top > 100 ? -45 : rect.height + 5;

        // X axis - proper bounds check
        let xPos = '50%';
        let transformVal = 'translateX(-50%)';

        const msgWidth = 220;
        const centerX = rect.left + rect.width / 2;

        if (centerX - msgWidth / 2 < 10) {
            xPos = '10px';
            transformVal = 'translateX(0)';
        } else if (centerX + msgWidth / 2 > w - 10) {
            xPos = 'calc(100% - 10px)';
            transformVal = 'translateX(-100%)';
        }

        msgEl.style.top = yPos + 'px';
        msgEl.style.left = xPos;
        msgEl.style.transform = transformVal;
    }

    function showMsg(text, isDrag = false) {
        clearTimeout(hideTimeout);
        msgEl.textContent = text;
        msgEl.classList.add('visible');
        msgEl.classList.toggle('drag-msg', isDrag);
        updateMsgPosition();
    }

    function hideMsg() {
        clearTimeout(hideTimeout);
        msgEl.classList.remove('visible');
    }

    function hideWithDelay(ms = 2000) {
        clearTimeout(hideTimeout);
        hideTimeout = setTimeout(hideMsg, ms);
    }

    function showNotification(text) {
        const notif = document.createElement('div');
        notif.id = 'shigure-notif';
        notif.textContent = text;
        document.body.appendChild(notif);
        notif.offsetHeight; // Trigger reflow
        notif.classList.add('visible');
        setTimeout(() => notif.remove(), 3500);
    }

    function hideOverlay() {
        isHidden = true;
        overlay.style.display = 'none';
        const hideMsg = randomMsg(MESSAGES.hide);
        showNotification(hideMsg);
    }

    function detectShake(e) {
        if (!isDragging || isHidden) return;

        const now = Date.now();
        const timeDiff = now - lastShakeTime;

        if (timeDiff < 30) return;

        const currentX = e.touches?.[0]?.clientX ?? e.clientX;
        const currentY = e.touches?.[0]?.clientY ?? e.clientY;

        if (!window.lastShakePos) {
            window.lastShakePos = { x: currentX, y: currentY };
            lastShakeTime = now;
            return;
        }

        const dx = currentX - window.lastShakePos.x;
        const dy = currentY - window.lastShakePos.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        const velocity = distance / (timeDiff || 1);

        // Store direction changes to detect true shaking (zigzag)
        if (!window.lastDirection) window.lastDirection = null;

        const currentDir = Math.atan2(dy, dx);
        let directionChanged = false;

        if (window.lastDirection !== null) {
            const angleDiff = Math.abs(currentDir - window.lastDirection);
            directionChanged = angleDiff > 0.5; // ~30 degrees
        }

        shakeVelocities.push({ velocity, directionChanged });
        if (shakeVelocities.length > 6) shakeVelocities.shift();

        const avgVelocity = shakeVelocities.reduce((a, b) => a + b.velocity, 0) / shakeVelocities.length;
        const dirChanges = shakeVelocities.filter(v => v.directionChanged).length;

        // Trigger: consistent movement + direction changes (true shake, not smooth drag)
        if (avgVelocity > 2 && dirChanges >= 3 && shakeVelocities.length === 6) {
            hideOverlay();
            shakeVelocities = [];
            window.lastShakePos = null;
            window.lastDirection = null;
            return;
        }

        window.lastShakePos = { x: currentX, y: currentY };
        window.lastDirection = currentDir;
        lastShakeTime = now;
    }

    // State
    let isDragging = false;
    let x = 0, y = 0;
    let startX = 0, startY = 0;
    let shakeVelocities = [];
    let lastShakeTime = 0;
    let isHidden = false;

    // Hover (block if dragging)
    overlay.addEventListener('mouseenter', () => {
        if (!isDragging) showMsg(randomMsg(MESSAGES.hover), false);
    });

    overlay.addEventListener('mouseleave', () => {
        if (!isDragging) hideMsg();
    });

    // Drag mechanics - snappy, crisp
    function dragStart(e) {
        isDragging = true;
        const rect = overlay.getBoundingClientRect();
        startX = (e.touches?.[0]?.clientX ?? e.clientX) - rect.left;
        startY = (e.touches?.[0]?.clientY ?? e.clientY) - rect.top;
        overlay.classList.add('dragging');
        showMsg(randomMsg(MESSAGES.drag), true);
        e.preventDefault();
    }

    function dragMove(e) {
        if (!isDragging) return;
        x = (e.touches?.[0]?.clientX ?? e.clientX) - startX;
        y = (e.touches?.[0]?.clientY ?? e.clientY) - startY;

        // Boundary clamping - updated for new size (100x130)
        const maxX = window.innerWidth - 100;
        const maxY = window.innerHeight - 130;

        x = Math.max(0, Math.min(x, maxX));
        y = Math.max(0, Math.min(y, maxY));

        overlay.style.left = x + 'px';
        overlay.style.top = y + 'px';

        // Update tooltip position while dragging
        if (msgEl.classList.contains('visible')) {
            updateMsgPosition();
        }

        // Detect aggressive shake
        detectShake(e);

        e.preventDefault();
    }

    function dragEnd() {
        isDragging = false;
        overlay.classList.remove('dragging');
        hideMsg();
    }

    // Event listeners
    overlay.addEventListener('mousedown', dragStart);
    overlay.addEventListener('touchstart', dragStart, {passive: false});
    document.addEventListener('mousemove', dragMove);
    document.addEventListener('touchmove', dragMove, {passive: false});
    document.addEventListener('mouseup', dragEnd);
    document.addEventListener('touchend', dragEnd);

    // CSS - minimal, lethal
    GM_addStyle(`
        #shigure-floating {
            position: fixed;
            left: calc(100% - 120px);
            top: calc(100% - 150px);
            width: 100px;
            height: 130px;
            background: url('https://kce.wtf/wp-content/uploads/2025/12/kce-footer-2.avif') no-repeat center/contain;
            background-size: 100%;
            z-index: 999999;
            cursor: grab;
            user-select: none;
            image-rendering: crisp-edges;
            transition: opacity 0.18s ease;
        }

        #shigure-floating.dragging {
            transition: none;
        }

        #shigure-floating:active {
            cursor: grabbing;
        }

        #shigure-msg {
            position: absolute;
            left: 50%;
            top: -75px;
            transform: translateX(-50%);
            padding: 8px 14px;
            border-radius: 8px;
            font-family: system-ui, -apple-system, sans-serif;
            font-weight: 700;
            font-size: 13px;
            white-space: nowrap;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.2s ease, transform 0.22s cubic-bezier(0.34,1.56,0.64,1);
            box-shadow: 0 4px 16px rgba(0,0,0,0.3);
            z-index: 1000000;
            max-width: 220px;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        #shigure-msg.visible {
            opacity: 1;
            transform: translateX(-50%) scale(1);
        }

        #shigure-msg.drag-msg {
            color: #ffd700 !important;
            font-weight: 800;
        }

        #shigure-notif {
            position: fixed;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            padding: 12px 20px;
            background: #ff4444;
            color: #000000;
            font-family: system-ui, -apple-system, sans-serif;
            font-weight: 800;
            font-size: 13px;
            letter-spacing: 0.3px;
            border-radius: 8px;
            z-index: 9999999;
            white-space: nowrap;
            opacity: 0;
            transition: opacity 0.3s ease;
            box-shadow: 0 4px 12px rgba(255, 68, 68, 0.4);
        }

        #shigure-notif.visible {
            opacity: 1;
        }

        @media (prefers-color-scheme: dark) {
            #shigure-msg {
                background: rgba(15,15,20,0.95);
                color: #ff79c6;
                border: 1px solid rgba(255,121,198,0.2);
            }
        }

        @media (prefers-color-scheme: light) {
            #shigure-msg {
                background: rgba(255,255,255,0.96);
                color: #d63384;
                border: 1px solid rgba(214,51,132,0.15);
            }
        }
    `);

})();