mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-05-29 23:55:48 +08:00
feat: 千星脚本添加html遮罩 (#3081)
* feat: 版本检测工具 * feat: 千星脚本添加html遮罩 * 添加存档 * feat: 版本检测
This commit is contained in:
10
repo/js/WeeklyThousandStarRealm/progress-mask/index.html
Normal file
10
repo/js/WeeklyThousandStarRealm/progress-mask/index.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
18
repo/js/WeeklyThousandStarRealm/progress-mask/package.json
Normal file
18
repo/js/WeeklyThousandStarRealm/progress-mask/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "progress-mask",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build && node ../../build/rename.js dist/index.html dist/progress-mask.html",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"gsap": "^3.12.7",
|
||||
"vue": "^3.5.30"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.4"
|
||||
}
|
||||
}
|
||||
318
repo/js/WeeklyThousandStarRealm/progress-mask/src/App.vue
Normal file
318
repo/js/WeeklyThousandStarRealm/progress-mask/src/App.vue
Normal file
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div class="overlay">
|
||||
<canvas ref="canvas" class="particle-canvas"></canvas>
|
||||
<div class="content" ref="content">
|
||||
<div class="title" ref="titleEl">{{ title }}</div>
|
||||
<div class="fraction" ref="fractionWrap">
|
||||
<span class="frac-current">{{ current }}</span>
|
||||
<span class="frac-sep">/</span>
|
||||
<span class="frac-total">{{ total }}</span>
|
||||
</div>
|
||||
<div class="bar-area" ref="barArea">
|
||||
<div class="bar-glow"></div>
|
||||
<div class="bar-track">
|
||||
<div class="bar-fill" ref="barFill">
|
||||
<div class="bar-shine"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="percent-wrap" ref="percentWrap">
|
||||
<span class="percent-value">{{ displayProgress }}</span>
|
||||
<span class="percent-unit">%</span>
|
||||
</div>
|
||||
<div class="status" ref="statusEl">{{ status }}</div>
|
||||
</div>
|
||||
<div v-if="showSkill" class="special-skill">
|
||||
<span>如需使用秒刷图,请查看脚本说明中的焚诀</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import gsap from 'gsap'
|
||||
|
||||
const canvas = ref(null)
|
||||
const content = ref(null)
|
||||
const titleEl = ref(null)
|
||||
const fractionWrap = ref(null)
|
||||
const barArea = ref(null)
|
||||
const barFill = ref(null)
|
||||
const percentWrap = ref(null)
|
||||
const statusEl = ref(null)
|
||||
const showSkill = ref(false)
|
||||
|
||||
const title = ref('')
|
||||
const status = ref('等待中...')
|
||||
const progress = ref(0)
|
||||
const displayProgress = ref(0)
|
||||
const current = ref(0)
|
||||
const total = ref(0)
|
||||
|
||||
let animId = null
|
||||
let particles = []
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
showSkill.value = false
|
||||
}, 60000)
|
||||
|
||||
window.htmlMask.onMessage = (msg) => {
|
||||
if (msg.url === '/progress') {
|
||||
if (msg.data.title !== undefined) title.value = msg.data.title
|
||||
if (msg.data.status) status.value = msg.data.status
|
||||
if (msg.data.current !== undefined) current.value = msg.data.current
|
||||
if (msg.data.total !== undefined) total.value = msg.data.total
|
||||
if (msg.data.progress !== undefined) {
|
||||
const pct = Math.min(100, Math.max(0, msg.data.progress))
|
||||
progress.value = pct
|
||||
gsap.to(displayProgress, { value: pct, duration: 0.5, snap: { value: 1 } })
|
||||
gsap.to(barFill.value, { height: pct + '%', duration: 2, ease: 'power2.out' })
|
||||
}
|
||||
} else if (msg.url === '/showskill') {
|
||||
showSkill.value = msg.data.show;
|
||||
}
|
||||
}
|
||||
|
||||
const tl = gsap.timeline({ defaults: { ease: 'power3.out' } })
|
||||
tl.from(content.value, { opacity: 0, x: 40, duration: 0.5 })
|
||||
.from(titleEl.value, { y: -15, opacity: 0, duration: 0.3 }, '-=0.2')
|
||||
.from(fractionWrap.value, { scale: 0.5, opacity: 0, duration: 0.4, ease: 'back.out(1.7)' }, '-=0.1')
|
||||
.from(barArea.value, { scaleY: 0, opacity: 0, duration: 0.4 }, '-=0.1')
|
||||
.from(percentWrap.value, { scale: 0.5, opacity: 0, duration: 0.4, ease: 'back.out(1.7)' }, '-=0.1')
|
||||
.from(statusEl.value, { y: 10, opacity: 0, duration: 0.3 }, '-=0.1')
|
||||
|
||||
initParticles()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.htmlMask.onMessage = null
|
||||
if (animId) cancelAnimationFrame(animId)
|
||||
})
|
||||
|
||||
function initParticles() {
|
||||
const cvs = canvas.value
|
||||
cvs.width = window.innerWidth
|
||||
cvs.height = window.innerHeight
|
||||
const ctx = cvs.getContext('2d')
|
||||
|
||||
const COUNT = 35
|
||||
particles = Array.from({ length: COUNT }, () => spawn(cvs))
|
||||
|
||||
;(function loop() {
|
||||
ctx.clearRect(0, 0, cvs.width, cvs.height)
|
||||
for (const p of particles) {
|
||||
p.x += p.vx
|
||||
p.y += p.vy
|
||||
p.life -= p.decay
|
||||
if (p.life <= 0) Object.assign(p, spawn(cvs))
|
||||
|
||||
ctx.save()
|
||||
ctx.globalAlpha = p.life * p.alpha
|
||||
ctx.shadowBlur = p.size * 6
|
||||
ctx.shadowColor = p.color
|
||||
ctx.fillStyle = p.color
|
||||
ctx.beginPath()
|
||||
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
ctx.restore()
|
||||
}
|
||||
animId = requestAnimationFrame(loop)
|
||||
})()
|
||||
}
|
||||
|
||||
function spawn(cvs) {
|
||||
// 粒子从右侧进度条区域生成
|
||||
const rx = cvs.width - 70
|
||||
const cy = cvs.height / 2
|
||||
return {
|
||||
x: rx + (Math.random() - 0.5) * 60,
|
||||
y: cy + (Math.random() - 0.5) * 280,
|
||||
vx: (Math.random() - 0.5) * 0.5 + 0.3,
|
||||
vy: -(Math.random() * 0.8 + 0.2),
|
||||
size: Math.random() * 2.5 + 0.5,
|
||||
life: 1,
|
||||
decay: Math.random() * 0.008 + 0.004,
|
||||
alpha: Math.random() * 0.5 + 0.2,
|
||||
color: Math.random() > 0.3 ? '#00ff88' : '#88ffcc',
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: transparent; font-family: 'Segoe UI', system-ui, sans-serif; }
|
||||
|
||||
.overlay {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-right: 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.particle-canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 标题 */
|
||||
.title {
|
||||
font-size: 15px;
|
||||
letter-spacing: 6px;
|
||||
color: rgba(0, 255, 136, 0.85);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* 分数 3/15 */
|
||||
.fraction {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.frac-current {
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
|
||||
}
|
||||
|
||||
.frac-sep {
|
||||
font-size: 22px;
|
||||
font-weight: 300;
|
||||
color: rgba(0, 255, 136, 0.7);
|
||||
}
|
||||
|
||||
.frac-total {
|
||||
font-size: 22px;
|
||||
font-weight: 300;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
/* 竖向进度条 */
|
||||
.bar-area {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bar-glow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 400%;
|
||||
height: 130%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: radial-gradient(ellipse, rgba(0, 255, 136, 0.08), transparent 60%);
|
||||
pointer-events: none;
|
||||
filter: blur(20px);
|
||||
animation: glow-pulse 2.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes glow-pulse {
|
||||
0%, 100% { opacity: 0.7; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
.bar-track {
|
||||
width: 14px;
|
||||
height: 260px;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
border-radius: 7px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow:
|
||||
inset 2px 3px 6px rgba(0, 0, 0, 0.6),
|
||||
inset -1px 0 2px rgba(255, 255, 255, 0.04),
|
||||
1px 0 0 rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 0%;
|
||||
border-radius: 7px;
|
||||
background: linear-gradient(90deg,
|
||||
rgba(255,255,255,0.2) 0%,
|
||||
#00ff88 15%,
|
||||
#00dd70 45%,
|
||||
#00aa55 80%,
|
||||
#008844 100%
|
||||
);
|
||||
box-shadow:
|
||||
0 0 12px rgba(0, 255, 136, 0.4),
|
||||
0 0 28px rgba(0, 255, 136, 0.15);
|
||||
}
|
||||
|
||||
/* 3D 高光 */
|
||||
.bar-shine {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 40%;
|
||||
background: linear-gradient(90deg, rgba(255,255,255,0.35), transparent);
|
||||
border-radius: 7px 0 0 7px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 百分比 */
|
||||
.percent-wrap {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.percent-value {
|
||||
font-size: 36px;
|
||||
font-weight: 200;
|
||||
color: #fff;
|
||||
text-shadow:
|
||||
0 0 20px rgba(0, 255, 136, 0.3),
|
||||
0 0 40px rgba(0, 255, 136, 0.1);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.percent-unit {
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
color: rgba(0, 255, 136, 0.7);
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/* 状态文字 */
|
||||
.status {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
letter-spacing: 1px;
|
||||
max-width: 100px;
|
||||
text-align: center;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.special-skill {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
color: #0aff96;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-shadow: 5px 0 5px rgba(0, 255, 136, 0.4),
|
||||
0 5px 5px rgba(0, 255, 136, 0.4),
|
||||
5px 5px 5px rgba(0, 255, 136, 0.4);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
@@ -0,0 +1,4 @@
|
||||
import { createConfig } from '../../vite.base.config.js'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default createConfig([vue()])
|
||||
Reference in New Issue
Block a user