🎀 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);
            }
        }
    `);

})();