// ==UserScript== // @name Amazing click effect! // @namespace http://tampermonkey.net/ // @version 1.14.1 // @description Enjoy clicking time! // @author Super_Diu and twyeottk(1000ttank) // @contributors Pigeonw Development // @match *://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/565342/Amazing%20click%20effect%21.user.js // @updateURL https://update.greasyfork.icu/scripts/565342/Amazing%20click%20effect%21.meta.js // ==/UserScript== (function() { 'use strict'; const defCfg = { BASE_SPD: 3, BASE_SPD_MAX: 5, BASE_CNT: 12, MAX_SPD_LIMIT: 15, MIN_SPD_LIMIT: 8, MAX_CNT: 30, LONG_PRESS: 800, SCALE_DUR: 3000, MAX_SIZE: 20, MIN_ALPHA_SPD: 8, ALPHA_SPD_BASE: 25, ALPHA_DECAY_SCALE: 1.1, TRI_SPD_DECAY: 0.998, DOT_R_MIN: 1, DOT_R_MAX: 3, DOT_INIT_SPD: 1.2, DOT_ACCEL: 0.2, DOT_ALPHA_SPD: 0.02, DOT_FADE_BASE: 0.03, DOT_SPAWN_R_MIN: 120, DOT_SPAWN_R_MAX: 350, DOT_ANGLE_JITTER: 0.3, SPD_ALPHA_FACTOR: 0.0001, BASE_COLL_PART_CNT: 8, MAX_COLL_PART_CNT: 20, BASE_COLL_SPD: 2, MAX_COLL_SPD: 10, BASE_COLL_SIZE: 2, MAX_COLL_SIZE: 5, MAX_TRACK: 6, DOT_TRACK: 3, SPD_FADE_FACTOR: 0.002, CHARGE_ALPHA_SCALE: 0.3, NORMAL_ALPHA_SCALE: 1.0 }; const cfg = {}; Object.keys(defCfg).forEach(k => { cfg[k] = GM_getValue(k, defCfg[k]); }); const decimalParams = new Set(['NORMAL_ALPHA_SCALE', 'CHARGE_ALPHA_SCALE', 'MAX_COLL_SPD']); function createCfgMenu() { GM_registerMenuCommand('⚙️ 点击特效配置', () => { const container = document.createElement('div'); container.style.cssText = ` position:fixed;top:50%;left:50%;transform:translate(-50%,-50%); background:#ffffff;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,0.15); z-index:9999999;width:90%;max-width:900px;height:80vh;max-height:700px; display:flex;flex-direction:column;overflow:hidden; font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif; `; const header = document.createElement('div'); header.style.cssText = ` display:flex;align-items:center;justify-content:space-between; padding:16px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0; `; container.appendChild(header); const menuBar = document.createElement('div'); menuBar.style.cssText = `display:flex;gap:8px;`; header.appendChild(menuBar); const menuItems = [ { id: 'cfg-panel', text: '配置面板' }, { id: 'guide-panel', text: '使用说明' } ]; menuItems.forEach(item => { const btn = document.createElement('button'); btn.textContent = item.text; btn.style.cssText = ` padding:8px 16px;border:none;border-radius:6px; background:${item.id === 'cfg-panel' ? '#3b82f6' : 'transparent'}; color:${item.id === 'cfg-panel' ? '#ffffff' : '#334155'}; cursor:pointer;transition:all 0.2s ease; font-size:14px;font-weight:500; `; btn.dataset.target = item.id; btn.addEventListener('click', (e) => { menuBar.querySelectorAll('button').forEach(b => { b.style.background = b.dataset.target === e.target.dataset.target ? '#3b82f6' : 'transparent'; b.style.color = b.dataset.target === e.target.dataset.target ? '#ffffff' : '#334155'; }); document.querySelectorAll('.content-panel').forEach(panel => { panel.style.display = panel.id === e.target.dataset.target ? 'block' : 'none'; }); }); menuBar.appendChild(btn); }); const closeBtn = document.createElement('button'); closeBtn.innerHTML = '×'; closeBtn.style.cssText = ` width:32px;height:32px;border:none;border-radius:50%; background:#fef2f2;color:#ef4444;cursor:pointer; font-size:20px;display:flex;align-items:center;justify-content:center; transition:all 0.2s ease;position:relative;z-index:1;outline:none; `; closeBtn.addEventListener('mouseenter', () => { closeBtn.style.background = '#ef4444'; closeBtn.style.color = '#ffffff'; }); closeBtn.addEventListener('mouseleave', () => { closeBtn.style.background = '#fef2f2'; closeBtn.style.color = '#ef4444'; }); closeBtn.addEventListener('click', () => { container.remove(); mask.remove(); }); header.appendChild(closeBtn); const contentWrap = document.createElement('div'); contentWrap.style.cssText = ` flex:1;overflow-y:auto;padding:24px;max-height:100%;box-sizing:border-box;background:#fafafa; `; container.appendChild(contentWrap); const cfgPanel = document.createElement('div'); cfgPanel.id = 'cfg-panel'; cfgPanel.className = 'content-panel'; cfgPanel.style.display = 'block'; cfgPanel.innerHTML = `

