Streamlined floating chaos - crisp drag physics, surgical positioning, puff exit, cached
// ==UserScript==
// @name KCE - Float Shigure
// @namespace kce_float_shigure_userscript
// @author KCE
// @version 2.3
// @licence MIT Pro Max Plus Ultra
// @icon data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">🎀</text></svg>
// @description Streamlined floating chaos - crisp drag physics, surgical positioning, puff exit, cached
// @match *://*/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
(function() {
'use strict';
if (window.self !== window.top) return;
const IMG_URL = 'https://kce.wtf/wp-content/uploads/2025/12/kce-footer-2.avif';
const CACHE_KEY = 'shigure-img-cache';
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"
],
reset: [
"back home~",
"snapped back into place",
"returning to base",
"home sweet home",
"resetting position"
]
};
const randomMsg = (pool) => pool[Math.floor(Math.random() * pool.length)];
// DOM setup
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;
// Default position (matches CSS default)
function getDefaultPos() {
return {
x: window.innerWidth - 120,
y: window.innerHeight - 150
};
}
// Image caching system
function initImageCache() {
const cached = GM_getValue(CACHE_KEY, null);
if (cached) {
overlay.style.backgroundImage = `url(${cached})`;
} else {
fetchAndCache();
}
}
function fetchAndCache() {
fetch(IMG_URL)
.then(r => r.blob())
.then(blob => {
const reader = new FileReader();
reader.onload = () => {
const dataUrl = reader.result;
GM_setValue(CACHE_KEY, dataUrl);
overlay.style.backgroundImage = `url(${dataUrl})`;
};
reader.readAsDataURL(blob);
})
.catch(() => {
overlay.style.backgroundImage = `url(${IMG_URL})`;
});
}
// Message display + smart positioning
function updateMsgPosition() {
const rect = overlay.getBoundingClientRect();
const w = window.innerWidth;
const yPos = rect.top > 100 ? -45 : rect.height + 5;
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;
notif.classList.add('visible');
setTimeout(() => notif.remove(), 3500);
}
let isPuffing = false;
function hideWithPuff() {
if (isPuffing) return; // Duplicate puff block
isPuffing = true;
overlay.classList.add('puff-out');
setTimeout(() => {
isHidden = true;
overlay.style.display = 'none';
const hideMsg = randomMsg(MESSAGES.hide);
showNotification(hideMsg);
}, 600);
}
function resetToDefaultPosition() {
const def = getDefaultPos();
x = def.x;
y = def.y;
overlay.style.left = x + 'px';
overlay.style.top = y + 'px';
showNotification(randomMsg(MESSAGES.reset));
}
// State
let isDragging = false;
let x = 0, y = 0;
let startX = 0, startY = 0;
let isHidden = false;
let longPressTimer = null;
let longPressTriggered = false;
let touchStartX = 0, touchStartY = 0;
const LONG_PRESS_MS = 550;
const LONG_PRESS_MOVE_TOLERANCE = 12;
// Hover
overlay.addEventListener('mouseenter', () => {
if (!isDragging) showMsg(randomMsg(MESSAGES.hover), false);
});
overlay.addEventListener('mouseleave', () => {
if (!isDragging) hideMsg();
});
// Right-click (desktop) -> hide with puff
overlay.addEventListener('contextmenu', (e) => {
e.preventDefault();
if (isHidden) return;
hideWithPuff();
});
// Middle-click (desktop) -> reset to default position
overlay.addEventListener('mousedown', (e) => {
if (e.button === 1) {
e.preventDefault();
if (isHidden) return;
resetToDefaultPosition();
}
});
// Some browsers fire 'auxclick' for middle button instead of/along with mousedown
overlay.addEventListener('auxclick', (e) => {
if (e.button === 1) {
e.preventDefault();
if (isHidden) return;
resetToDefaultPosition();
}
});
// Drag mechanics
function dragStart(e) {
if (isHidden) return;
// Ignore right-click / middle-click starting a drag
if (e.type === 'mousedown' && e.button !== 0) return;
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);
// Long-press setup (touch only)
if (e.type === 'touchstart') {
longPressTriggered = false;
touchStartX = e.touches?.[0]?.clientX ?? 0;
touchStartY = e.touches?.[0]?.clientY ?? 0;
clearTimeout(longPressTimer);
longPressTimer = setTimeout(() => {
longPressTriggered = true;
isDragging = false;
overlay.classList.remove('dragging');
hideMsg();
hideWithPuff();
}, LONG_PRESS_MS);
}
e.preventDefault();
}
function dragMove(e) {
if (!isDragging) return;
// Cancel long-press if finger moves too much
if (e.type === 'touchmove' && longPressTimer) {
const curX = e.touches?.[0]?.clientX ?? 0;
const curY = e.touches?.[0]?.clientY ?? 0;
const dist = Math.hypot(curX - touchStartX, curY - touchStartY);
if (dist > LONG_PRESS_MOVE_TOLERANCE) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
}
x = (e.touches?.[0]?.clientX ?? e.clientX) - startX;
y = (e.touches?.[0]?.clientY ?? e.clientY) - startY;
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';
if (msgEl.classList.contains('visible')) {
updateMsgPosition();
}
e.preventDefault();
}
function dragEnd() {
clearTimeout(longPressTimer);
longPressTimer = null;
if (longPressTriggered) {
longPressTriggered = false;
return;
}
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);
document.addEventListener('touchcancel', dragEnd);
// CSS - optimized
GM_addStyle(`
#shigure-floating {
position: fixed;
left: calc(100% - 120px);
top: calc(100% - 150px);
width: 100px;
height: 130px;
background: 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;
will-change: transform;
pointer-events: none;
}
#shigure-floating:active {
cursor: grabbing;
}
#shigure-floating.puff-out {
animation: puffOut 0.6s cubic-bezier(0.36, 0, 0.66, -0.56) forwards;
}
@keyframes puffOut {
0% {
opacity: 1;
transform: scale(1);
filter: blur(0);
}
100% {
opacity: 0;
transform: scale(2.5);
filter: blur(12px);
}
}
#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), top 0.18s ease, left 0.18s ease;
box-shadow: 0 4px 16px rgba(0,0,0,0.3);
z-index: 1000000;
max-width: 220px;
overflow: hidden;
text-overflow: ellipsis;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
#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 22px;
/* kırmızı cam */
background: rgba(255, 60, 60, 0.18);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
color: #fff;
font-family: system-ui, -apple-system, sans-serif;
font-weight: 700;
font-size: 13px;
letter-spacing: 0.3px;
/* oval + net ama zarif kenar */
border-radius: 999px;
border: 1px solid rgba(255, 80, 80, 0.65);
box-shadow:
0 4px 12px rgba(0, 0, 0, 0.35),
inset 0 0 0 1px rgba(255, 255, 255, 0.08);
z-index: 9999999;
white-space: nowrap;
opacity: 0;
transition: opacity 0.25s ease, transform 0.25s ease;
}
#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);
}
}
`);
// Init image cache on load
initImageCache();
})();