💙💛 Ukrainian Flag & Flowers (Ctrl+Shift+U)

Zero observers, minimal DOM, aggressive caching, and ultra-low CPU usage.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         💙💛 Ukrainian Flag & Flowers (Ctrl+Shift+U)
// @namespace    tampermonkey.net
// @version      17.2
// @description  Zero observers, minimal DOM, aggressive caching, and ultra-low CPU usage.
// @author       邢智轩 (from China)
// @match        *://*/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
'use strict';

// 防止重复初始化
const SCRIPT_VERSION = '23.0-ultra-lite';
if (window.__UA_FLAG_SCRIPT_VER__ === SCRIPT_VERSION && window.__UA_FLAG_INSTANCED__) return;
window.__UA_FLAG_INSTANCED__ = true;
window.__UA_FLAG_SCRIPT_VER__ = SCRIPT_VERSION;

// 清理旧版本残留
const oldHost = document.getElementById('ua-waving-badge-root');
if (oldHost) oldHost.remove();

// 三叉戟 SVG(内嵌优化)
const TRIDENT_SVG = `data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAwIDMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDAgTDg1IDQ1IEw0MCA0NSBRMjAgNDUgMjAgODAgTDIwIDE4MCBRMjAgMjIwIDUwIDIyMCBMNjUgMjIwIEw2NSAxOTAgTDUwIDE5MCBRNDAgMTkwIDQwIDE3NSBMNDAgOTAgTDc1IDkwIEw4MCAxODAgUTgyIDI1MCAxMDAgMjUwIFExMTggMjUwIDEyMCAxODAgTDEyNSA5MCBMMTYwIDkwIEwxNjAgMTc1IFExNjAgMTkwIDE1MCAxOTAgTDEzNSAxOTAgTDEzNSAyMjAgTDE1MCAyMjAgUTE4MCAyMjAgMTgwIDE4MCBMMTgwIDgwIFExODAgNDUgMTYwIDQ1IEwxMTUgNDUgWiBNMTAwIDI2MCBMOTAgMzAwIEwxMTAgMzAwIFoiIGZpbGw9IiNGRkQ3MDAiLz48L3N2Zz4=`;

// 状态管理(极简)
let isDragging = false;
let offsetX = 0;
let offsetY = 0;
let rafId = null;
let hostElement = null;
let shadowRoot = null;
let lastSavedPos = null;
let lastMoveTime = 0;
let boundHandlers = null;
let isTerminated = false;

// 配置(极致节能)
const CONFIG = {
  width: 320,
  height: 200,
  moveThrottle: 40, // 进一步降低移动频率
  resizeDebounce: 500, // 减少 resize 触发频率
  colors: {
    blue: '#0057B7',
    yellow: '#FFD700',
    poleLight: '#FDC830',
    poleDark: '#8B6508',
  },
  // 使用压缩字符串存储配置
  sunflowers: '18,0,0.6,35,L,-0.2,150|35,0,0.85,58,R,-1.5,152|48,0,0.55,28,,-2.8,150|85,0,0.7,45,L,-3.3,150|110,0,0.75,52,,-0.9,150|155,0,0.6,40,,-4.1,150|215,0,0.65,38,,-1.2,150|25,8,0.45,18,,-1.1,160|70,5,0.4,15,,-3.7,160|135,10,0.5,22,,-0.5,160|195,4,0.4,16,,-2.9,160',
  kalynaBranches: '2,0,0.5,-1.0,10,148|280,2,0.6,-2.5,-15,148|55,5,0.7,-3.5,5,149|260,10,0.55,-0.8,-10,149',
  wheatStalks: '5,0,0.7,55,-5,-2.0,145|25,0,0.5,40,5,-3.5,145|295,0,0.6,50,8,-1.5,145|300,0,0.4,35,-3,-4.0,145',
  candles: '115,2,0.7,171|135,2,0.8,170|155,2,0.75,169',
};

// 运行环境检查
const canRun = () => window.innerWidth >= 800 && window.self === window.top;

