Skip to content

Commit 25c67bf

Browse files
authored
Add files via upload
1 parent f23ce21 commit 25c67bf

1 file changed

Lines changed: 153 additions & 46 deletions

File tree

index.html

Lines changed: 153 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -102,32 +102,35 @@
102102
transition: opacity 0.8s ease;
103103
}
104104

105-
/* ---- 遮罩(含音量控制) ---- */
105+
/* ---- 遮罩(含灵感来源和音量控制) ---- */
106106
#overlay {
107107
position: absolute;
108108
inset: 0;
109109
z-index: 20;
110110
display: flex;
111111
flex-direction: column;
112-
gap: 20px;
112+
gap: 14px;
113113
align-items: center;
114114
justify-content: center;
115-
background: rgba(79, 56, 38, 0.85);
115+
background: rgba(79, 56, 38, 0.88);
116116
backdrop-filter: blur(4px);
117-
cursor: pointer;
118-
transition: opacity 0.6s ease;
119-
padding: 0 20px;
120-
}
121-
#overlay.hide {
122-
opacity: 0;
123-
pointer-events: none;
117+
padding: 20px;
118+
cursor: default;
119+
transition: opacity 0.5s ease;
124120
}
125121
#overlay .big {
126122
font-size: clamp(42px, 10vw, 82px);
127123
font-weight: 900;
128124
letter-spacing: 0.2em;
129125
color: rgba(255, 220, 180, 0.85);
130126
text-shadow: 0 6px 30px rgba(0, 0, 0, 0.5);
127+
cursor: pointer;
128+
padding: 8px 20px;
129+
border-radius: 12px;
130+
transition: background 0.2s;
131+
}
132+
#overlay .big:hover {
133+
background: rgba(255, 200, 150, 0.06);
131134
}
132135
#overlay .big em {
133136
font-style: normal;
@@ -138,7 +141,8 @@
138141
letter-spacing: 0.4em;
139142
color: rgba(255, 200, 150, 0.4);
140143
animation: pulseHint 1.8s ease-in-out infinite;
141-
margin-top: -4px;
144+
margin-top: -6px;
145+
cursor: pointer;
142146
}
143147
@keyframes pulseHint {
144148
0%,
@@ -150,6 +154,30 @@
150154
}
151155
}
152156

157+
/* 灵感来源链接 */
158+
.inspire-links {
159+
display: flex;
160+
gap: 18px;
161+
margin: 4px 0 6px;
162+
flex-wrap: wrap;
163+
justify-content: center;
164+
}
165+
.inspire-links a {
166+
color: rgba(255, 200, 150, 0.5);
167+
font-size: 13px;
168+
letter-spacing: 0.06em;
169+
text-decoration: none;
170+
border-bottom: 1px solid rgba(255, 200, 150, 0.15);
171+
padding-bottom: 2px;
172+
transition: color 0.25s, border-color 0.25s;
173+
cursor: pointer;
174+
pointer-events: auto;
175+
}
176+
.inspire-links a:hover {
177+
color: rgba(255, 220, 180, 0.85);
178+
border-color: rgba(255, 200, 150, 0.4);
179+
}
180+
153181
/* 音量控制 */
154182
.volume-control {
155183
display: flex;
@@ -225,10 +253,48 @@
225253
text-align: center;
226254
}
227255

228-
/* 阻止滑块事件冒泡到遮罩 */
229-
.volume-control * {
256+
/* 底部按钮 */
257+
#bottom-links {
258+
position: absolute;
259+
bottom: max(14px, env(safe-area-inset-bottom));
260+
left: 50%;
261+
transform: translateX(-50%);
262+
z-index: 8;
263+
display: flex;
264+
gap: 14px;
265+
align-items: center;
266+
background: rgba(0, 0, 0, 0.25);
267+
padding: 6px 14px;
268+
border-radius: 30px;
269+
backdrop-filter: blur(4px);
270+
border: 1px solid rgba(255, 200, 150, 0.08);
271+
transition: opacity 0.4s ease;
272+
}
273+
#bottom-links a {
274+
display: flex;
275+
align-items: center;
276+
justify-content: center;
277+
width: 28px;
278+
height: 28px;
279+
color: rgba(255, 210, 160, 0.5);
280+
transition: color 0.25s, transform 0.2s;
281+
cursor: pointer;
230282
pointer-events: auto;
231283
}
284+
#bottom-links a:hover {
285+
color: rgba(255, 220, 180, 0.85);
286+
transform: scale(1.12);
287+
}
288+
#bottom-links svg {
289+
width: 22px;
290+
height: 22px;
291+
fill: currentColor;
292+
stroke: none;
293+
}
294+
/* 确保链接可点击 */
295+
#bottom-links a * {
296+
pointer-events: none;
297+
}
232298

