diff --git a/index.html b/index.html
index 46fb4a2..7fa18d1 100644
--- a/index.html
+++ b/index.html
@@ -7,7 +7,7 @@
兜爸心选 · 孕育陪伴
-
+
diff --git a/js/app.js b/js/app.js
index 9a874f9..b765ab7 100644
--- a/js/app.js
+++ b/js/app.js
@@ -3,7 +3,7 @@
(function () {
'use strict';
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
- var VER = '26100176';
+ var VER = '26100177';
const $ = (s, c) => (c || document).querySelector(s);
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
@@ -3349,6 +3349,8 @@
· 底部内容卡同时出现:整句 + 孕周 + 抱抱 + 「下一颗」。流星在卡片下面穿过,不挡字。 */
const RM = !!(window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches);
const AURA = [['#6B4AA8', '#C2667A'], ['#3F4FA6', '#8E5BB0'], ['#9A4F86', '#E0907A'], ['#365C9E', '#7A58AE'], ['#7D3F8C', '#D27A9A']];
+ /* 五声音阶 C4 D4 E4 G4 A4 C5 …(18 个音,C4 到 E7,一屏亮星一颗一个) */
+ const PENTA = Array.from({ length: 18 }, (_, k) => 440 * Math.pow(2, (60 + [0, 2, 4, 7, 9][k % 5] + 12 * Math.floor(k / 5) - 69) / 12));
const hsh = s => { let h = 7; for (const c of String(s)) h = (h * 31 + c.charCodeAt(0)) >>> 0; return h; };
const card = $('#wsc');
const seen = new Set();
@@ -3371,13 +3373,19 @@
function paintSky(l) {
const n = l.length, cols = n > 16 ? 5 : 4, rows = Math.max(2, Math.ceil(n / cols));
const fresh = l.findIndex(x => !x.mine && !seen.has(x.id));
+ const xs = l.map((it, i) => 36 + ((i % cols + .5 + ((hsh(it.id) % 100) / 100 - .5) * .7) / cols) * 58);
+ /* 十三改(用户:「每点一下都是一个音符,每一个星星代表不同的音符」):
+ 按横向位置从左到右排成一架竖琴——越靠左越低、越靠右越高,五声音阶(C4 起),连着点就是一段旋律 */
+ const rank = xs.map((x, i) => i).sort((p, q) => xs[p] - xs[q]);
+ const note = [];
+ rank.forEach((i, k) => { note[i] = PENTA[k % PENTA.length]; });
$('#wskBright').innerHTML = l.map((it, i) => {
- const h = hsh(it.id), c = i % cols, r = Math.floor(i / cols);
- const x = 36 + ((c + .5 + ((h % 100) / 100 - .5) * .7) / cols) * 58;
+ const h = hsh(it.id), r = Math.floor(i / cols);
+ const x = xs[i];
const y = 21 + ((r + .5 + (((h >> 8) % 100) / 100 - .5) * .6) / rows) * 38;
const sz = it.mine ? 26 : Math.round(15 + Math.min(it.hugs || 0, 30) / 30 * 11);
return '';
+ '" data-go="' + (i + 1) + '" data-note="' + note[i].toFixed(1) + '" style="left:' + x.toFixed(1) + '%;top:' + y.toFixed(1) + '%;--s:' + sz + 'px;--tw:' + (2 + (h % 30) / 10).toFixed(1) + 's" aria-label="' + esc(it.text) + '">';
}).join('');
}
function paintList(l) {
@@ -3442,11 +3450,11 @@
} catch (e) { return null; }
return actx;
}
- const NOTES = [1046.5, 1174.7, 1318.5, 1568, 1760, 2093];
- function chime() {
+ function chime(f) {
const c = ac();
if (!c) return;
- const t = c.currentTime, f = NOTES[Math.floor(Math.random() * NOTES.length)];
+ const t = c.currentTime;
+ f = f || PENTA[5 + Math.floor(Math.random() * 6)];
const g = c.createGain();
g.gain.setValueAtTime(0, t);
g.gain.linearRampToValueAtTime(.16, t + .012);
@@ -3502,10 +3510,11 @@
seen.clear();
$('#wskDone').classList.remove('show');
paintSky(list());
+ /* 星星回来:从低到高刷一遍琴弦 */
+ PENTA.slice(0, 8).forEach((f, k) => setTimeout(() => chime(f), k * 70));
$('#wskBright').classList.remove('back');
void $('#wskBright').offsetWidth;
$('#wskBright').classList.add('back');
- chime();
});
const stopAll = () => [...mts.values()].forEach(m => stopMeteor(m));
/* 第一次进来:一闪一闪的提示,点过一次星星就永久收起 */
@@ -3555,7 +3564,7 @@
btn.classList.add('flare');
btn.classList.remove('used');
$('#wskDone').classList.remove('show');
- chime();
+ chime(+btn.dataset.note);
tapFx(x0, y0, it.mine);
let swish = false, dustT = 0;
const t0 = performance.now();