点击特效配置

📌 普通点击专属参数

当前值:${cfg.BASE_SPD}
当前值:${cfg.BASE_SPD_MAX}
当前值:${cfg.BASE_CNT}
当前值:${cfg.NORMAL_ALPHA_SCALE.toFixed(1)}

🚀 蓄力专属参数

当前值:${cfg.MIN_SPD_LIMIT}
当前值:${cfg.MAX_SPD_LIMIT}
当前值:${cfg.MAX_CNT}
当前值:${cfg.LONG_PRESS}
当前值:${cfg.CHARGE_ALPHA_SCALE.toFixed(1)}

🔧 核心通用参数

当前值:${cfg.MAX_SIZE}
当前值:${cfg.MAX_COLL_SPD.toFixed(1)}
当前值:${cfg.MAX_TRACK}
当前值:${cfg.DOT_TRACK}
`; contentWrap.appendChild(cfgPanel); const guidePanel = document.createElement('div'); guidePanel.id = 'guide-panel'; guidePanel.className = 'content-panel'; guidePanel.style.display = 'none'; guidePanel.innerHTML = `

使用说明

1. 基础操作

2. 注意事项

3. 开发人员

`; contentWrap.appendChild(guidePanel); const mask = document.createElement('div'); mask.style.cssText = ` position:fixed;top:0;left:0;width:100%;height:100%; background:rgba(0,0,0,0.5);z-index:9999998;backdrop-filter:blur(2px); `; document.body.appendChild(mask); document.body.appendChild(container); function initSlider(sliderGroup) { const container = sliderGroup.querySelector('.slider-container'); const progress = sliderGroup.querySelector('.slider-progress'); const thumb = sliderGroup.querySelector('.slider-thumb'); const input = sliderGroup.querySelector('.slider-input'); const valueDisplay = sliderGroup.querySelector('.slider-value'); const paramName = sliderGroup.dataset.param; const min = parseFloat(input.min); const max = parseFloat(input.max); const step = parseFloat(input.step); const showDecimal = decimalParams.has(paramName); const getPercent = (value) => { return Math.max(0, Math.min(100, ((value - min) / (max - min)) * 100)); }; const formatValue = (value) => { if (showDecimal) { return value.toFixed(1); } return Math.round(value).toString(); }; const updateSlider = (value, animate = false) => { const percent = getPercent(value); if (animate) { progress.style.transition = 'width 0.2s ease'; thumb.style.transition = 'left 0.2s ease'; } else { progress.style.transition = 'none'; thumb.style.transition = 'none'; } progress.style.width = `${percent}%`; thumb.style.left = `${percent}%`; input.value = value; valueDisplay.textContent = `当前值:${formatValue(value)}`; }; const getValueFromMouse = (clientX) => { const rect = container.getBoundingClientRect(); const mouseX = Math.max(0, Math.min(rect.width, clientX - rect.left)); const percent = (mouseX / rect.width); let value = min + percent * (max - min); if (step !== 1) { value = Math.round(value / step) * step; } else { value = Math.round(value); } return Math.max(min, Math.min(max, value)); }; updateSlider(parseFloat(input.value), false); let isDragging = false; const handleMouseDown = (e) => { e.preventDefault(); e.stopPropagation(); isDragging = true; const value = getValueFromMouse(e.clientX); updateSlider(value, false); const handleMouseMove = (e) => { if (!isDragging) return; const value = getValueFromMouse(e.clientX); updateSlider(value, false); }; const handleMouseUp = () => { if (!isDragging) return; isDragging = false; document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); document.removeEventListener('mouseleave', handleMouseUp); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); document.addEventListener('mouseleave', handleMouseUp); }; thumb.addEventListener('mousedown', handleMouseDown); container.addEventListener('mousedown', handleMouseDown); input.addEventListener('input', () => { updateSlider(parseFloat(input.value), true); }); sliderGroup.getValue = () => { return parseFloat(input.value); }; } document.querySelectorAll('.slider-group').forEach(initSlider); document.getElementById('saveBtn').addEventListener('click', () => { document.querySelectorAll('.slider-group').forEach(group => { const paramName = group.dataset.param; const value = group.getValue(); GM_setValue(paramName, value); cfg[paramName] = value; }); alert('配置保存成功!立即生效'); container.remove(); mask.remove(); }); document.getElementById('resetBtn').addEventListener('click', () => { if (confirm('确定要重置所有配置为默认值吗?')) { Object.keys(defCfg).forEach(k => { GM_setValue(k, defCfg[k]); cfg[k] = defCfg[k]; }); alert('已重置为默认配置!'); container.remove(); mask.remove(); location.reload(); } }); }); } function clickTriEffect() { let tris = []; let dots = []; let cvs, ctx; let w, h; const blueColors = ["#1E90FF", "#4169E1", "#00BFFF", "#87CEFA", "#6495ED", "#0099FF", "#7B68EE"]; const triTypes = ["acute", "right", "obtuse", "isosceles", "equilateral"]; let MAX_TRACK = cfg.MAX_TRACK; let DOT_TRACK = cfg.DOT_TRACK; let pressStart = 0; let isPress = false; let px = 0, py = 0; let lastDotSpawn = 0; const DOT_INTERVAL = 150; let collMode = false; const CONTENT_TAGS = new Set(['P', 'SPAN', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'A', 'LI', 'TD', 'IMG', 'CANVAS', 'SVG', 'VIDEO']); const INTERACTIVE_TAGS = new Set(['INPUT', 'TEXTAREA', 'BUTTON', 'SELECT', 'TEXTAREA', 'LABEL', 'FORM']); cvs = document.createElement("canvas"); document.body.appendChild(cvs); cvs.setAttribute("style", "width:100%;height:100%;top:0;left:0;z-index:99999;position:fixed;pointer-events:none;"); ctx = cvs.getContext("2d"); updateCvsSize(); window.addEventListener('resize', updateCvsSize, false); requestAnimationFrame(loop); window.addEventListener("keydown", function(e) { if (e.keyCode === 192) { const activeEl = document.activeElement; if (INTERACTIVE_TAGS.has(activeEl.tagName) || activeEl.isContentEditable) { return; } else { collMode = !collMode; e.preventDefault(); } } }); window.addEventListener("mousedown", function(e){ isPress = true; pressStart = Date.now(); px = e.clientX; py = e.clientY; lastDotSpawn = Date.now(); }); window.addEventListener("mouseup", createEffect); window.addEventListener("mouseout", function(){ isPress = false; pressStart = 0; dots.forEach(dot => dot.needFade = true); }); window.addEventListener("mousemove", function(e){ if(isPress){ px = e.clientX; py = e.clientY; dots.forEach(dot => { if(!dot.arrived && !dot.hasColl) { dot.tx = px; dot.ty = py; dot.angle = Math.atan2(dot.ty - dot.y, dot.tx - dot.x); } }); } }); function updateCvsSize(){ cvs.width = window.innerWidth * 2; cvs.height = window.innerHeight * 2; cvs.style.width = window.innerWidth + 'px'; cvs.style.height = window.innerHeight + 'px'; ctx.scale(2,2); w = window.innerWidth; h = window.innerHeight; } function alphaToHex(alpha){ const hex = Math.floor(Math.max(0, Math.min(255, alpha*255))).toString(16); return hex.length===1 ? '0'+hex : hex; } function randInt(min,max){ return Math.floor(Math.random()*(max-min+1))+min; } function randFloat(min,max){ return Math.random()*(max-min)+min; } function isRealContentEl(el) { if (!el) return false; if (INTERACTIVE_TAGS.has(el.tagName)) return false; if (['IMG', 'CANVAS', 'SVG', 'VIDEO'].includes(el.tagName)) return true; if (CONTENT_TAGS.has(el.tagName)) { const text = el.textContent?.trim() || ''; const rect = el.getBoundingClientRect(); const hasSize = rect.width > 0 && rect.height > 0; const isVisible = window.getComputedStyle(el).display !== 'none' && window.getComputedStyle(el).visibility !== 'hidden'; return text.length > 0 && hasSize && isVisible; } const parent = el.parentElement; return parent ? isRealContentEl(parent) : false; } function isPointOnContent(x, y) { const el = document.elementFromPoint(x, y); if (!el || el === cvs) return false; return isRealContentEl(el); } function checkColl(x, y) { if (!collMode) return false; if (x < 0 || x > w || y < 0 || y > h) return true; return isPointOnContent(x, y); } function getBounceRange(flyAngle) { flyAngle = flyAngle % (Math.PI * 2); if (flyAngle < 0) flyAngle += Math.PI * 2; let minAngle, maxAngle; if (flyAngle >= Math.PI/2 && flyAngle <= Math.PI*3/2) { if (flyAngle >= Math.PI/2 && flyAngle <= Math.PI) { minAngle = -Math.PI; maxAngle = 0; } else { minAngle = -Math.PI/2; maxAngle = Math.PI/2; } } else { if (flyAngle < Math.PI/2) { minAngle = -Math.PI/2; maxAngle = Math.PI/2; } else { minAngle = Math.PI/2; maxAngle = Math.PI*3/2; } } if (flyAngle > Math.PI/4 && flyAngle < Math.PI*3/4) { minAngle = -Math.PI; maxAngle = 0; } else if (flyAngle > Math.PI*5/4 && flyAngle < Math.PI*7/4) { minAngle = -Math.PI/2; maxAngle = Math.PI/2; } return { minAngle, maxAngle }; } function createCollEffect(x, y, color, size, flyAngle, spd) { const sizeRatio = Math.min(1, size / cfg.MAX_SIZE); const spdRatio = Math.min(1, spd / cfg.MAX_SPD_LIMIT); const partCnt = Math.floor(cfg.BASE_COLL_PART_CNT + sizeRatio * (cfg.MAX_COLL_PART_CNT - cfg.BASE_COLL_PART_CNT)); const maxSpd = cfg.BASE_COLL_SPD + spdRatio * (cfg.MAX_COLL_SPD - cfg.BASE_COLL_SPD); const maxSize = cfg.BASE_COLL_SIZE + sizeRatio * (cfg.MAX_COLL_SIZE - cfg.BASE_COLL_SIZE); const { minAngle, maxAngle } = getBounceRange(flyAngle); for (let i = 0; i < partCnt; i++) { const angle = randFloat(minAngle, maxAngle); const centerAngle = (minAngle + maxAngle) / 2; const spdFactor = Math.cos(angle - centerAngle); const partSpd = randFloat(maxSpd * 0.7, maxSpd) * (0.9 + spdFactor * 0.3); const partSize = randFloat(maxSize * 0.5, maxSize); tris.push(new CollPart( x, y, angle, partSpd, partSize, color, sizeRatio )); } } function createEffect(){ if(!isPress) return; const pressDur = Date.now() - pressStart; isPress = false; pressStart = 0; dots.forEach(dot => dot.needFade = true); let sizeMin = 7, sizeMax = 13; let alphaSpdMin = cfg.ALPHA_SPD_BASE, alphaSpdMax = 35; let createCnt = cfg.BASE_CNT; let spdMin, spdMax; let isCharge = false; if(pressDur < cfg.LONG_PRESS){ spdMin = cfg.BASE_SPD; spdMax = cfg.BASE_SPD_MAX; } else { isCharge = true; const over = pressDur - cfg.LONG_PRESS; const scale = Math.min(1, over/cfg.SCALE_DUR); createCnt = Math.floor(cfg.BASE_CNT + scale*(cfg.MAX_CNT - cfg.BASE_CNT)); sizeMax = 13 + scale*(cfg.MAX_SIZE - 13); spdMin = cfg.MIN_SPD_LIMIT; spdMax = cfg.MAX_SPD_LIMIT; alphaSpdMin = cfg.ALPHA_SPD_BASE - scale*(cfg.ALPHA_SPD_BASE - cfg.MIN_ALPHA_SPD); alphaSpdMax = 35 - scale*(35 - cfg.MIN_ALPHA_SPD); } for(let i=0;iDOT_TRACK) this.track.shift(); } update(){ if(this.arrived || this.hasColl){ this.alpha=0; this.track = []; return; } if (collMode && checkColl(this.x, this.y)) { this.hasColl = true; this.alpha = 0; this.track = []; return; } this.addTrack(); const spdFactor = 1+this.spd*cfg.SPD_ALPHA_FACTOR; this.alpha = this.needFade ? Math.max(0,this.alpha-cfg.DOT_FADE_BASE*spdFactor) : Math.min(1,this.alpha+cfg.DOT_ALPHA_SPD*spdFactor); const dx = this.tx - this.x; const dy = this.ty - this.y; const dist = Math.sqrt(dx*dx+dy*dy); const nextStep = this.spd+this.accel; if(dist<=this.r*3 || nextStep>=dist){ this.arrived=true; this.alpha=0; this.track=[]; this.x=this.tx; this.y=this.ty; } else { this.spd = Math.min(this.spd+this.accel,8); this.x += Math.cos(this.angle)*this.spd; this.y += Math.sin(this.angle)*this.spd; } } drawTrail(){ if(this.track.length<2 || this.alpha<=0 || this.arrived || this.hasColl) return; ctx.save(); ctx.beginPath(); ctx.moveTo(this.track[0].x,this.track[0].y); for(let i=1;iMAX_TRACK) this.track.shift(); } drawSingle(ctx,x,y,rot,size,alpha){ if(alpha<=0||size<=0) return; ctx.save(); ctx.globalAlpha=alpha; ctx.translate(x,y); ctx.rotate(rot*Math.PI/180); ctx.fillStyle=this.color; ctx.beginPath(); switch(this.type){ case"acute":ctx.moveTo(0,-size);ctx.lineTo(size*0.7,size*0.6);ctx.lineTo(-size*0.7,size*0.6);break; case"right":ctx.moveTo(0,-size*0.8);ctx.lineTo(size*0.8,size*0.8);ctx.lineTo(-size*0.8,size*0.8);break; case"obtuse":ctx.moveTo(0,-size);ctx.lineTo(size*1.0,size*0.4);ctx.lineTo(-size*1.0,size*0.4);break; case"isosceles":ctx.moveTo(0,-size);ctx.lineTo(size*0.6,size*0.8);ctx.lineTo(-size*0.6,size*0.8);break; case"equilateral":const h=size*Math.sqrt(3)/2;ctx.moveTo(0,-h/2);ctx.lineTo(size/2,h/2);ctx.lineTo(-size/2,h/2);break; } ctx.closePath();ctx.fill();ctx.restore(); } drawTrail(ctx){ if(this.track.length<2||this.alpha<=0) return; const trackCnt=this.track.length; const startP=this.track[0]; const endP=this.track[trackCnt-1]; const trailAngle=Math.atan2(endP.y-startP.y,endP.x-startP.x); const endW=endP.size*0.3; const startW=endW*0.05; ctx.save(); const endLX=endP.x+Math.cos(trailAngle+Math.PI/2)*endW; const endLY=endP.y+Math.sin(trailAngle+Math.PI/2)*endW; const endRX=endP.x+Math.cos(trailAngle-Math.PI/2)*endW; const endRY=endP.y+Math.sin(trailAngle-Math.PI/2)*endW; const startX=startP.x+Math.cos(trailAngle)*startW; const startY=startP.y+Math.sin(trailAngle)*startW; ctx.beginPath(); ctx.moveTo(endLX,endLY); ctx.lineTo(endRX,endRY); ctx.lineTo(startX,startY); ctx.closePath(); const grad=ctx.createLinearGradient(endP.x,endP.y,startP.x,startP.y); grad.addColorStop(0,`${this.color}${alphaToHex(Math.min(0.4,this.alpha))}`); grad.addColorStop(1,`${this.color}10`); ctx.fillStyle=grad; ctx.fill(); ctx.restore(); } draw(){if(this.alpha<=0) return; this.drawTrail(ctx); this.drawSingle(ctx,this.x,this.y,this.rot,this.size,this.alpha);} } function loop(){ ctx.clearRect(0,0,w,h); if(isPress){ const pressDur=Date.now()-pressStart; if(pressDur >= cfg.LONG_PRESS){ const now=Date.now(); if(now-lastDotSpawn>=DOT_INTERVAL){ dots.push(new Dot(px,py)); lastDotSpawn=now; } } } dots.forEach(dot=>dot.update()); dots.forEach(dot=>dot.draw()); dots=dots.filter(dot=>dot.alpha>0&&!dot.arrived&&!dot.hasColl); tris.forEach(tri=>{ if (tri.isCollPart) { tri.update(); } else { tri.update(); } }); tris.forEach(tri=>{ if (tri.isCollPart) { tri.draw(); } else { tri.draw(); } }); tris=tris.filter(tri=>{ if (tri.isCollPart) { return tri.alpha > 0 && tri.size > 0; } else { return tri.alpha > 0 && !tri.hasColl; } }); requestAnimationFrame(loop); } } createCfgMenu(); clickTriEffect(); })();