// 存储封装(极简)
const storage = {
  get: (key, def) => {
    try { return localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key)) : def; }
    catch { return def; }
  },
  set: (key, value) => {
    try { localStorage.setItem(key, JSON.stringify(value)); } catch {}
  },
  remove: (key) => {
    try { localStorage.removeItem(key); } catch {}
  },
};

// 坐标获取
const getClientCoords = (e) => ({
  x: e.touches?.[0]?.clientX ?? e.clientX,
  y: e.touches?.[0]?.clientY ?? e.clientY,
});

// --- 拖拽系统 ---
const startDrag = (e) => {
  if (!hostElement) return;
  attachGlobalListeners();
  if (e.type === 'touchstart') e.preventDefault();
  isDragging = true;
  lastMoveTime = 0;
  const rect = hostElement.getBoundingClientRect();
  const coords = getClientCoords(e);
  offsetX = coords.x - rect.left;
  offsetY = coords.y - rect.top;
  hostElement.style.transition = 'none';
  hostElement.style.top = `${rect.top}px`;
  hostElement.style.left = `${rect.left}px`;
  hostElement.style.bottom = 'auto';
};

const onMove = (e) => {
  if (!isDragging || !hostElement) return;
  const now = performance.now();
  if (now - lastMoveTime < CONFIG.moveThrottle) return;
  lastMoveTime = now;
  if (e.type === 'touchmove') e.preventDefault();
  if (rafId) return;
  rafId = requestAnimationFrame(() => {
    const coords = getClientCoords(e);
    let x = Math.max(0, coords.x - offsetX);
    let y = Math.max(0, coords.y - offsetY);
    const maxX = window.innerWidth - CONFIG.width;
    const maxY = window.innerHeight - CONFIG.height;
    if (maxX > 0) x = Math.min(x, maxX);
    if (maxY > 0) y = Math.min(y, maxY);
    if (hostElement) {
      hostElement.style.left = `${x}px`;
      hostElement.style.top = `${y}px`;
    }
    rafId = null;
  });
};

const endDrag = () => {
  if (!isDragging) return;
  isDragging = false;
  detachGlobalListeners();
  if (hostElement) {
    hostElement.style.transition = 'all 0.8s cubic-bezier(0.16, 1, 0.3, 1)';
    const rect = hostElement.getBoundingClientRect();
    const currentPos = { left: rect.left, top: rect.top };
    if (!lastSavedPos || lastSavedPos.left !== currentPos.left || lastSavedPos.top !== currentPos.top) {
      storage.set('ua-flag-pos', currentPos);
      lastSavedPos = currentPos;
    }
  }
};

// 事件监听器管理
function attachGlobalListeners() {
  if (boundHandlers) return;
  boundHandlers = { mouseMove: onMove, touchMove: onMove, mouseUp: endDrag, touchEnd: endDrag };
  document.addEventListener('mousemove', boundHandlers.mouseMove, { passive: true });
  document.addEventListener('touchmove', boundHandlers.touchMove, { passive: false });
  window.addEventListener('mouseup', boundHandlers.mouseUp, { passive: true });
  window.addEventListener('touchend', boundHandlers.touchEnd, { passive: true });
  window.addEventListener('touchcancel', boundHandlers.touchEnd, { passive: true });
}

function detachGlobalListeners() {
  if (!boundHandlers) return;
  document.removeEventListener('mousemove', boundHandlers.mouseMove);
  document.removeEventListener('touchmove', boundHandlers.touchMove);
  window.removeEventListener('mouseup', boundHandlers.mouseUp);
  window.removeEventListener('touchend', boundHandlers.touchEnd);
  window.removeEventListener('touchcancel', boundHandlers.touchEnd);
  boundHandlers = null;
}

