// ==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. 基础操作
- 点击:释放蓝色三角
- 长按:蓄力越久,威力越大
- 开启碰撞模式:按下键盘左上角 "~"(ESC下面)开启,所有三角形都会爆炸!
2. 注意事项
- 配置修改后需点击「保存配置」才能生效
- 最慢速度建议大于最快速度(不然到底是最大还是最小?)
- 参数值过大可能导致卡顿哦~
3. 开发人员
- Super_Diu(uid:1057013)项目开创者
- twyeottk (uid:1635665)项目合作者(比楼上厉害)
- doubao(uid:?)项目开发者
`;
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();
})();