233299
/* ---- 响应式 ---- */
234300
@media (max-width: 480px) {
@@ -249,6 +315,29 @@
249315
font-size: 11px;
250316
min-width: 26px;
251317
}
318+
.inspire-links a {
319+
font-size: 11px;
320+
}
321+
#bottom-links {
322+
padding: 4px 10px;
323+
gap: 10px;
324+
}
325+
#bottom-links a {
326+
width: 24px;
327+
height: 24px;
328+
}
329+
#bottom-links svg {
330+
width: 18px;
331+
height: 18px;
332+
}
333+
}
334+
@media (max-height: 600px) {
335+
.inspire-links {
336+
gap: 12px;
337+
}
338+
.volume-control {
339+
padding: 6px 12px;
340+
}
252341
}
253342
</style>
254343
</head>
@@ -262,23 +351,39 @@
262351
<div id="title">拉伸<span>Tap</span></div>
263352
<div id="hint">点击 · 滑动 · 升调</div>
264353

354+
<!-- 遮罩 -->
265355
<div id="overlay">
266-
<div class="big">拉伸<em>Tap</em></div>
267-
<div class="sub">点 击 任 意 位 置 开 始</div>
356+
<div class="big" id="start-trigger">拉伸<em>Tap</em></div>
357+
<div class="sub" id="start-trigger-sub">点 击 任 意 位 置 开 始</div>
358+
359+
<div class="inspire-links">
360+
<a href="https://aidn.jp/mikutap/" target="_blank" rel="noopener noreferrer">Mikutap</a>
361+
<a href="https://www.bilibili.com/toy/Dagou-Tap/index.html" target="_blank" rel="noopener noreferrer">大狗Tap</a>
362+
</div>
363+
268364
<div class="volume-control" id="volume-control">
269365
<label for="bgm-volume">背景音量</label>
270366
<input type="range" id="bgm-volume" min="0" max="1" step="0.01" value="0.25" />
271367
<span class="vol-value" id="vol-value">25%</span>
272368
</div>
273369
</div>
370+
371+
<!-- 底部链接 -->
372+
<div id="bottom-links">
373+
<a href="https://github.com/CraftSoul/soviettap/" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
374+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.468-2.38 1.235-3.22-.123-.3-.535-1.52.117-3.16 0 0 1.008-.322 3.3 1.23.96-.267 1.98-.399 3-.399s2.04.132 3 .399c2.292-1.552 3.3-1.23 3.3-1.23.653 1.64.24 2.86.118 3.16.768.84 1.233 1.91 1.233 3.22 0 4.61-2.804 5.62-5.476 5.92.43.37.824 1.102.824 2.22 0 1.602-.015 2.894-.015 3.287 0 .322.216.694.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
375+
</a>
376+
<a href="https://space.bilibili.com/3546775476505152" target="_blank" rel="noopener noreferrer" aria-label="Bilibili">
377+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17.813 4.653h.854l1.338 1.259c.477.447.713.944.713 1.491v8.557c0 .547-.236 1.044-.713 1.491l-1.338 1.259h-.854l1.371-1.259c.35-.33.525-.718.525-1.163V7.403c0-.445-.175-.833-.525-1.163l-1.371-1.587zm-9.792 0l-1.37 1.587c-.35.33-.526.718-.526 1.163v8.557c0 .445.176.833.526 1.163l1.37 1.259h.854L7.47 16.457c-.477-.447-.713-.944-.713-1.491V7.403c0-.547.236-1.044.713-1.491l1.338-1.259h-.854zM3.492 1.955c-.822 0-1.491.668-1.491 1.491v17.108c0 .823.669 1.491 1.491 1.491h17.016c.823 0 1.491-.668 1.491-1.491V3.446c0-.823-.668-1.491-1.491-1.491H3.492z"/></svg>
378+
</a>
379+
</div>
274380
</div>
275381

