悄悄话流星六改:头窄尾宽光楔、字由小到大、亮头、起步更快后段加速 (v26100170)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<title>兜爸心选 · 孕育陪伴</title>
|
<title>兜爸心选 · 孕育陪伴</title>
|
||||||
<!-- V:26100169 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
<!-- V:26100170 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||||
<link rel="stylesheet" href="mama-box.css">
|
<link rel="stylesheet" href="mama-box.css">
|
||||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||||
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
|
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
|
||||||
|
|||||||
52
js/app.js
52
js/app.js
@@ -3,7 +3,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||||
var VER = '26100169';
|
var VER = '26100170';
|
||||||
const $ = (s, c) => (c || document).querySelector(s);
|
const $ = (s, c) => (c || document).querySelector(s);
|
||||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||||
|
|
||||||
@@ -3370,7 +3370,7 @@
|
|||||||
const fresh = l.findIndex(x => !x.mine && !seen.has(x.id));
|
const fresh = l.findIndex(x => !x.mine && !seen.has(x.id));
|
||||||
$('#wskBright').innerHTML = l.map((it, i) => {
|
$('#wskBright').innerHTML = l.map((it, i) => {
|
||||||
const h = hsh(it.id), c = i % cols, r = Math.floor(i / cols);
|
const h = hsh(it.id), c = i % cols, r = Math.floor(i / cols);
|
||||||
const x = 24 + ((c + .5 + ((h % 100) / 100 - .5) * .7) / cols) * 70;
|
const x = 36 + ((c + .5 + ((h % 100) / 100 - .5) * .7) / cols) * 58;
|
||||||
const y = 21 + ((r + .5 + (((h >> 8) % 100) / 100 - .5) * .6) / rows) * 38;
|
const y = 21 + ((r + .5 + (((h >> 8) % 100) / 100 - .5) * .6) / rows) * 38;
|
||||||
const sz = it.mine ? 9 : Math.round(4 + Math.min(it.hugs || 0, 30) / 30 * 6);
|
const sz = it.mine ? 9 : Math.round(4 + Math.min(it.hugs || 0, 30) / 30 * 6);
|
||||||
return '<button type="button" class="wsk-st' + (it.mine ? ' mine' : '') + (seen.has(it.id) ? ' seen' : '') + (i === fresh && !seen.size ? ' hint' : '') +
|
return '<button type="button" class="wsk-st' + (it.mine ? ' mine' : '') + (seen.has(it.id) ? ' seen' : '') + (i === fresh && !seen.size ? ' hint' : '') +
|
||||||
@@ -3421,37 +3421,47 @@
|
|||||||
const pr = page.getBoundingClientRect(), br = btn.getBoundingClientRect();
|
const pr = page.getBoundingClientRect(), br = btn.getBoundingClientRect();
|
||||||
const x0 = br.left + br.width / 2 - pr.left, y0 = br.top + br.height / 2 - pr.top;
|
const x0 = br.left + br.width / 2 - pr.left, y0 = br.top + br.height / 2 - pr.top;
|
||||||
/* 瞄准左下(屏幕左边外、六成高处):越靠左起步角度越陡,保证在屏幕里拖得够长 */
|
/* 瞄准左下(屏幕左边外、六成高处):越靠左起步角度越陡,保证在屏幕里拖得够长 */
|
||||||
const th = Math.max(22, Math.min(50, Math.atan2(pr.height * .62 - y0, x0 + 30) * 180 / Math.PI)) * Math.PI / 180, dx = -Math.cos(th), dy = Math.sin(th), rot = -th * 180 / Math.PI;
|
const th = Math.max(24, Math.min(55, Math.atan2(pr.height * .8 - y0, x0 + 30) * 180 / Math.PI)) * Math.PI / 180, dx = -Math.cos(th), dy = Math.sin(th), rot = -th * 180 / Math.PI;
|
||||||
|
/* 六改(用户:「头是窄的,往后越来越宽;前面的字小,后面慢慢变大,形成流星尾巴;头特别亮往前滑;
|
||||||
|
点完亮一下就开始滑,一点点变快,不要太慢也别太快」):
|
||||||
|
字号从头到尾 12px → 26px 渐大,尾巴是一条从头部尖起、往后张开的光楔;
|
||||||
|
运动 = 起步就有速度、缓缓提速,整句出来后再猛加速唰出去。 */
|
||||||
const chars = [...String(it.text)], n = chars.length;
|
const chars = [...String(it.text)], n = chars.length;
|
||||||
const cw = n > 16 ? 21 : 25, gap = 20, body = gap + n * cw;
|
const f0 = 12, f1 = n > 20 ? 21 : n > 12 ? 24 : 27, gap = 22;
|
||||||
|
const fs = chars.map((c, k) => f0 + (f1 - f0) * Math.pow(n > 1 ? k / (n - 1) : 1, .85));
|
||||||
|
const off = [];
|
||||||
|
fs.reduce((d, f) => { off.push(d + f * .55); return d + f * 1.08; }, gap);
|
||||||
|
const body = off.length ? off[n - 1] + fs[n - 1] * .6 : gap;
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'wmt' + (it.mine ? ' mine' : '');
|
el.className = 'wmt' + (it.mine ? ' mine' : '');
|
||||||
el.style.setProperty('--fs', (cw - 4) + 'px');
|
el.innerHTML = '<i class="wmt-l"></i><i class="wmt-c"></i><i class="wmt-h"></i>' + chars.map((c, k) => '<span style="font-size:' + fs[k].toFixed(1) + 'px">' + esc(c) + '</span>').join('');
|
||||||
el.innerHTML = '<i class="wmt-l"></i><i class="wmt-h"></i>' + chars.map(c => '<span>' + esc(c) + '</span>').join('');
|
|
||||||
page.insertBefore(el, card);
|
page.insertBefore(el, card);
|
||||||
const line = el.children[0], head = el.children[1], sp = $$('span', el);
|
const line = el.children[0], core = el.children[1], head = el.children[2], sp = $$('span', el);
|
||||||
/* 节奏:星闪 380ms → 慢飘(按字数给阅读时间,起步再缓一点)→ 750ms 加速唰出去 */
|
line.style.height = (f1 * 1.9).toFixed(0) + 'px';
|
||||||
const T0 = 380, T1 = Math.min(11000, 2400 + n * 300), T2 = 800, L1 = body + 60, v1 = L1 / (.94 * T1);
|
line.style.marginTop = (-f1 * .95).toFixed(0) + 'px';
|
||||||
|
/* 节奏:星闪 420ms → 以约 90px/s 起步并缓缓提速,整句拖出来后再留 0.7 秒给眼睛 → 加速度猛增,1.3 秒内唰出屏幕 */
|
||||||
|
const T0 = 420, v0 = .09, TR = (body + 20) / v0 + 700, A = .0018, TE = 1300;
|
||||||
btn.classList.add('flare');
|
btn.classList.add('flare');
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
const frame = now => {
|
const frame = now => {
|
||||||
const t = now - t0;
|
const t = now - t0;
|
||||||
if (t < T0) { mt.raf = requestAnimationFrame(frame); return; }
|
if (t < T0) { mt.raf = requestAnimationFrame(frame); return; }
|
||||||
btn.classList.add('gone');
|
btn.classList.add('gone');
|
||||||
const t1 = t - T0;
|
const tc = t - T0, dt = Math.max(0, tc - TR), u = Math.min(1, dt / TE);
|
||||||
let s, u = 0;
|
const s = v0 * tc + v0 * tc * tc / 16000 + .5 * A * dt * dt;
|
||||||
if (t1 < T1) { const p = t1 / T1; s = L1 * (p < .12 ? p * p / .24 : p - .06) / .94; }
|
const v = v0 * (1 + tc / 8000) + A * dt;
|
||||||
else { u = Math.min(1, (t1 - T1) / T2); s = L1 + v1 * T2 * u + 1600 * Math.pow(u, 2.6); }
|
const hx = x0 + dx * s, hy = y0 + dy * s, at = 'translate(' + hx.toFixed(1) + 'px,' + hy.toFixed(1) + 'px) rotate(' + rot.toFixed(1) + 'deg)';
|
||||||
const hx = x0 + dx * s, hy = y0 + dy * s;
|
const st = Math.min(1.6, Math.max(0, (v - .25) / .5));
|
||||||
head.style.transform = 'translate(' + hx.toFixed(1) + 'px,' + hy.toFixed(1) + 'px) rotate(' + rot.toFixed(1) + 'deg) scaleX(' + (1 + u * 5).toFixed(2) + ')';
|
head.style.transform = at + ' scaleX(' + (1 + st * 1.6).toFixed(2) + ')';
|
||||||
line.style.width = Math.min(s, body + 50 + 700 * u * u).toFixed(0) + 'px';
|
const tl = Math.min(s, body + 70 + 260 * st);
|
||||||
line.style.transform = 'translate(' + hx.toFixed(1) + 'px,' + hy.toFixed(1) + 'px) rotate(' + rot.toFixed(1) + 'deg)';
|
line.style.width = core.style.width = tl.toFixed(0) + 'px';
|
||||||
const fade = Math.max(0, 1 - u * 1.25);
|
line.style.transform = core.style.transform = at;
|
||||||
el.style.setProperty('--bl', (u * 5).toFixed(1) + 'px');
|
const fade = u < .6 ? 1 : Math.max(0, 1 - (u - .6) / .4);
|
||||||
|
el.style.setProperty('--bl', (st * 1.6).toFixed(1) + 'px');
|
||||||
sp.forEach((c, k) => {
|
sp.forEach((c, k) => {
|
||||||
const d = s - gap - k * cw;
|
const d = s - off[k];
|
||||||
if (d < 0) { c.style.opacity = 0; return; }
|
if (d < 0) { c.style.opacity = 0; return; }
|
||||||
c.style.opacity = (Math.min(1, d / 22) * fade).toFixed(2);
|
c.style.opacity = (Math.min(1, d / 26) * fade).toFixed(2);
|
||||||
c.style.transform = 'translate(' + (x0 + dx * d).toFixed(1) + 'px,' + (y0 + dy * d).toFixed(1) + 'px) translate(-50%,-50%) rotate(' + rot.toFixed(1) + 'deg)';
|
c.style.transform = 'translate(' + (x0 + dx * d).toFixed(1) + 'px,' + (y0 + dy * d).toFixed(1) + 'px) translate(-50%,-50%) rotate(' + rot.toFixed(1) + 'deg)';
|
||||||
});
|
});
|
||||||
if (u >= 1) { stopMeteor(); return; }
|
if (u >= 1) { stopMeteor(); return; }
|
||||||
|
|||||||
16
mama-box.css
16
mama-box.css
@@ -3922,3 +3922,19 @@ a.skip:focus{left:16px;top:16px}
|
|||||||
@media (prefers-reduced-motion:reduce){
|
@media (prefers-reduced-motion:reduce){
|
||||||
.wsk-deco i,.wsk-st i,.wsk-shoot{animation:none}
|
.wsk-deco i,.wsk-st i,.wsk-shoot{animation:none}
|
||||||
}
|
}
|
||||||
|
/* 六改:头窄尾宽的光楔 + 特别亮的头 */
|
||||||
|
.wmt-l,.wmt-c{position:absolute;left:0;top:0;transform-origin:0 50%;border-radius:0;will-change:transform,width}
|
||||||
|
.wmt-l{clip-path:polygon(0 50%,100% 0,100% 100%);filter:blur(5px);
|
||||||
|
background:linear-gradient(90deg,rgba(255,255,255,.75),rgba(220,200,255,.38) 30%,rgba(255,180,200,.16) 70%,transparent)}
|
||||||
|
.wmt-c{height:6px;margin-top:-3px;clip-path:polygon(0 50%,100% 0,100% 100%);filter:blur(1px);
|
||||||
|
background:linear-gradient(90deg,#fff,rgba(255,255,255,.55) 35%,transparent)}
|
||||||
|
.wmt-h{width:16px;height:16px;margin:-8px 0 0 -8px;background:radial-gradient(circle,#fff 45%,rgba(255,255,255,.85) 60%,rgba(255,255,255,0) 72%);
|
||||||
|
box-shadow:0 0 12px 6px #fff,0 0 34px 16px rgba(230,215,255,.85),0 0 80px 30px rgba(255,190,210,.45)}
|
||||||
|
.wmt-h::before,.wmt-h::after{content:"";position:absolute;left:50%;top:50%;width:70px;height:2px;margin:-1px 0 0 -35px;border-radius:2px;
|
||||||
|
background:linear-gradient(90deg,transparent,#fff,transparent)}
|
||||||
|
.wmt-h::after{transform:rotate(90deg);width:40px;margin-left:-20px}
|
||||||
|
.wmt span{font-weight:900}
|
||||||
|
.wmt.mine .wmt-l{background:linear-gradient(90deg,rgba(255,240,210,.8),rgba(255,200,130,.4) 30%,rgba(255,150,90,.16) 70%,transparent)}
|
||||||
|
.wsk-st.flare i{animation:wskFlare2 .42s ease-out forwards}
|
||||||
|
@keyframes wskFlare2{0%{transform:scale(1)}55%{transform:scale(3.4);box-shadow:0 0 26px 14px #fff,0 0 60px 24px rgba(230,210,255,.7)}100%{transform:scale(2);box-shadow:0 0 20px 10px #fff}}
|
||||||
|
.wsk-st.gone{opacity:0;transition:opacity .5s}
|
||||||
|
|||||||
Reference in New Issue
Block a user