// 边界校正
const ensureInBounds = () => {
  if (!hostElement || !lastSavedPos || hostElement.style.top === 'auto') return;
  const maxX = window.innerWidth - CONFIG.width;
  const maxY = window.innerHeight - CONFIG.height;
  let { left, top } = lastSavedPos;
  let updated = false;
  if (left > maxX) { left = Math.max(0, maxX); updated = true; }
  if (top > maxY) { top = Math.max(0, maxY); updated = true; }
  if (updated) {
    hostElement.style.left = `${left}px`;
    hostElement.style.top = `${top}px`;
    storage.set('ua-flag-pos', { left, top });
    lastSavedPos = { left, top };
  }
};

// 复位位置
const resetBadgePosition = () => {
  storage.remove('ua-flag-pos');
  lastSavedPos = null;
  if (hostElement) {
    hostElement.style.bottom = '60px';
    hostElement.style.left = '60px';
    hostElement.style.top = 'auto';
    hostElement.style.transform = 'translateX(0) scale(0.95)';
    setTimeout(() => {
      if (hostElement) hostElement.style.transform = 'translateX(0) scale(1)';
    }, 150);
  }
};

// HTML 生成(极简字符串模板)
function generateBadgeHTML() {
  // 解析配置字符串
  const parseConfig = (str, template) => {
    return str.split('|').map((item, idx) => {
      const params = item.split(',');
      return template(...params, idx);
    }).join('');
  };

  const sunflowersHtml = parseConfig(CONFIG.sunflowers, (l, b, s, h, leaf, d, z) =>
    `<div class="sunflower" style="left:${l}px;bottom:${b}px;transform:scale(${s});animation-delay:${d}s;z-index:${z}"><div class="flower-head"><div class="petals"></div><div class="core"></div></div><div class="stem" style="height:${h}px">${leaf ? `<div class="sf-leaf leaf-${leaf}"></div>` : ''}</div></div>`
  );

  const kalynaHtml = parseConfig(CONFIG.kalynaBranches, (l, b, s, d, rot, z, idx) => {
    const greenVar = idx % 2 === 0 ? '#2E7D32' : '#43A047';
    return `<div class="kalyna-branch" style="left:${l}px;bottom:${b}px;transform:scale(${s}) rotate(${rot}deg);animation-delay:${d}s;z-index:${z}"><div class="k-cluster"><div class="k-berry" style="background:radial-gradient(circle at 30% 30%,#ff5252,#b71c1c)"></div><div class="k-berry" style="background:radial-gradient(circle at 30% 30%,#ef5350,#c62828);width:8px;height:8px;left:12px;top:5px"></div><div class="k-berry" style="background:radial-gradient(circle at 30% 30%,#e53935,#c62828);width:7px;height:7px;left:6px;top:-4px"></div></div><div class="k-leaf k-l1" style="background-color:${greenVar}"></div><div class="k-leaf k-l2" style="background-color:${greenVar}"></div><div class="k-stem"></div></div>`;
  });

  const wheatHtml = parseConfig(CONFIG.wheatStalks, (l, b, s, h, rot, d, z) =>
    `<div class="wheat-stalk" style="left:${l}px;bottom:${b}px;transform:scale(${s}) rotate(${rot}deg);animation-delay:${d}s;z-index:${z}"><div class="w-head"><div class="w-grain r1"></div><div class="w-grain r2"></div><div class="w-grain r3"></div><div class="w-grain r4"></div><div class="w-grain r5"></div></div><div class="w-stem" style="height:${h}px"></div><div class="w-leaf"></div></div>`
  );

  const candleHtml = parseConfig(CONFIG.candles, (l, b, s, z) =>
    `<div class="candle-setup" style="left:${l}px;bottom:${b}px;transform:scale(${s});z-index:${z}"><div class="c-flame"><div class="f-inner"></div></div><div class="c-wick"></div><div class="c-wax"></div><div class="c-glow"></div></div>`
  );

  return `<style>:host{display:block;--ua-blue:${CONFIG.colors.blue};--ua-yellow:${CONFIG.colors.yellow};--pole-l:${CONFIG.colors.poleLight};--pole-d:${CONFIG.colors.poleDark}}.container{position:relative;width:100%;height:100%;display:flex;align-items:flex-end;user-select:none;overflow:hidden;pointer-events:none;-webkit-user-select:none}.drag-handle{position:absolute;left:25px;top:20px;width:45px;height:160px;z-index:999;pointer-events:auto;cursor:move;touch-action:none}.pole-system{position:absolute;left:40px;bottom:20px;height:160px;display:flex;flex-direction:column;align-items:center;z-index:100;pointer-events:none}.pole-top{width:14px;height:14px;background:radial-gradient(circle at 35% 35%,#FFFACD 0%,var(--ua-yellow) 45%,#C5A059 100%);border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.4);margin-bottom:-2px}.pole-body{width:8px;height:100%;background:linear-gradient(to right,var(--pole-d) 0%,#B8860B 15%,var(--pole-l) 40%,#FFF8E1 55%,var(--pole-l) 70%,#B8860B 85%,var(--pole-d) 100%);border-radius:0 0 4px 4px}.flag-wrapper{position:absolute;left:44px;top:32px;width:150px;height:90px;perspective:1200px;z-index:50;pointer-events:none}.flag{width:100%;height:100%;transform-style:preserve-3d;transform-origin:left center;animation:cinematic-wave 6s infinite ease-in-out;transform:translate3d(0,0,0)}.fabric{position:absolute;inset:0;background:linear-gradient(to bottom,var(--ua-blue) 50%,var(--ua-yellow) 50%);border-radius:0 4px 4px 0;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:inset 12px 0 15px rgba(0,0,0,.5);backface-visibility:hidden}.shading{position:absolute;inset:0;background:linear-gradient(90deg,rgba(0,0,0,.05) 0%,rgba(255,255,255,.15) 25%,rgba(0,0,0,.1) 50%,rgba(255,255,255,.15) 75%,rgba(0,0,0,.05) 100%);background-size:200% 100%;animation:move-shade 4s infinite linear;pointer-events:none}.trident{width:30px;filter:drop-shadow(0 4px 8px rgba(0,0,0,.4));transform:translateZ(10px)}.garden{position:absolute;left:0;bottom:0;width:100%;height:85px;pointer-events:none;contain:layout style paint}.sunflower,.kalyna-branch,.wheat-stalk{position:absolute;display:flex;flex-direction:column;align-items:center;transform-origin:bottom center}.sunflower{animation:flower-sway 5s infinite ease-in-out}.kalyna-branch{animation:flower-sway 6s infinite ease-in-out}.wheat-stalk{animation:flower-sway 7s infinite ease-in-out}.flower-head{width:24px;height:24px;position:relative}.petals{position:absolute;inset:0;background:radial-gradient(ellipse at center,#FFD700 35%,transparent 75%),repeating-conic-gradient(from 0deg,#FFC107 0deg 20deg,#F57F17 20deg 40deg);border-radius:50%}.petals::before{content:'';position:absolute;inset:-3px;background:repeating-conic-gradient(from 10deg,transparent 0deg 15deg,#FFD700 15deg 35deg,transparent 35deg 40deg);border-radius:50%;mask:radial-gradient(circle,black 40%,transparent 85%);-webkit-mask:radial-gradient(circle,black 40%,transparent 85%)}.core{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:8px;height:8px;background:#3E2723;border-radius:50%;box-shadow:inset 0 0 3px #000;z-index:2}.stem{width:2.5px;background:linear-gradient(to right,#1B5E20,#388E3C,#1B5E20);border-radius:2px;position:relative}.sf-leaf{position:absolute;width:9px;height:6px;background:radial-gradient(at 20% 20%,#66BB6A,#1B5E20);border-radius:1px 80% 1px 80%}.leaf-L{left:-8px;top:12px;transform:rotate(-20deg)}.leaf-R{right:-8px;top:18px;transform:scaleX(-1) rotate(-20deg)}.k-cluster{position:relative;top:-4px;left:-2px}.k-berry{width:10px;height:10px;border-radius:50%;position:absolute;top:0;left:0;box-shadow:1px 1px 2px rgba(0,0,0,.2)}.k-leaf{position:absolute;width:12px;height:6px;border-radius:50% 0 50% 0;clip-path:polygon(0% 100%,50% 0%,100% 100%)}.k-l1{bottom:4px;left:-8px;transform:rotate(-20deg)}.k-l2{bottom:6px;left:6px;transform:scaleX(-1) rotate(-25deg)}.k-stem{width:2px;height:35px;background:linear-gradient(to right,#2E7D32,#66BB6A);transform-origin:top center}.w-head{position:relative;width:10px;height:25px;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;margin-bottom:-2px}.w-grain{width:6px;height:8px;background:radial-gradient(circle at 30% 30%,#FFECB3,#FFB300);border-radius:50% 50% 50% 50% / 60% 60% 40% 40%;position:absolute;box-shadow:1px 1px 2px rgba(0,0,0,.2)}.r1{transform:rotate(-15deg) translateX(-4px);top:0}.r2{transform:rotate(15deg) translateX(4px);top:2px}.r3{top:5px;z-index:2;width:7px;height:9px}.r4{transform:rotate(-10deg) translateX(-3px);top:9px}.r5{transform:rotate(10deg) translateX(3px);top:11px}.w-stem{width:2px;background:linear-gradient(to right,#E6EE9C,#CDDC39);position:relative}.w-leaf{position:absolute;width:12px;height:3px;background:#CDDC39;bottom:10px;left:-10px;transform:rotate(-20deg);border-radius:50% 0 50% 0}.candle-setup{position:absolute;display:flex;flex-direction:column;align-items:center}.c-wax{width:14px;height:20px;background:linear-gradient(to right,#fafafa,#e0e0e0,#bdbdbd);border-radius:2px;box-shadow:inset -2px 0 5px rgba(0,0,0,.1)}.c-wick{width:2px;height:6px;background:#333;margin-bottom:-2px}.c-flame{width:10px;height:18px;background:radial-gradient(ellipse at 50% 85%,#FFFFFF 10%,#ffeb3b 40%,#ff9800 90%,#bf360c 100%);border-radius:50% 50% 50% 50% / 60% 60% 40% 40%;transform-origin:center bottom;animation:flicker .15s infinite alternate;position:relative;top:-2px;transform:translate3d(0,0,0)}.f-inner{position:absolute;bottom:2px;left:3px;width:4px;height:6px;background:rgba(255,255,255,.9);border-radius:50%;filter:blur(1px)}.c-glow{position:absolute;top:-50px;left:-30px;width:70px;height:70px;background:radial-gradient(circle,rgba(255,235,59,.35) 0%,transparent 60%);animation:glow-pulse 3s infinite ease-in-out;pointer-events:none;mix-blend-mode:screen}.ua-paused *{animation-play-state:paused !important}@keyframes cinematic-wave{0%,100%{transform:rotateY(12deg) rotateX(2deg) translate3d(0,0,0)}50%{transform:rotateY(26deg) rotateX(-2deg) translate3d(0,0,0)}}@keyframes flower-sway{0%,100%{transform:rotate(-3deg) translate3d(0,0,0)}50%{transform:rotate(3deg) translate3d(0,0,0)}}@keyframes move-shade{from{background-position:0 0}to{background-position:200% 0}}@keyframes flicker{0%{transform:scale(1) rotate(-2deg) translate3d(0,0,0)}100%{transform:scale(1.02) rotate(2deg) translate3d(0,0,0)}}@keyframes glow-pulse{0%,100%{opacity:.5;transform:scale(1) translate3d(0,0,0)}50%{opacity:.8;transform:scale(1.1) translate3d(0,0,0)}}</style>
<div class="container">
  <div class="drag-handle" title="拖动移动,双击复位"></div>
  <div class="pole-system">
    <div class="pole-top"></div>
    <div class="pole-body"></div>
  </div>
  <div class="flag-wrapper">
    <div class="flag">
      <div class="fabric">
        <div class="shading"></div>
        <img src="${TRIDENT_SVG}" class="trident">
      </div>
    </div>
  </div>
  <div class="garden">
    ${wheatHtml}${kalynaHtml}${sunflowersHtml}${candleHtml}
  </div>
</div>`;
}