276382
<script>
277383
/* ============================================================
278384
* 拉伸Tap —— 四列音效 (sl.wav, boom.wav, sla.wav, a.wav)
279-
* 自下至上升调 · 仿大狗Tap特效 + 背景音乐
280-
* 隐藏网格 · 背景音量可调(默认1/4)
281-
* 触发后等待节拍播放(量化队列)
385+
* 音调反向(上高下低)· 点击修复 · 灵感来源 · 底部链接
386+
* 遮罩彻底移除 · 触发后量化播放
282387
* ============================================================ */
283388

284389
// ---------- 常量 ----------
@@ -306,7 +411,7 @@
306411
let nextNoteTime = 0;
307412
let stepCount = 0;
308413

309-
let bgmVolume = 0.25; // 默认1/4
414+
let bgmVolume = 0.25;
310415

311416
const buffers = {};
312417
let loadedCount = 0;
@@ -374,11 +479,6 @@
374479

375480
function nowSec() { return ctx ? ctx.currentTime : performance.now() / 1000; }
376481

377-
function getStageMetrics() {
378-
const rect = document.getElementById('stage').getBoundingClientRect();
379-
return { width: rect.width, height: rect.height, left: rect.left, top: rect.top };
380-
}
381-
382482
// ---------- 音频初始化 ----------
383483
function initAudio() {
384484
ctx = new(window.AudioContext || window.webkitAudioContext)();
@@ -592,11 +692,12 @@
592692
return t;
593693
}
594694

595-
// ---------- 播放音效 ----------
695+
// ---------- 播放音效(音调反向:上高下低) ----------
596696
function playSample(sampleName, pitchTier, when) {
597697
const buffer = buffers[sampleName];
598698
if (!buffer) return;
599-
const rate = 0.6 + (pitchTier / (ROWS - 1)) * 1.4;
699+
// 反向:pitchTier=0 → 最高音 (2.0), pitchTier=7 → 最低音 (0.6)
700+
const rate = 0.6 + ((ROWS - 1 - pitchTier) / (ROWS - 1)) * 1.4;
600701
const source = ctx.createBufferSource();
601702
source.buffer = buffer;
602703
source.playbackRate.setValueAtTime(rate, when);
@@ -646,11 +747,9 @@
646747
}
647748
}
648749

750+
// 不再取消队列(点击修复)
649751
function cancelQueuedInputs(pointerId) {
650-
for (let i = inputQueue.length - 1; i >= 0; i--) {
651-
if (inputQueue[i].pointerId === pointerId) inputQueue.splice(i, 1);
652-
}
653-
reflowQueuedInputTimes();
752+
// 保留队列,不取消任何条目(点击修复)
654753
}
655754

656755
// ---------- 网格交互 ----------
@@ -1331,23 +1430,21 @@
13311430

13321431
stage.addEventListener('pointerup', (e) => {
13331432
const state = pointers.get(e.pointerId);
1334-
if (state) cancelQueuedInputs(e.pointerId);
1433+
// 不取消队列,只清除状态
13351434
pointers.delete(e.pointerId);
13361435
try { stage.releasePointerCapture(e.pointerId); } catch (_) {}
13371436
});
13381437

13391438
stage.addEventListener('pointercancel', (e) => {
13401439
const state = pointers.get(e.pointerId);
1341-
if (state) cancelQueuedInputs(e.pointerId);
13421440
pointers.delete(e.pointerId);
13431441
try { stage.releasePointerCapture(e.pointerId); } catch (_) {}
13441442
});
13451443