// 注入徽章
function injectBadge() {
  if (!canRun()) return;
  if (hostElement?.isConnected) return;

  const existingHost = document.getElementById('ua-waving-badge-root');
  if (existingHost) {
    hostElement = existingHost;
    shadowRoot = existingHost.shadowRoot;
    return;
  }

  const host = document.createElement('div');
  host.id = 'ua-waving-badge-root';
  host.setAttribute('aria-hidden', 'true');
  host.lang = 'uk';
  host.title = '🇺🇦 Ukraine - Слава Україні!';

  lastSavedPos = storage.get('ua-flag-pos', null);
  const styles = {
    position: 'fixed',
    zIndex: '2147483647',
    pointerEvents: 'none',
    transition: 'all 0.8s cubic-bezier(0.16,1,0.3,1)',
    opacity: '0',
    transform: 'translateX(-20px) scale(0.9)',
    width: `${CONFIG.width}px`,
    height: `${CONFIG.height}px`,
    contain: 'layout style paint',
  };

  if (lastSavedPos && lastSavedPos.left >= 0 && lastSavedPos.left < window.innerWidth) {
    styles.top = `${lastSavedPos.top}px`;
    styles.left = `${lastSavedPos.left}px`;
  } else {
    styles.bottom = '60px';
    styles.left = '60px';
  }

  Object.assign(host.style, styles);
  document.documentElement.appendChild(host);
  hostElement = host;

  const shadow = host.attachShadow({ mode: 'closed' });
  shadowRoot = shadow;
  shadow.innerHTML = generateBadgeHTML();

  const dragHandle = shadow.querySelector('.drag-handle');
  if (dragHandle) {
    dragHandle.addEventListener('mousedown', startDrag);
    dragHandle.addEventListener('touchstart', startDrag, { passive: false });
    dragHandle.addEventListener('dblclick', resetBadgePosition);
  }

  requestAnimationFrame(() => {
    if (hostElement) {
      hostElement.style.opacity = '1';
      hostElement.style.transform = 'translateX(0) scale(1)';
    }
  });
}

// 销毁
function destroyBadge() {
  if (rafId) cancelAnimationFrame(rafId);
  if (hostElement) {
    hostElement.remove();
    hostElement = null;
  }
  shadowRoot = null;
  detachGlobalListeners();
  isTerminated = true;
}

// 视口可见性检测(极简)
let lastScrollTime = 0;
let scrollRafId = null;
const checkVisibility = () => {
  if (!hostElement) return;
  const rect = hostElement.getBoundingClientRect();
  const isVisible = rect.right > 0 && rect.left < window.innerWidth && rect.bottom > 0 && rect.top < window.innerHeight;
  hostElement.classList.toggle('ua-paused', !isVisible);
};

const onScrollOrResize = () => {
  const now = performance.now();
  if (now - lastScrollTime < 200) return;
  lastScrollTime = now;
  if (scrollRafId) return;
  scrollRafId = requestAnimationFrame(() => {
    checkVisibility();
    ensureInBounds();
    scrollRafId = null;
  });
};

// 全局快捷键
window.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.shiftKey && e.code === 'KeyU') {
    e.preventDefault();
    hostElement ? destroyBadge() : canRun() && (isTerminated = false, injectBadge());
  }
}, { passive: false, capture: true });

// 初始化
if (document.readyState === 'loading') {
  window.addEventListener('DOMContentLoaded', () => {
    injectBadge();
    window.addEventListener('scroll', onScrollOrResize, { passive: true });
    window.addEventListener('resize', onScrollOrResize, { passive: true });
  }, { once: true, passive: true });
} else {
  injectBadge();
  window.addEventListener('scroll', onScrollOrResize, { passive: true });
  window.addEventListener('resize', onScrollOrResize, { passive: true });
}
})();