13461444
stage.addEventListener('contextmenu', (e) => e.preventDefault());
13471445

13481446
window.addEventListener('blur', () => {
1349-
inputQueue.length = 0;
1350-
pointers.clear();
1447+
// 不清除队列,防止丢失
13511448
});
13521449
}
13531450

@@ -1366,7 +1463,7 @@
13661463
}
13671464
});
13681465

1369-
// 阻止滑块事件冒泡到遮罩,避免误触发启动
1466+
// 阻止滑块事件冒泡到遮罩
13701467
control.addEventListener('pointerdown', (e) => e.stopPropagation());
13711468
control.addEventListener('pointerup', (e) => e.stopPropagation());
13721469
control.addEventListener('click', (e) => e.stopPropagation());
@@ -1376,19 +1473,20 @@
13761473
function start() {
13771474
if (started) return;
13781475
const overlay = document.getElementById('overlay');
1379-
overlay.classList.add('hide');
1380-
document.getElementById('hint').style.opacity = '0';
1476+
if (overlay) {
1477+
// 彻底移除遮罩
1478+
overlay.remove();
1479+
}
13811480

1382-
// 禁用音量控件
1481+
// 禁用音量控件(已经移除,但以防万一)
13831482
const slider = document.getElementById('bgm-volume');
1483+
if (slider) slider.disabled = true;
13841484
const control = document.getElementById('volume-control');
1385-
slider.disabled = true;
1386-
control.classList.add('disabled');
1485+
if (control) control.classList.add('disabled');
13871486

13881487
initAudio();
13891488
if (ctx.state === 'suspended') ctx.resume();
13901489

1391-
// 应用当前音量设置
13921490
if (bgmBus) {
13931491
bgmBus.gain.value = bgmVolume;
13941492
}
@@ -1401,7 +1499,6 @@
14011499
stepCount = 0;
14021500
started = true;
14031501
console.log('启动完成');
1404-
// 触发一次初始特效(不播放音效)
14051502
spawnEffect(0, 3, ctx.currentTime + 0.05);
14061503
}).catch(err => {
14071504
console.warn('加载音效失败,仍可使用合成', err);
@@ -1420,18 +1517,27 @@
14201517
setupEvents();
14211518
setupVolumeSlider();
14221519

1423-
// 点击遮罩只启动,不触发播放
1520+
// 遮罩点击触发启动,但排除链接和音量控件
14241521
const overlay = document.getElementById('overlay');
1522+
// 使用事件代理,但链接会冒泡,所以需要阻止
14251523
overlay.addEventListener('click', (e) => {
1426-
if (e.target.closest('.volume-control')) return;
1524+
const target = e.target;
1525+
if (target.closest('a') || target.closest('.volume-control')) return;
14271526
start();
14281527
});
14291528
overlay.addEventListener('touchstart', (e) => {
1430-
if (e.target.closest('.volume-control')) return;
1529+
const target = e.target;
1530+
if (target.closest('a') || target.closest('.volume-control')) return;
14311531
e.preventDefault();
14321532
start();
14331533
}, { passive: false });
14341534

1535+
// 链接点击不触发启动,且阻止冒泡
1536+
overlay.querySelectorAll('a').forEach(link => {
1537+
link.addEventListener('click', (e) => e.stopPropagation());
1538+
link.addEventListener('touchstart', (e) => e.stopPropagation());
1539+
});
1540+
14351541
window.addEventListener('resize', resizeFx);
14361542
requestAnimationFrame(tick);
14371543

@@ -1440,7 +1546,7 @@
14401546
if (!ctx) initAudio();
14411547
}, { once: true });
14421548

1443-
console.log('拉伸Tap 已加载 (网格隐藏,背景音量可调,触发后量化播放)');
1549+
console.log('拉伸Tap 已加载 (音调反向,点击修复,遮罩移除)');
14441550
}
14451551

14461552
if (document.readyState === 'loading') {
@@ -1449,5 +1555,6 @@
14491555
init();
14501556
}
14511557
</script>
1558+
14521559
</body>
14531560
</html>

0 commit comments

Comments
 (0)