dsh-boot-suite 2.15.16 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/lib/client.js +4 -4
- package/package.json +1 -1
- package/templates/division-bigfish-codex/app.js +165 -30
- package/templates/division-bigfish-codex/assets/voice-login.wav +0 -0
- package/templates/division-bigfish-codex/config.js +10 -7
- package/templates/division-bigfish-codex/index.html +14 -1
- package/templates/division-bigfish-codex/render.html +14 -1
- package/templates/division-bigfish-codex/style.css +27 -0
- package/templates/division-bigfish-codex/template.json +10 -10
- package/test/smoke-package.mjs +33 -2
- package/test/smoke-wallpaper-client.mjs +1 -1
- package/tools/build-release.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [2.16.0] — 2026-11-02
|
|
2
|
+
|
|
3
|
+
- **全景大肥鱼新增第二节登录 ID 动画**:第一节(登录 ID 段)延长到约 5.8s、只保留「检测到新的特工登录」;第二节 5s 登录动画,「WELCOME TO DEEPSEEK HARNESS」乱码→逐字、橙色扫描线从上往下、「正在登录:自定义用户名」按贝塞尔曲线平滑居中、用户名破解式逐字出现(最多 20 字符,过滤系统冲突符号)。
|
|
4
|
+
- **登录段新增第二段配音**:`Agent ID confirmed.` / 中文「特工身份确认。」,并复用「图标 + DSH + 波形 + 中文」整行;登录段内其它语音按新时间轴后移,第三节 0–100 保持不变。
|
|
5
|
+
- **配音串行播放(修叠音)**:第三节是 1.5x 加速段,音频按真实时长播放,上一句没播完不再启动下一句(此前 line1 尾巴会和 line2 重叠约 0.8s);重连后的 line2/line3/orig3 同样串行。
|
|
6
|
+
- **彩蛋尾部等待(修截断)**:动画临近结束时触发掉线彩蛋,会等当前配音(含 orig3 最后一句)播完再弹出,动画收尾也会等彩蛋语音播完,不再硬切。
|
|
7
|
+
- 总时长 33.4s(原 30.92s,给最后一句留足播完时间),登录框整体缩到原 1/3;模板名仍为「全景大肥鱼-含彩蛋版」。
|
|
8
|
+
- 版本号 2.16.0,构建号 cw-66。
|
|
9
|
+
|
|
10
|
+
## [2.15.17] — 2026-11-02
|
|
11
|
+
|
|
12
|
+
- **字幕不再提前消失**:每句配音的中文台词与波形改为跟随该句音频的真实播放时钟(Audio 元素的 currentTime / ended),不再按动画时间轴推算;即使主线程卡顿导致音频晚开始,字幕也会和语音同时出现、同时结束。
|
|
13
|
+
- **掉线彩蛋字幕同步**:彩蛋里「警告:特工已离线。」同样跟随 voice-line4 的播放时钟,不会在语音结束前消失。
|
|
14
|
+
- 版本号 2.15.17,构建号 cw-65。
|
|
15
|
+
|
|
1
16
|
## [2.15.16] — 2026-11-02
|
|
2
17
|
|
|
3
18
|
- **掉线彩蛋不再硬切配音**:如果掉线正好触发在某句配音播放期间,先等这句播完(含中文字幕)再弹出彩蛋,不会出现「语音没说完、字幕先消失」;有 0.9s 兜底超时与动画结束保护。
|
package/lib/client.js
CHANGED
|
@@ -269,7 +269,7 @@ window.__ModuleLoader__.load({
|
|
|
269
269
|
—— 桌面端走浏览器半侧自举时没有 1,就靠这一条
|
|
270
270
|
3) 下面这个常量:两份都没拿到时的兜底,别让面板显示 undefined
|
|
271
271
|
版本号本身只在 lib/index.js 里读一次,这里不重复维护。 */
|
|
272
|
-
var FALLBACK_VERSION = '2.
|
|
272
|
+
var FALLBACK_VERSION = '2.16.0'
|
|
273
273
|
/* 手动选包成功后置 true:让还在后台跑的“浏览器下载监听”不要再弹第二次更新器 */
|
|
274
274
|
var __manualUpdateApplied = false
|
|
275
275
|
function readInjectedVersion() {
|
|
@@ -1253,8 +1253,8 @@ window.__ModuleLoader__.load({
|
|
|
1253
1253
|
? h('div', { className: '__ss_group' },
|
|
1254
1254
|
h('div', { className: '__ss_groupTitle' }, '全景大肥鱼-含彩蛋版 · 专属文案'),
|
|
1255
1255
|
h('div', { className: '__ss_hint' }, '只对第一幕「全景大肥鱼-含彩蛋版」生效;留空则用模板自带默认值。'),
|
|
1256
|
-
h(Field, { label: '连接用户名', hint: '
|
|
1257
|
-
h(TextInput, { value: draft.bigfishUsername || '', maxLength:
|
|
1256
|
+
h(Field, { label: '连接用户名', hint: '动画提示条和登录动画里的用户名;最多 20 个字符,\\ / : * ? " < > | 等特殊符号会被忽略。' },
|
|
1257
|
+
h(TextInput, { value: draft.bigfishUsername || '', maxLength: 20, onChange: (v) => set('bigfishUsername', Array.from(String(v || '').replace(/[\\/:*?"<>|]/g, '').replace(/\s+/g, ' ').trim()).slice(0, 20).join('')) })
|
|
1258
1258
|
),
|
|
1259
1259
|
h(Field, { label: '提示条标题' },
|
|
1260
1260
|
h(TextInput, { value: draft.bigfishTitle || '', maxLength: 60, onChange: (v) => set('bigfishTitle', v) })
|
|
@@ -2022,7 +2022,7 @@ window.__ModuleLoader__.load({
|
|
|
2022
2022
|
/* 每次改客户端就把这个号 +1。
|
|
2023
2023
|
有了它在控制台一眼就能判断"浏览器里跑的是不是最新那份" ——
|
|
2024
2024
|
排查问题时,分不清是代码问题还是旧包,会白猜一轮。 */
|
|
2025
|
-
var BUILD = 'cw-
|
|
2025
|
+
var BUILD = 'cw-66'
|
|
2026
2026
|
|
|
2027
2027
|
function log() {
|
|
2028
2028
|
try {
|
package/package.json
CHANGED
|
@@ -46,12 +46,145 @@ function renderVoiceRow(g,se,h,sub,visible){
|
|
|
46
46
|
g.style.opacity=visible;
|
|
47
47
|
if(se){if(se.textContent!==sub)se.textContent=sub||'';se.setAttribute('x',String(subX));se.setAttribute('y',String(baseY));se.setAttribute('text-anchor','start');se.setAttribute('dominant-baseline','central');se.setAttribute('font-size',String(subFs));se.style.opacity=(visible&&sub)?1:0}
|
|
48
48
|
}
|
|
49
|
+
var loginStart=+(cfg.loginStart!=null?cfg.loginStart:cfg.loadingStart),loginDur=Math.max(0,+(cfg.loginDur||0)),loginEnd=loginStart+loginDur;
|
|
50
|
+
function voiceVT(x){if(x<loginEnd)return Math.max(0,x-(+cfg.startAt||0));return 11.6+(x-cfg.loadingStart)/1.5}
|
|
51
|
+
/* ===== v2.16.0:登录 ID 动画(WELCOME TO DEEPSEEK HARNESS + 正在登录:用户名) ===== */
|
|
52
|
+
var LOGIN=(function(){
|
|
53
|
+
var el=$('login'),l1=$('login-line1'),l2=$('login-line2'),track=$('login-l2-track'),head=$('login-l2-head'),scanText=$('login-scan-text'),scanWrap=scanText?scanText.parentNode:null,scanBar=$('login-scan-bar'),colon=$('login-colon'),nameEl=$('login-name'),caret=$('login-caret'),meta=$('login-name-meta');
|
|
54
|
+
if(!el||!l1||!l2||!track||!head||!scanText||!nameEl)return null;
|
|
55
|
+
var L1='WELCOME TO DEEPSEEK HARNESS';
|
|
56
|
+
var POOL='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&@$*+-=/<>[]{}';
|
|
57
|
+
/* 5s 版:第一行 0.18~1.2s、扫描 1.28~1.73s、冒号 1.76~1.88s、用户名 1.94~4.34s、停留到 5s */
|
|
58
|
+
var L1_START=0.18,L1_SPAN=0.72,L1_FLICK=0.3;
|
|
59
|
+
var L2_START=1.28,L2_SCAN=0.45,COLON_AT=1.76,COLON_DUR=0.12,NAME_AT=1.94,NAME_DUR=2.4,SLIDE_DUR=0.62;
|
|
60
|
+
function mulberry32(a){return function(){a|=0;a=a+0x6D2B79F5|0;var t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
|
|
61
|
+
/* 用户名安全化:去掉控制符/双向控制符与 \ / : * ? " < > |,合并空白,最多 20 个字符(按码点计)。 */
|
|
62
|
+
function sanitize(raw){
|
|
63
|
+
var s=String(raw==null?'':raw).replace(/[\u0000-\u001F\u007F\u200B-\u200F\u2028-\u202E\uFEFF]/g,'').replace(/[\\/:*?"<>|]/g,'').replace(/\s+/g,' ').trim();
|
|
64
|
+
var cp=Array.from(s);if(cp.length>20)cp=cp.slice(0,20);
|
|
65
|
+
return cp.join('');
|
|
66
|
+
}
|
|
67
|
+
function esc(ch){return ch===' '?' ':ch.replace(/[&<>]/g,function(c){return {'&':'&','<':'<','>':'>'}[c]})}
|
|
68
|
+
var rnd=mulberry32(20261102),l1c=null,order=[],nameChars=[],nmc=null,settles=[],rates=[],builtName=null,HEAD_W=0,NAME_W=0,measuredKey='';
|
|
69
|
+
function rebuild(name){
|
|
70
|
+
var s=sanitize(name)||'AGENT';
|
|
71
|
+
if(s===builtName)return;
|
|
72
|
+
builtName=s;
|
|
73
|
+
l1.innerHTML=L1.split('').map(function(ch){return '<span class="l1c">'+(ch===' '?' ':ch)+'</span>'}).join('');
|
|
74
|
+
l1c=l1.children;
|
|
75
|
+
var idx=[];for(var i=0;i<L1.length;i++)idx.push(i);
|
|
76
|
+
for(var j=idx.length-1;j>0;j--){var k=Math.floor(rnd()*(j+1));var tmp=idx[j];idx[j]=idx[k];idx[k]=tmp}
|
|
77
|
+
order=new Array(L1.length);idx.forEach(function(v,rank){order[v]=rank});
|
|
78
|
+
nameChars=Array.from(s);
|
|
79
|
+
nameEl.innerHTML=nameChars.map(function(ch){return '<span class="nmc">'+esc(ch)+'</span>'}).join('');
|
|
80
|
+
nmc=nameEl.children;
|
|
81
|
+
settles=nameChars.map(function(){return rnd()});
|
|
82
|
+
rates=nameChars.map(function(){return 12+rnd()*22});
|
|
83
|
+
/* 按最终字符宽度定宽,乱码阶段不会因为字宽变化而抖动 */
|
|
84
|
+
for(var m=0;m<nmc.length;m++){nmc[m].style.width=(nmc[m].getBoundingClientRect().width+0.6)+'px';}
|
|
85
|
+
measuredKey='';measure();
|
|
86
|
+
colon.style.opacity='0';caret.style.opacity='0';scanBar.style.opacity='0';if(scanWrap)scanWrap.style.setProperty('--p','0%');
|
|
87
|
+
if(meta)meta.textContent='AUTH MODULE v2.16';
|
|
88
|
+
}
|
|
89
|
+
function measure(){
|
|
90
|
+
var fs=parseFloat(getComputedStyle(l2).fontSize)||17;
|
|
91
|
+
var key=fs.toFixed(2)+'|'+Math.round(l2.clientWidth);
|
|
92
|
+
if(key===measuredKey)return;
|
|
93
|
+
measuredKey=key;
|
|
94
|
+
HEAD_W=head.getBoundingClientRect().width;
|
|
95
|
+
NAME_W=nameEl.getBoundingClientRect().width;
|
|
96
|
+
}
|
|
97
|
+
/* 三次贝塞尔缓动(cubic-bezier(.22,1,.36,1)),用于「正在登录」平滑左移 */
|
|
98
|
+
function bezier(p){
|
|
99
|
+
p=Math.max(0,Math.min(1,p));
|
|
100
|
+
var x1=.22,y1=1,x2=.36,y2=1;
|
|
101
|
+
var t=p;
|
|
102
|
+
for(var i=0;i<4;i++){
|
|
103
|
+
var mt=1-t;
|
|
104
|
+
var x=3*mt*mt*t*x1+3*mt*t*t*x2+t*t*t;
|
|
105
|
+
var dx=3*mt*mt*x1+6*mt*t*(x2-x1)+3*t*t*(1-x2);
|
|
106
|
+
if(Math.abs(dx)<1e-6)break;
|
|
107
|
+
t=Math.max(0,Math.min(1,t-(x-p)/dx));
|
|
108
|
+
}
|
|
109
|
+
var m2=1-t;
|
|
110
|
+
return 3*m2*m2*t*y1+3*m2*t*t*y2+t*t*t;
|
|
111
|
+
}
|
|
112
|
+
function render(lt,name){
|
|
113
|
+
rebuild(name);measure();
|
|
114
|
+
var n=l1c.length;
|
|
115
|
+
for(var i=0;i<n;i++){
|
|
116
|
+
var st=L1_START+(order[i]/Math.max(1,n-1))*L1_SPAN,en=st+L1_FLICK,c=l1c[i],final=L1[i];
|
|
117
|
+
if(lt<st){c.textContent=POOL[(i*131+Math.floor(lt*26)*17)%POOL.length];c.style.opacity=String(0.05+0.22*Math.max(0,Math.sin(lt*11+i)));}
|
|
118
|
+
else if(lt<en){c.textContent=POOL[(i*97+Math.floor(lt*30)*31)%POOL.length];c.style.opacity=String(0.25+0.75*((lt-st)/L1_FLICK));}
|
|
119
|
+
else{c.textContent=final===' '?'\u00a0':final;c.style.opacity='1';}
|
|
120
|
+
}
|
|
121
|
+
l1.style.opacity=String(0.9+0.1*Math.abs(Math.sin(lt*13)));
|
|
122
|
+
var p=Math.max(0,Math.min(1,(lt-L2_START)/L2_SCAN));
|
|
123
|
+
if(scanWrap)scanWrap.style.setProperty('--p',(p*100).toFixed(2)+'%');
|
|
124
|
+
scanBar.style.top=(p*100).toFixed(2)+'%';
|
|
125
|
+
if(lt>=L2_START-0.03&<<=L2_START+L2_SCAN)scanBar.style.opacity='1';
|
|
126
|
+
else if(lt>L2_START+L2_SCAN)scanBar.style.opacity=String(Math.max(0,1-(lt-(L2_START+L2_SCAN))/0.12));
|
|
127
|
+
else scanBar.style.opacity='0';
|
|
128
|
+
colon.style.opacity=String(Math.max(0,Math.min(1,(lt-COLON_AT)/COLON_DUR)));
|
|
129
|
+
for(var j=0;j<nmc.length;j++){
|
|
130
|
+
var cs=NAME_AT+0.04+settles[j]*NAME_DUR,e2=nmc[j];
|
|
131
|
+
if(lt<NAME_AT){e2.style.opacity='0';continue;}
|
|
132
|
+
if(lt<cs){e2.textContent=POOL[(j*73+Math.floor(lt*rates[j])*29)%POOL.length];e2.style.opacity=String(0.55+0.25*Math.abs(Math.sin(lt*rates[j])));e2.classList.remove('settled');}
|
|
133
|
+
else{e2.textContent=nameChars[j]===' '?'\u00a0':nameChars[j];e2.style.opacity='1';e2.classList.add('settled');}
|
|
134
|
+
}
|
|
135
|
+
caret.style.opacity=(lt>=NAME_AT&&(Math.floor((lt-NAME_AT)*2.6)%2===0))?'1':'0';
|
|
136
|
+
/* 用户名出现时整行按贝塞尔曲线平移,避免「正在登录」瞬移 */
|
|
137
|
+
var W=l2.clientWidth||1;
|
|
138
|
+
var xHead=Math.max(0,(W-HEAD_W)/2);
|
|
139
|
+
var xFull=Math.max(0,(W-(HEAD_W+NAME_W))/2);
|
|
140
|
+
var k=lt<NAME_AT?0:bezier((lt-NAME_AT)/SLIDE_DUR);
|
|
141
|
+
track.style.transform='translateX('+(xHead+(xFull-xHead)*k).toFixed(2)+'px)';
|
|
142
|
+
}
|
|
143
|
+
return {render:render,sanitize:sanitize};
|
|
144
|
+
})();
|
|
145
|
+
function hideLogin(){var el=$('login'),sc=$('scene');if(el)el.classList.remove('on');if(sc)sc.style.opacity='1';}
|
|
146
|
+
|
|
147
|
+
function voiceState(VT,rt){
|
|
148
|
+
let vh=null,vOn=false,sub="";
|
|
149
|
+
const cueOn=!!(window.__DSH_CUE__&&performance.now()<(window.__DSH_CUE_UNTIL__||0));
|
|
150
|
+
if(cueOn){
|
|
151
|
+
sub=window.__DSH_CUE__;
|
|
152
|
+
vh=Array.from({length:20},(_,k)=>4+Math.min(360,Math.abs(Math.sin(rt*7+k*0.55))*300));
|
|
153
|
+
vOn=true;
|
|
154
|
+
}else{
|
|
155
|
+
const vsched=(window.__VSCHED__&&window.__VSCHED__.length)?window.__VSCHED__:(window.VOICE_SCHED||[]).map(function(x){var atV=voiceVT(x.at);return{key:x.key,at:atV,dur:(x.at>=loginEnd?x.dur/1.5:x.dur)};});
|
|
156
|
+
const audioOn=!!window.__DSH_AUDIO_ON__, avNow=window.__DSH_ACTIVE_VOICE__||'', aNow=+window.__DSH_AUDIO_T__||0, aPlaying=!!window.__DSH_AUDIO_PLAYING__;
|
|
157
|
+
for(const x of vsched){
|
|
158
|
+
let vt=null;
|
|
159
|
+
if(audioOn){if(avNow===x.key&&aPlaying)vt=Math.max(0,aNow);}
|
|
160
|
+
else if(VT>=x.at-0.02&&VT<x.at+x.dur)vt=VT-x.at;
|
|
161
|
+
if(vt==null)continue;
|
|
162
|
+
sub=(cfg.voice&&cfg.voice.subs&&cfg.voice.subs[x.key])||"";
|
|
163
|
+
const e=(window.VOICE_ENV||{})[x.key];
|
|
164
|
+
if(e&&e.length){vh=Array.from({length:20},(_,k)=>{const st=Math.max(0,vt-(19-k)*0.055);const fi=st/0.008;const ai=Math.min(e.length-1,Math.floor(fi));const af=fi-Math.floor(fi);const a=((e[ai]||0)*(1-af)+(e[Math.min(e.length-1,ai+1)]||0)*af);return 4+Math.min(360,Math.pow(Math.max(0,a),0.9)*360)});vOn=true;}
|
|
165
|
+
else{vh=Array.from({length:20},(_,k)=>4+Math.min(360,Math.abs(Math.sin(vt*7+k*0.55))*300));vOn=true;}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return {h:vh||Array(20).fill(4),sub:sub,on:vOn};
|
|
170
|
+
}
|
|
49
171
|
function render(){
|
|
50
|
-
const m=HUDMotion.state(t,cfg.loadingStart),loading=m.load,p=progress(t);
|
|
51
|
-
lastLoaded=m.load;
|
|
52
|
-
/* v2.15.12:结尾等配音时 t 冻结在 duration,波形/圆环改用连续时钟 rt,动画不中断 */
|
|
53
172
|
const waitSec=((window.__VTIME__==null)&&window.__WAIT_START__>0&&t>=cfg.duration-0.03)?(performance.now()-window.__WAIT_START__)/1000:0;
|
|
54
173
|
const rt=t+waitSec;
|
|
174
|
+
let VT=(window.__VTIME__!=null)?+window.__VTIME__:voiceVT(t);VT+=waitSec;
|
|
175
|
+
const vs=voiceState(VT,rt);
|
|
176
|
+
/* v2.16.0:登录动画期间只驱动登录层,主场景淡出;台词走同一套「图标+DSH+波形+字幕」行 */
|
|
177
|
+
if(loginDur>0&&t>=loginStart&&t<loginEnd){
|
|
178
|
+
var lg=$('login'),sc=$('scene');if(sc)sc.style.opacity='0';if(lg)lg.classList.add('on');
|
|
179
|
+
if(LOGIN)LOGIN.render(t-loginStart,cfg.username);
|
|
180
|
+
renderVoiceRow($('login-voice'),$('login-voice-sub'),vs.h,vs.sub,vs.on?1:0);
|
|
181
|
+
lastLoaded=false;
|
|
182
|
+
$('seek').value=t;$('time').textContent=(t-(+cfg.startAt||0)).toFixed(2)+' / '+(cfg.duration-(+cfg.startAt||0)).toFixed(2)+' s';
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
hideLogin();
|
|
186
|
+
const m=HUDMotion.state(t,cfg.loadingStart),loading=m.load,p=progress(t);
|
|
187
|
+
lastLoaded=m.load;
|
|
55
188
|
$('rings').style.opacity=m.opacity;$('rings').removeAttribute('transform');
|
|
56
189
|
$('outer').setAttribute('transform',`scale(${m.outerScale}) rotate(${rt*5})`);$('outer').style.opacity=m.outerOpacity;
|
|
57
190
|
$('ticks').setAttribute('transform',`scale(${m.outerScale*m.outerPulse})`);$('ticks').style.opacity=m.outerOpacity;
|
|
@@ -68,18 +201,7 @@ function render(){
|
|
|
68
201
|
$('status').textContent=loading?'加载中':'连接中:'+cfg.username;$('status').style.opacity=m.opacity*m.labelOpacity;
|
|
69
202
|
$('statusArrow').style.opacity=m.opacity*m.labelOpacity;
|
|
70
203
|
$('statusDots').style.opacity=m.opacity*m.labelOpacity*(.35+.65*Math.abs(Math.sin(rt*4)));
|
|
71
|
-
|
|
72
|
-
/* v2.15.14:重连接提示音独占一整行(图标+DSH+波形+中文),播完才恢复后续配音 */
|
|
73
|
-
const cueOn=!!(window.__DSH_CUE__&&performance.now()<(window.__DSH_CUE_UNTIL__||0));
|
|
74
|
-
if(cueOn){
|
|
75
|
-
sub=window.__DSH_CUE__;
|
|
76
|
-
vh=Array.from({length:20},(_,k)=>4+Math.min(360,Math.abs(Math.sin(rt*7+k*0.55))*300));
|
|
77
|
-
vOn=true;
|
|
78
|
-
}else{
|
|
79
|
-
const vsched=(window.__VSCHED__&&window.__VSCHED__.length)?window.__VSCHED__:(window.VOICE_SCHED||[]).map(function(s){var atV=(s.at<=9.2)?s.at-3.4:5.8+(s.at-9.2)/1.5;return{key:s.key,at:atV,dur:s.dur};});
|
|
80
|
-
for(const s of vsched){if(VT>=s.at-0.02&&VT<s.at+s.dur&&(!window.__DSH_AUDIO_ON__||window.__DSH_ACTIVE_VOICE__===s.key)){sub=(cfg.voice&&cfg.voice.subs&&cfg.voice.subs[s.key])||"";const e=(window.VOICE_ENV||{})[s.key];if(e&&e.length){const vt=VT-s.at;vh=Array.from({length:20},(_,k)=>{const st=Math.max(0,vt-(19-k)*0.055);const fi=st/0.008;const ai=Math.min(e.length-1,Math.floor(fi));const af=fi-Math.floor(fi);const a=((e[ai]||0)*(1-af)+(e[Math.min(e.length-1,ai+1)]||0)*af);return 4+Math.min(360,Math.pow(Math.max(0,a),0.9)*360)});vOn=true;}break;}}
|
|
81
|
-
}
|
|
82
|
-
const h=vh||Array(20).fill(4);const voiceVisible=vOn?1:0;renderVoiceRow($('voice'),$('subtitle'),h,sub,voiceVisible);$('seek').value=t;$('time').textContent=(t-(+cfg.startAt||0)).toFixed(2)+' / '+(cfg.duration-(+cfg.startAt||0)).toFixed(2)+' s';
|
|
204
|
+
renderVoiceRow($('voice'),$('subtitle'),vs.h,vs.sub,vs.on?1:0);$('seek').value=t;$('time').textContent=(t-(+cfg.startAt||0)).toFixed(2)+' / '+(cfg.duration-(+cfg.startAt||0)).toFixed(2)+' s';
|
|
83
205
|
}
|
|
84
206
|
function syncAudio(){if(!env)return;const at=t- +$('voiceStart').value;if(at<0||at>=env.duration){audio.pause();return}if(Math.abs(audio.currentTime-at)>.12)audio.currentTime=at;if(playing&&audio.paused)audio.play().catch(()=>{$('audioInfo').textContent='请点击播放以启用音频。'});if(!playing)audio.pause()}
|
|
85
207
|
function play(){if(t>=cfg.duration)t=+cfg.startAt||0;playing=true;last=performance.now();$('play').textContent='暂停';syncAudio()}
|
|
@@ -116,16 +238,16 @@ $('prevFrame').onclick=()=>{pause();seek(t-1/60)};$('nextFrame').onclick=()=>{pa
|
|
|
116
238
|
function voiceDuck(on){try{if(parent&&parent!==window)parent.postMessage({type:'dsh-startup-voice',on:!!on},'*')}catch(e){}}
|
|
117
239
|
/* v2.15.10:彩蛋弹出时请宿主截断 BGM;重连后请宿主重新播 */
|
|
118
240
|
function bgmSig(on){try{if(parent&&parent!==window)parent.postMessage({type:'dsh-startup-bgm',on:!!on},'*')}catch(e){}}
|
|
119
|
-
var sched=vc.sched||[[4.6,'orig1',2.65],[8.
|
|
241
|
+
var sched=vc.sched||[[4.6,'orig1',2.65],[9.8,'login',1.79],[14.5,'line1',3.375],[18.4,'line2',3.232],[25.0,'line3',3.300],[30.45,'orig3',2.77]];
|
|
120
242
|
var eggLineAt=+(vc.eggLineAt!=null?vc.eggLineAt:2.0), eggReplayWait=+(vc.eggReplayWait!=null?vc.eggReplayWait:2.0), line4Dur=+(vc.line4Dur||1.911);
|
|
121
|
-
var aud={},played={},activeVoice=null,cueGate=false,cueFailTimer=null;window.__DSH_AUDIO_ON__=!mute;window.__DSH_ACTIVE_VOICE__='';
|
|
122
|
-
sched.forEach(function(e){var k=e[1];if(!mute&&vc[k]){var a=new Audio(vc[k]);a.preload='auto';a.volume=voiceVol;a.addEventListener('ended',function(){if(activeVoice===k){activeVoice=null;window.__DSH_ACTIVE_VOICE__='';}voiceDuck(false)});aud[k]=a;played[k]=false;}});
|
|
243
|
+
var aud={},played={},activeVoice=null,cueGate=false,cueFailTimer=null;window.__DSH_AUDIO_ON__=!mute;window.__DSH_ACTIVE_VOICE__='';window.__DSH_AUDIO_T__=-1;window.__DSH_AUDIO_PLAYING__=false;
|
|
244
|
+
sched.forEach(function(e){var k=e[1];if(!mute&&vc[k]){var a=new Audio(vc[k]);a.preload='auto';a.volume=voiceVol;a.addEventListener('ended',function(){if(activeVoice===k){activeVoice=null;window.__DSH_ACTIVE_VOICE__='';}window.__DSH_AUDIO_PLAYING__=false;window.__DSH_AUDIO_T__=-1;voiceDuck(false)});aud[k]=a;played[k]=false;}});
|
|
123
245
|
if(!mute&&vc.reconnect){var rc=new Audio(vc.reconnect);rc.preload='auto';rc.volume=voiceVol;rc.addEventListener('ended',function(){if(activeVoice==='reconnect'){activeVoice=null;window.__DSH_ACTIVE_VOICE__=''}window.__DSH_CUE__='';window.__DSH_CUE_UNTIL__=0;cueGate=false;voiceDuck(false)});aud.reconnect=rc;played.reconnect=true;}
|
|
124
|
-
/* v2.15.14
|
|
246
|
+
/* v2.15.14:重连接提示音独占一整行;重连提示音只播自己这一行;播完(ended)才解除 cueGate,后续 line2/line3/orig3 才允许开始 */
|
|
125
247
|
function playReconnectCue(){if(mute||!aud.reconnect)return;cueGate=true;setTimeout(function(){try{attachVoiceFx('reconnect');aud.reconnect.currentTime=0;aud.reconnect.play().catch(function(){})}catch(e){}activeVoice='reconnect';window.__DSH_ACTIVE_VOICE__='';var txt=(cfg.voice&&cfg.voice.subs&&cfg.voice.subs.reconnect)||'';var d=isFinite(aud.reconnect.duration)&&aud.reconnect.duration>0?aud.reconnect.duration:2.82;window.__DSH_CUE__=txt;window.__DSH_CUE_UNTIL__=performance.now()+d*1000+150;voiceDuck(true);if(cueFailTimer)clearTimeout(cueFailTimer);
|
|
126
248
|
/* 兜底:音频若因自动播放策略被拒,ended 不会触发;到时强制解除门控,避免后续配音全被卡住 */
|
|
127
249
|
cueFailTimer=setTimeout(function(){if(activeVoice==='reconnect'){activeVoice=null;window.__DSH_ACTIVE_VOICE__='';window.__DSH_CUE__='';window.__DSH_CUE_UNTIL__=0;cueGate=false;voiceDuck(false)}},d*1000+1500)},500)}
|
|
128
|
-
if(!mute&&vc.line4){var l4=new Audio(vc.line4);l4.preload='auto';l4.volume=voiceVol;l4.addEventListener('ended',function(){if(activeVoice==='line4'){activeVoice=null;window.__DSH_ACTIVE_VOICE__='';}voiceDuck(false)});aud.line4=l4;played.line4=false;}
|
|
250
|
+
if(!mute&&vc.line4){var l4=new Audio(vc.line4);l4.preload='auto';l4.volume=voiceVol;l4.addEventListener('ended',function(){if(activeVoice==='line4'){activeVoice=null;window.__DSH_ACTIVE_VOICE__='';}window.__DSH_AUDIO_PLAYING__=false;window.__DSH_AUDIO_T__=-1;voiceDuck(false)});aud.line4=l4;played.line4=false;}
|
|
129
251
|
/* v2.15.5:模板内配音效果(与全局 5 个声音效果同参数);只在宿主注入 voiceFx 时生效。 */
|
|
130
252
|
var VOICE_FX_PRESETS={'ai-mech':{hp:130,lp:4200,peak:{f:260,g:4,q:1.0},drive:0.15,ring:0},'robot':{hp:180,lp:3200,peak:{f:1500,g:3,q:0.9},drive:0.35,ring:42},'radio':{hp:420,lp:2800,peak:{f:1800,g:5,q:1.2},drive:0.6,ring:0},'oldtv':{hp:220,lp:2200,peak:null,drive:0.45,ring:0},'dark':{hp:90,lp:1200,peak:{f:180,g:5,q:0.8},drive:0.1,ring:0}};
|
|
131
253
|
var voiceFxMode=String((cfg&&cfg.voiceFx)||'none');
|
|
@@ -167,21 +289,25 @@ $('prevFrame').onclick=()=>{pause();seek(t-1/60)};$('nextFrame').onclick=()=>{pa
|
|
|
167
289
|
eggSub.setAttribute('font-family',"'DIN Alternate','Bahnschrift','Microsoft YaHei',sans-serif");
|
|
168
290
|
eggSvg.appendChild(eggRow);eggSvg.appendChild(eggSub);eggEl.appendChild(eggSvg);
|
|
169
291
|
}
|
|
170
|
-
|
|
292
|
+
/* v2.15.17:彩蛋里的中文台词改为跟随 voice-line4 的真实播放时钟,不再用墙钟推算。
|
|
293
|
+
这样即使彩蛋的 setTimeout 被主线程拖慢,字幕也会和语音同时出现、同时结束。 */
|
|
294
|
+
function eggVoice(){
|
|
171
295
|
ensureEggVoice();
|
|
296
|
+
var a=aud.line4, live=!!(window.__DSH_AUDIO_ON__&&a&&!a.paused&&!a.ended&&window.__DSH_ACTIVE_VOICE__==='line4');
|
|
297
|
+
var vt=live?Math.max(0,+a.currentTime||0):-1;
|
|
172
298
|
var e=(window.VOICE_ENV||{}).line4||[], vh=Array(20).fill(4);
|
|
173
|
-
if(
|
|
299
|
+
if(live&&vt<line4Dur+0.25&&e.length){
|
|
174
300
|
var fi=vt/0.008, ai=Math.min(e.length-1,Math.floor(fi)), af=fi-Math.floor(fi);
|
|
175
301
|
var amp=((e[ai]||0)*(1-af)+(e[Math.min(e.length-1,ai+1)]||0)*af);
|
|
176
302
|
vh=[];for(var k=0;k<20;k++){var tv2=vt-(19-k)*0.06;var f2=tv2/0.008,i2=Math.min(e.length-1,Math.floor(f2));var a2=((e[i2]||0)*(1-(f2-Math.floor(f2)))+(e[Math.min(e.length-1,i2+1)]||0)*(f2-Math.floor(f2)));vh.push(4+Math.min(440,Math.pow(Math.max(0,a2),0.85)*440))}
|
|
177
303
|
}
|
|
178
|
-
var show=
|
|
304
|
+
var show=live?1:0;
|
|
179
305
|
var st=show?((cfg.voice&&cfg.voice.subs&&cfg.voice.subs.line4)||''):'';
|
|
180
306
|
renderVoiceRow(eggRow,eggSub,vh,st,show);
|
|
181
307
|
}
|
|
182
308
|
var shown=false,done=false,rolled=false,v3Ended=false,waitStart=0,v4Timer=null,replayTimer=null,eggShownAt=0,eggWait=false,eggWaitTimer=null;
|
|
183
309
|
var hit=q.get('egg')==='1'||Math.random()<EGG_CHANCE;
|
|
184
|
-
function stopVoice(){voiceDuck(false);activeVoice=null;window.__DSH_ACTIVE_VOICE__='';window.__DSH_CUE__='';window.__DSH_CUE_UNTIL__=0;cueGate=false;if(cueFailTimer){clearTimeout(cueFailTimer);cueFailTimer=null}Object.keys(aud).forEach(function(k){var a=aud[k];try{a.pause();a.currentTime=0}catch(e){}});if(v4Timer){clearTimeout(v4Timer);v4Timer=null}if(replayTimer){clearTimeout(replayTimer);replayTimer=null}}
|
|
310
|
+
function stopVoice(){voiceDuck(false);activeVoice=null;window.__DSH_ACTIVE_VOICE__='';window.__DSH_AUDIO_PLAYING__=false;window.__DSH_AUDIO_T__=-1;window.__DSH_CUE__='';window.__DSH_CUE_UNTIL__=0;cueGate=false;if(cueFailTimer){clearTimeout(cueFailTimer);cueFailTimer=null}Object.keys(aud).forEach(function(k){var a=aud[k];try{a.pause();a.currentTime=0}catch(e){}});if(v4Timer){clearTimeout(v4Timer);v4Timer=null}if(replayTimer){clearTimeout(replayTimer);replayTimer=null}}
|
|
185
311
|
function playKey(k,offset){var a=aud[k];if(a&&!played[k]){played[k]=true;attachVoiceFx(k);try{a.currentTime=Math.max(0,offset||0);a.play().catch(function(){});activeVoice=k;window.__DSH_ACTIVE_VOICE__=k}catch(e){}voiceDuck(true);}}
|
|
186
312
|
function resetPlayedAfter(t0){
|
|
187
313
|
Object.keys(played).forEach(function(k){played[k]=false});v3Ended=false;
|
|
@@ -197,12 +323,12 @@ $('prevFrame').onclick=()=>{pause();seek(t-1/60)};$('nextFrame').onclick=()=>{pa
|
|
|
197
323
|
stopVoice();
|
|
198
324
|
bgmSig(false);
|
|
199
325
|
eggEl.classList.add('on'); eggEl.setAttribute('aria-hidden','false'); try{document.body.classList.add('egg-on')}catch(e){}
|
|
200
|
-
eggShownAt=performance.now(); eggVoice(
|
|
326
|
+
eggShownAt=performance.now(); eggVoice();
|
|
201
327
|
v4Timer=setTimeout(function(){playKey('line4')},eggLineAt*1000);
|
|
202
328
|
/* v2.15.6:不再自动 reconnect——彩蛋必须等用户点【重新连接】,否则动画会自己往下走、声音叠在一起。 */
|
|
203
329
|
render();
|
|
204
330
|
}
|
|
205
|
-
function eggFrame(sec){showEgg();stopVoice();window.__EGG_T=Math.max(0,sec);eggShownAt=performance.now()-window.__EGG_T*1000;if(sec>=eggLineAt)playKey('line4');eggVoice(
|
|
331
|
+
function eggFrame(sec){showEgg();stopVoice();window.__EGG_T=Math.max(0,sec);eggShownAt=performance.now()-window.__EGG_T*1000;if(sec>=eggLineAt)playKey('line4');eggVoice();}
|
|
206
332
|
function hideEgg(){eggEl.classList.remove('on');eggEl.setAttribute('aria-hidden','true');try{document.body.classList.remove('egg-on')}catch(e){}shown=false;}
|
|
207
333
|
/* v2.15.14:重连后不再续播断句(原来会把 line1 从半句接着放,和 reconnect 叠在一起)。
|
|
208
334
|
顺序:等待 0.5s → 只播 reconnect(独占一行)→ 播完解除 cueGate → line2/line3/orig3 按时间线继续。 */
|
|
@@ -220,13 +346,22 @@ $('prevFrame').onclick=()=>{pause();seek(t-1/60)};$('nextFrame').onclick=()=>{pa
|
|
|
220
346
|
if(aud.orig3)aud.orig3.addEventListener('ended',function(){v3Ended=true});
|
|
221
347
|
(function watch(){
|
|
222
348
|
if(!done){
|
|
223
|
-
|
|
349
|
+
/* v2.15.17:把当前配音的真实播放状态镜像到 window,供 render()/eggVoice() 使用,
|
|
350
|
+
让字幕与波形以音频时钟为准,而不是按时间轴推算。 */
|
|
351
|
+
var __av=activeVoice?aud[activeVoice]:null;
|
|
352
|
+
if(__av){window.__DSH_AUDIO_T__=+__av.currentTime||0;window.__DSH_AUDIO_DUR__=+__av.duration||0;window.__DSH_AUDIO_PLAYING__=!__av.paused&&!__av.ended;}
|
|
353
|
+
if(playing&&!cueGate){
|
|
354
|
+
/* v2.16.0:配音串行播放——上一句没播完(ended/pause)不启动下一句。
|
|
355
|
+
原因:第三节是 1.5x 加速段,时间轴会比真实音频快,按时间轴 forEach 会让 line1 尾巴和 line2 叠在一起。 */
|
|
356
|
+
var __busy=!!(activeVoice&&aud[activeVoice]&&!aud[activeVoice].paused&&!aud[activeVoice].ended);
|
|
357
|
+
if(!__busy){var __next=null;sched.forEach(function(e){if(!__next&&t>=e[0]&&!played[e[1]])__next=e;});if(__next)playKey(__next[1]);}
|
|
358
|
+
}
|
|
224
359
|
/* v2.15.16:掉线彩蛋若正好赶上某句配音,先等这句播完再弹出,避免语音和字幕被硬切断(有兜底超时)。 */
|
|
225
360
|
if(!rolled&&playing&&!shown&&t>=eggAt){
|
|
226
361
|
if(!hit){rolled=true;}
|
|
227
362
|
else if(!eggWait&&activeVoice&&aud[activeVoice]&&!aud[activeVoice].paused&&!aud[activeVoice].ended){
|
|
228
363
|
var eggA=aud[activeVoice], eggLeft=(+eggA.duration||0)-(+eggA.currentTime||0);
|
|
229
|
-
if(isFinite(eggLeft)&&eggLeft>0.05&&
|
|
364
|
+
if(isFinite(eggLeft)&&eggLeft>0.05&&eggLeft<=6){
|
|
230
365
|
eggWait=true;
|
|
231
366
|
(function(a){
|
|
232
367
|
var fired=false,fin=function(){if(fired)return;fired=true;eggWait=false;eggWaitTimer=null;rolled=true;showEgg();};
|
|
@@ -236,8 +371,8 @@ $('prevFrame').onclick=()=>{pause();seek(t-1/60)};$('nextFrame').onclick=()=>{pa
|
|
|
236
371
|
} else {rolled=true;showEgg();}
|
|
237
372
|
} else if(!eggWait){rolled=true;showEgg();}
|
|
238
373
|
}
|
|
239
|
-
if(shown){
|
|
240
|
-
if(!shown&&t>=cfg.duration-0.02){if(!waitStart){waitStart=performance.now();window.__WAIT_START__=waitStart;}var waitVoice=(!mute&&aud.orig3&&!v3Ended&&(performance.now()-waitStart<4000));if(!waitVoice)flashDone();}
|
|
374
|
+
if(shown){eggVoice();}
|
|
375
|
+
if(!shown&&!eggWait&&t>=cfg.duration-0.02){if(!waitStart){waitStart=performance.now();window.__WAIT_START__=waitStart;}var waitVoice=(!mute&&aud.orig3&&!v3Ended&&(performance.now()-waitStart<4000));if(!waitVoice)flashDone();}
|
|
241
376
|
}
|
|
242
377
|
requestAnimationFrame(watch);
|
|
243
378
|
})();
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 全景大肥鱼-含彩蛋版 · 可编辑代码动画参数(Lead 2026-11-
|
|
1
|
+
// 全景大肥鱼-含彩蛋版 · 可编辑代码动画参数(Lead 2026-11-02 更新:三段时间轴 + 登录 ID 动画)
|
|
2
2
|
window.CONFIG={
|
|
3
3
|
username:'人类与AI的日常',
|
|
4
4
|
title:'什么是「模板」?',
|
|
@@ -10,15 +10,18 @@ window.CONFIG={
|
|
|
10
10
|
{title:'想自己改?',description:'打开模板编辑器,标题、正文、连接用户名都能改,保存后下次启动生效。'},
|
|
11
11
|
{title:'怎么跳过?',description:'等进度条走完会自动进入聊天;想提前进,按 Esc 或点右上角「跳过」。'}
|
|
12
12
|
],
|
|
13
|
-
duration:
|
|
13
|
+
duration:33.4,
|
|
14
14
|
startAt:3.4,
|
|
15
|
-
|
|
15
|
+
/* 第一节:3.4 → 9.2s(约 5s 可见);第二节登录动画:9.2 → 14.2s(5s);第三节读取 0–100:14.2 → 30.92s。 */
|
|
16
|
+
loginStart:9.2,
|
|
17
|
+
loginDur:5.0,
|
|
18
|
+
loadingStart:14.2,
|
|
16
19
|
voiceY:908,
|
|
17
20
|
voiceWidth:520,
|
|
18
|
-
speedStart:
|
|
21
|
+
speedStart:14.2,
|
|
19
22
|
speed:1.5,
|
|
20
|
-
speedEnd:
|
|
23
|
+
speedEnd:30.45,
|
|
21
24
|
egg:{}, // v2.15.10:掉线时机在「进度 0–100%」之间随机(app.js 按 loadingStart~speedEnd 计算)
|
|
22
|
-
voice:{subs:{orig1:'警告:检测到新特工登录。',line1:'战术模块传输中,请稍候。',line2:'装备与技能配置已验证。倒计时十秒。',line3:'网络同步完成。正在移交权限。',line4:'警告:特工已离线。',reconnect:'检测到特工重新连接。',orig3:'欢迎回来,特工。很高兴再次见到你。'},orig1:'assets/voice-orig1.wav',line1:'assets/voice-line1.wav',line2:'assets/voice-line2.wav',line3:'assets/voice-line3.wav',orig3:'assets/voice-orig3.wav',line4:'assets/voice-line4.wav',reconnect:'assets/voice-reconnect.wav',sched:[[4.6,'orig1',2.65],[8.
|
|
23
|
-
progress:[[
|
|
25
|
+
voice:{subs:{orig1:'警告:检测到新特工登录。',login:'特工身份确认。',line1:'战术模块传输中,请稍候。',line2:'装备与技能配置已验证。倒计时十秒。',line3:'网络同步完成。正在移交权限。',line4:'警告:特工已离线。',reconnect:'检测到特工重新连接。',orig3:'欢迎回来,特工。很高兴再次见到你。'},orig1:'assets/voice-orig1.wav',login:'assets/voice-login.wav',line1:'assets/voice-line1.wav',line2:'assets/voice-line2.wav',line3:'assets/voice-line3.wav',orig3:'assets/voice-orig3.wav',line4:'assets/voice-line4.wav',reconnect:'assets/voice-reconnect.wav',sched:[[4.6,'orig1',2.65],[9.8,'login',1.79],[14.5,'line1',3.375],[18.4,'line2',3.232],[25.0,'line3',3.300],[30.45,'orig3',2.77]],eggLineAt: 1.0,line4Dur:1.911},
|
|
26
|
+
progress:[[14.2,0],[15,0],[15.9,0],[16.5,10],[17,29],[18,41],[19,43],[20,43],[25,43],[26,46],[27,51],[28,55],[29,59],[30,63],[30.4,64],[30.45,100],[30.92,100],[33.4,100]]
|
|
24
27
|
};
|
|
@@ -1 +1,14 @@
|
|
|
1
|
-
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>全境封锁 · 可编辑代码动画</title><link rel="stylesheet" href="style.css"><style id="dsh-embed-style">html.embed,html.embed body{width:100%;height:100%;margin:0;overflow:hidden;background:#000}html.embed main{display:block!important;width:100%;height:100%}html.embed aside{display:none!important}html.embed #stage{width:100%;height:100%}html.embed #scene{width:100%;height:100%;display:block}</style></head><body><main><div id="stage"><svg id="scene" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080"><g id="tip"><path d="M615 222v-22q15-17 30 0v22zM620 201h20v18h-20zM626 189h9" fill="none" stroke="#aaa" stroke-width="2"/><text id="title" x="657" y="219" fill="#ccc" font-size="27"></text><path d="M606 232H1316M606 299H1316" stroke="#252525"/><foreignObject x="621" y="240" width="683" height="58"><div xmlns="http://www.w3.org/1999/xhtml" id="description"></div></foreignObject><path d="M596 256v19M1324 256v19" stroke="#999" stroke-width="2"/><rect x="624" y="313" width="45" height="16" fill="#555"/><text x="631" y="324" font-size="13" fill="#ccc">▏</text><text x="681" y="329" font-size="18" fill="#999">下一则</text><g id="pages"></g></g><g transform="translate(960 540)"><g id="rings"><circle id="pulse" r="10" fill="none" stroke="#70491a" stroke-width="2"/><circle id="pulseTrail" r="10" fill="none" stroke="#30250d" stroke-width="9"/><circle id="outerPulse" r="210" fill="none" stroke="#89521b" stroke-width="1"/><g id="ticks"></g><g id="outer"></g><g id="middle"></g><g id="inner"></g><g id="markers"></g><path id="progressArc" fill="none" stroke="#f29420" stroke-width="16"/><circle r="68" fill="none" stroke="#50340b" stroke-width="2"/></g><text id="percent" text-anchor="middle" y="9" fill="#bcbcbc" font-size="29" font-weight="300"></text></g><path id="statusArrow" d="M958 810l5 7 5-7" fill="#555"/><text id="status" x="960" y="853" text-anchor="middle" fill="#757575" font-size="25"></text><g id="statusDots" fill="#888"><rect x="951" y="792" width="3" height="3"/><rect x="960" y="787" width="3" height="3"/><rect x="967" y="796" width="3" height="3"/></g><g id="voice"></g><text id="subtitle" x="960" y="944" text-anchor="middle" fill="#e9d6b8" font-size="24" letter-spacing="1" opacity="0" style="transition:opacity .22s ease;pointer-events:none"></text></svg></div><aside><h1>可编辑代码动画</h1><label>连接用户名<input id="username"></label><label>提示标题<input id="heading"></label><label>提示正文<textarea id="body" rows="4"></textarea></label><div class="buttons"><button id="play">播放</button><button id="restart">从头播放</button><button id="fullscreen">全屏</button></div><label><span id="time">0.00 / 25.90 秒</span><input id="seek" type="range" min="0" max="25.9" step="0.016667" value="0"></label><div class="buttons"><button id="connection">查看连接阶段</button><button id="loading">查看加载阶段</button><button id="prevFrame">上一帧</button><button id="nextFrame">下一帧</button></div><hr><label>导入语音<input id="file" type="file" accept="audio/*"></label><label>语音开始时间(秒)<input id="voiceStart" type="number" min="0" step="0.1" value="9.2"></label><label>语音框距“加载中”的间隔<input id="gap" type="range" min="12" max="100" step="1" value="55"></label><p id="audioInfo">尚未导入语音,波形静止。语音框在加载阶段出现。</p><div class="buttons"><button id="save">保存设置 JSON</button><button id="reset">恢复默认</button></div><p>文字即时生效并保存在当前浏览器。时间轴、圆环和刻度均由参数生成。</p></aside></main><audio id="audio"></audio><div id="egg" aria-hidden="true"><img id="egg-bg" src="assets/egg-bg.png" alt=""><div id="egg-veil"></div><div id="egg-card" role="alertdialog"><div class="egg-head"><span class="egg-badge">!</span><span class="egg-title">错误</span></div><div class="egg-msg">《战术大肥鱼®》服务目前无法使用,请点击重试按钮。<div class="egg-code"><span>DELTA</span><span>C-0-1302</span></div></div><div class="egg-actions"><button id="egg-retry" type="button">重新连接</button></div></div></div><
|
|
1
|
+
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>全境封锁 · 可编辑代码动画</title><link rel="stylesheet" href="style.css"><style id="dsh-embed-style">html.embed,html.embed body{width:100%;height:100%;margin:0;overflow:hidden;background:#000}html.embed main{display:block!important;width:100%;height:100%}html.embed aside{display:none!important}html.embed #stage{width:100%;height:100%}html.embed #scene{width:100%;height:100%;display:block}</style></head><body><main><div id="stage"><svg id="scene" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080"><g id="tip"><path d="M615 222v-22q15-17 30 0v22zM620 201h20v18h-20zM626 189h9" fill="none" stroke="#aaa" stroke-width="2"/><text id="title" x="657" y="219" fill="#ccc" font-size="27"></text><path d="M606 232H1316M606 299H1316" stroke="#252525"/><foreignObject x="621" y="240" width="683" height="58"><div xmlns="http://www.w3.org/1999/xhtml" id="description"></div></foreignObject><path d="M596 256v19M1324 256v19" stroke="#999" stroke-width="2"/><rect x="624" y="313" width="45" height="16" fill="#555"/><text x="631" y="324" font-size="13" fill="#ccc">▏</text><text x="681" y="329" font-size="18" fill="#999">下一则</text><g id="pages"></g></g><g transform="translate(960 540)"><g id="rings"><circle id="pulse" r="10" fill="none" stroke="#70491a" stroke-width="2"/><circle id="pulseTrail" r="10" fill="none" stroke="#30250d" stroke-width="9"/><circle id="outerPulse" r="210" fill="none" stroke="#89521b" stroke-width="1"/><g id="ticks"></g><g id="outer"></g><g id="middle"></g><g id="inner"></g><g id="markers"></g><path id="progressArc" fill="none" stroke="#f29420" stroke-width="16"/><circle r="68" fill="none" stroke="#50340b" stroke-width="2"/></g><text id="percent" text-anchor="middle" y="9" fill="#bcbcbc" font-size="29" font-weight="300"></text></g><path id="statusArrow" d="M958 810l5 7 5-7" fill="#555"/><text id="status" x="960" y="853" text-anchor="middle" fill="#757575" font-size="25"></text><g id="statusDots" fill="#888"><rect x="951" y="792" width="3" height="3"/><rect x="960" y="787" width="3" height="3"/><rect x="967" y="796" width="3" height="3"/></g><g id="voice"></g><text id="subtitle" x="960" y="944" text-anchor="middle" fill="#e9d6b8" font-size="24" letter-spacing="1" opacity="0" style="transition:opacity .22s ease;pointer-events:none"></text></svg></div><aside><h1>可编辑代码动画</h1><label>连接用户名<input id="username"></label><label>提示标题<input id="heading"></label><label>提示正文<textarea id="body" rows="4"></textarea></label><div class="buttons"><button id="play">播放</button><button id="restart">从头播放</button><button id="fullscreen">全屏</button></div><label><span id="time">0.00 / 25.90 秒</span><input id="seek" type="range" min="0" max="25.9" step="0.016667" value="0"></label><div class="buttons"><button id="connection">查看连接阶段</button><button id="loading">查看加载阶段</button><button id="prevFrame">上一帧</button><button id="nextFrame">下一帧</button></div><hr><label>导入语音<input id="file" type="file" accept="audio/*"></label><label>语音开始时间(秒)<input id="voiceStart" type="number" min="0" step="0.1" value="9.2"></label><label>语音框距“加载中”的间隔<input id="gap" type="range" min="12" max="100" step="1" value="55"></label><p id="audioInfo">尚未导入语音,波形静止。语音框在加载阶段出现。</p><div class="buttons"><button id="save">保存设置 JSON</button><button id="reset">恢复默认</button></div><p>文字即时生效并保存在当前浏览器。时间轴、圆环和刻度均由参数生成。</p></aside></main><audio id="audio"></audio><div id="egg" aria-hidden="true"><img id="egg-bg" src="assets/egg-bg.png" alt=""><div id="egg-veil"></div><div id="egg-card" role="alertdialog"><div class="egg-head"><span class="egg-badge">!</span><span class="egg-title">错误</span></div><div class="egg-msg">《战术大肥鱼®》服务目前无法使用,请点击重试按钮。<div class="egg-code"><span>DELTA</span><span>C-0-1302</span></div></div><div class="egg-actions"><button id="egg-retry" type="button">重新连接</button></div></div></div><div id="login" aria-hidden="true">
|
|
2
|
+
<div class="login-grid"></div>
|
|
3
|
+
<div class="login-scanlines"></div>
|
|
4
|
+
<div class="login-frame">
|
|
5
|
+
<div class="login-meta"><span>DSH // SECURE ACCESS</span><span>CHANNEL 02 · AUTH</span></div>
|
|
6
|
+
<div id="login-line1" class="login-line1"></div>
|
|
7
|
+
<div id="login-line2" class="login-line2">
|
|
8
|
+
<span id="login-l2-track" class="login-l2-track"><span id="login-l2-head" class="login-l2-head"><span class="login-scan-wrap"><span id="login-scan-text">正在登录</span><i id="login-scan-bar"></i></span><span id="login-colon">:</span></span><span id="login-name"></span><i id="login-caret"></i></span>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="login-meta login-foot"><span>AUTH MODULE v2.16</span><span>DEEPSEEK HARNESS</span></div>
|
|
11
|
+
</div>
|
|
12
|
+
<svg id="login-voice-layer" class="login-voice-layer" viewBox="0 0 1920 1080" preserveAspectRatio="xMidYMid slice" aria-hidden="true"><g id="login-voice"></g><text id="login-voice-sub" fill="#e9d6b8" font-family="'DIN Alternate','Bahnschrift','Microsoft YaHei',sans-serif"></text></svg>
|
|
13
|
+
</div>
|
|
14
|
+
<script src="config.js"></script><script src="voice.js"></script><script src="voice-env.js"></script><script src="motion.js"></script><script src="app.js"></script><script>/* DSH_EMBED_PATCH */ (function(){try{var t=window.__DSH_STARTUP_TEMPLATE__||null;var embedded=(window.self!==window.top)||(t&&t.id==="division-bigfish-codex");if(!embedded)return;document.documentElement.classList.add("embed");function setv(id,v){if(!v)return;var el=document.getElementById(id);if(el){el.value=v;el.dispatchEvent(new Event("input",{bubbles:true}));}}if(t){setv("username",t.bigfishUsername);setv("heading",t.bigfishTitle);setv("body",t.bigfishDesc);}var n=0;var iv=setInterval(function(){n++;var b=document.getElementById("play");if(b){b.click();clearInterval(iv);}else if(n>60){clearInterval(iv);}},100);}catch(e){}})();</script></body></html>
|
|
@@ -1 +1,14 @@
|
|
|
1
|
-
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>全境封锁 · 可编辑代码动画</title><link rel="stylesheet" href="style.css"><style>html,body{overflow:hidden;background:#000}main{display:block!important}aside{display:none!important}#stage{width:100vw;height:100vh;display:grid;place-items:center;background:#000}svg{width:100vw!important;height:100vh!important;max-height:none!important;display:block}</style></head><body><main><div id="stage"><svg id="scene" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080"><g id="tip"><path d="M615 222v-22q15-17 30 0v22zM620 201h20v18h-20zM626 189h9" fill="none" stroke="#aaa" stroke-width="2"/><text id="title" x="657" y="219" fill="#ccc" font-size="27"></text><path d="M606 232H1316M606 299H1316" stroke="#252525"/><foreignObject x="621" y="240" width="683" height="58"><div xmlns="http://www.w3.org/1999/xhtml" id="description"></div></foreignObject><path d="M596 256v19M1324 256v19" stroke="#999" stroke-width="2"/><rect x="624" y="313" width="45" height="16" fill="#555"/><text x="631" y="324" font-size="13" fill="#ccc">▏</text><text x="681" y="329" font-size="18" fill="#999">下一则</text><g id="pages"></g></g><g transform="translate(960 540)"><g id="rings"><circle id="pulse" r="10" fill="none" stroke="#70491a" stroke-width="2"/><circle id="pulseTrail" r="10" fill="none" stroke="#30250d" stroke-width="9"/><circle id="outerPulse" r="210" fill="none" stroke="#89521b" stroke-width="1"/><g id="ticks"></g><g id="outer"></g><g id="middle"></g><g id="inner"></g><g id="markers"></g><path id="progressArc" fill="none" stroke="#f29420" stroke-width="16"/><circle r="68" fill="none" stroke="#50340b" stroke-width="2"/></g><text id="percent" text-anchor="middle" y="9" fill="#bcbcbc" font-size="29" font-weight="300"></text></g><path id="statusArrow" d="M958 810l5 7 5-7" fill="#555"/><text id="status" x="960" y="853" text-anchor="middle" fill="#757575" font-size="25"></text><g id="statusDots" fill="#888"><rect x="951" y="792" width="3" height="3"/><rect x="960" y="787" width="3" height="3"/><rect x="967" y="796" width="3" height="3"/></g><g id="voice"></g></svg></div><aside><h1>可编辑代码动画</h1><label>连接用户名<input id="username"></label><label>提示标题<input id="heading"></label><label>提示正文<textarea id="body" rows="4"></textarea></label><div class="buttons"><button id="play">播放</button><button id="restart">从头播放</button><button id="fullscreen">全屏</button></div><label><span id="time">0.00 / 25.90 秒</span><input id="seek" type="range" min="0" max="25.9" step="0.016667" value="0"></label><div class="buttons"><button id="connection">查看连接阶段</button><button id="loading">查看加载阶段</button><button id="prevFrame">上一帧</button><button id="nextFrame">下一帧</button></div><hr><label>导入语音<input id="file" type="file" accept="audio/*"></label><label>语音开始时间(秒)<input id="voiceStart" type="number" min="0" step="0.1" value="9.2"></label><label>语音框距“加载中”的间隔<input id="gap" type="range" min="12" max="100" step="1" value="55"></label><p id="audioInfo">尚未导入语音,波形静止。语音框在加载阶段出现。</p><div class="buttons"><button id="save">保存设置 JSON</button><button id="reset">恢复默认</button></div><p>文字即时生效并保存在当前浏览器。时间轴、圆环和刻度均由参数生成。</p></aside></main><audio id="audio"></audio><div id="egg" aria-hidden="true"><img id="egg-bg" src="assets/egg-bg.png" alt=""><div id="egg-veil"></div><div id="egg-card" role="alertdialog"><div class="egg-head"><span class="egg-badge">!</span><span class="egg-title">错误</span></div><div class="egg-msg">《战术大肥鱼®》服务目前无法使用,请点击重试按钮。<div class="egg-code"><span>DELTA</span><span>C-0-1302</span></div></div><div class="egg-actions"><button id="egg-retry" type="button">重新连接</button></div></div></div><
|
|
1
|
+
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>全境封锁 · 可编辑代码动画</title><link rel="stylesheet" href="style.css"><style>html,body{overflow:hidden;background:#000}main{display:block!important}aside{display:none!important}#stage{width:100vw;height:100vh;display:grid;place-items:center;background:#000}svg{width:100vw!important;height:100vh!important;max-height:none!important;display:block}</style></head><body><main><div id="stage"><svg id="scene" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080"><g id="tip"><path d="M615 222v-22q15-17 30 0v22zM620 201h20v18h-20zM626 189h9" fill="none" stroke="#aaa" stroke-width="2"/><text id="title" x="657" y="219" fill="#ccc" font-size="27"></text><path d="M606 232H1316M606 299H1316" stroke="#252525"/><foreignObject x="621" y="240" width="683" height="58"><div xmlns="http://www.w3.org/1999/xhtml" id="description"></div></foreignObject><path d="M596 256v19M1324 256v19" stroke="#999" stroke-width="2"/><rect x="624" y="313" width="45" height="16" fill="#555"/><text x="631" y="324" font-size="13" fill="#ccc">▏</text><text x="681" y="329" font-size="18" fill="#999">下一则</text><g id="pages"></g></g><g transform="translate(960 540)"><g id="rings"><circle id="pulse" r="10" fill="none" stroke="#70491a" stroke-width="2"/><circle id="pulseTrail" r="10" fill="none" stroke="#30250d" stroke-width="9"/><circle id="outerPulse" r="210" fill="none" stroke="#89521b" stroke-width="1"/><g id="ticks"></g><g id="outer"></g><g id="middle"></g><g id="inner"></g><g id="markers"></g><path id="progressArc" fill="none" stroke="#f29420" stroke-width="16"/><circle r="68" fill="none" stroke="#50340b" stroke-width="2"/></g><text id="percent" text-anchor="middle" y="9" fill="#bcbcbc" font-size="29" font-weight="300"></text></g><path id="statusArrow" d="M958 810l5 7 5-7" fill="#555"/><text id="status" x="960" y="853" text-anchor="middle" fill="#757575" font-size="25"></text><g id="statusDots" fill="#888"><rect x="951" y="792" width="3" height="3"/><rect x="960" y="787" width="3" height="3"/><rect x="967" y="796" width="3" height="3"/></g><g id="voice"></g><text id="subtitle" x="960" y="944" text-anchor="middle" fill="#e9d6b8" font-size="24" letter-spacing="1" opacity="0" style="transition:opacity .22s ease;pointer-events:none"></text></svg></div><aside><h1>可编辑代码动画</h1><label>连接用户名<input id="username"></label><label>提示标题<input id="heading"></label><label>提示正文<textarea id="body" rows="4"></textarea></label><div class="buttons"><button id="play">播放</button><button id="restart">从头播放</button><button id="fullscreen">全屏</button></div><label><span id="time">0.00 / 25.90 秒</span><input id="seek" type="range" min="0" max="25.9" step="0.016667" value="0"></label><div class="buttons"><button id="connection">查看连接阶段</button><button id="loading">查看加载阶段</button><button id="prevFrame">上一帧</button><button id="nextFrame">下一帧</button></div><hr><label>导入语音<input id="file" type="file" accept="audio/*"></label><label>语音开始时间(秒)<input id="voiceStart" type="number" min="0" step="0.1" value="9.2"></label><label>语音框距“加载中”的间隔<input id="gap" type="range" min="12" max="100" step="1" value="55"></label><p id="audioInfo">尚未导入语音,波形静止。语音框在加载阶段出现。</p><div class="buttons"><button id="save">保存设置 JSON</button><button id="reset">恢复默认</button></div><p>文字即时生效并保存在当前浏览器。时间轴、圆环和刻度均由参数生成。</p></aside></main><audio id="audio"></audio><div id="egg" aria-hidden="true"><img id="egg-bg" src="assets/egg-bg.png" alt=""><div id="egg-veil"></div><div id="egg-card" role="alertdialog"><div class="egg-head"><span class="egg-badge">!</span><span class="egg-title">错误</span></div><div class="egg-msg">《战术大肥鱼®》服务目前无法使用,请点击重试按钮。<div class="egg-code"><span>DELTA</span><span>C-0-1302</span></div></div><div class="egg-actions"><button id="egg-retry" type="button">重新连接</button></div></div></div><div id="login" aria-hidden="true">
|
|
2
|
+
<div class="login-grid"></div>
|
|
3
|
+
<div class="login-scanlines"></div>
|
|
4
|
+
<div class="login-frame">
|
|
5
|
+
<div class="login-meta"><span>DSH // SECURE ACCESS</span><span>CHANNEL 02 · AUTH</span></div>
|
|
6
|
+
<div id="login-line1" class="login-line1"></div>
|
|
7
|
+
<div id="login-line2" class="login-line2">
|
|
8
|
+
<span id="login-l2-track" class="login-l2-track"><span id="login-l2-head" class="login-l2-head"><span class="login-scan-wrap"><span id="login-scan-text">正在登录</span><i id="login-scan-bar"></i></span><span id="login-colon">:</span></span><span id="login-name"></span><i id="login-caret"></i></span>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="login-meta login-foot"><span>AUTH MODULE v2.16</span><span>DEEPSEEK HARNESS</span></div>
|
|
11
|
+
</div>
|
|
12
|
+
<svg id="login-voice-layer" class="login-voice-layer" viewBox="0 0 1920 1080" preserveAspectRatio="xMidYMid slice" aria-hidden="true"><g id="login-voice"></g><text id="login-voice-sub" fill="#e9d6b8" font-family="'DIN Alternate','Bahnschrift','Microsoft YaHei',sans-serif"></text></svg>
|
|
13
|
+
</div>
|
|
14
|
+
<script src="config.js"></script><script src="voice.js"></script><script src="voice-env.js"></script><script src="motion.js"></script><script src="app.js"></script><script>(function(){var q=new URLSearchParams(location.search);setTimeout(function(){var A=window.__DSH_APP__,s=document.getElementById('seek');if(!A)return;window.__HOLD__=parseFloat(q.get('hold')||'0')||0;window.__VTIME__=q.has('vtime')?parseFloat(q.get('vtime')):null;window.__VSCHED__=q.has('demo')?[{key:'reconnect',at:10.7333,dur:2.821},{key:'line3',at:14.054,dur:3.3},{key:'orig3',at:21.5667,dur:2.77}]:null;window.__DEMO_SCHED__=null;var tv=parseFloat(q.get('t')||'0');if(s){s.value=Math.max(0,Math.min(25.9,tv));s.dispatchEvent(new Event('input',{bubbles:true}));}A.pause();if(q.has('egg')){var et=parseFloat(q.get('eggt')||'0');if(A.eggFrame)A.eggFrame(et);}else if(q.has('play')){A.play();}},240);})();</script></body></html>
|
|
@@ -16,3 +16,30 @@
|
|
|
16
16
|
#egg-retry{min-width:280px;padding:14px 26px;background:#15171a;border:1px solid rgba(255,255,255,.35);color:#e8e8e8;font-size:20px;letter-spacing:4px;cursor:pointer}
|
|
17
17
|
#egg-retry:hover{border-color:#f09a2e;color:#fff;background:#1b1d21}
|
|
18
18
|
body.egg-on #skip{display:none!important}
|
|
19
|
+
|
|
20
|
+
/* ===== v2.16.0:登录 ID 动画(整体缩到原来的 1/3) ===== */
|
|
21
|
+
#scene{transition:opacity .35s ease}
|
|
22
|
+
#login{position:fixed;inset:0;z-index:70;display:none;overflow:hidden;background:radial-gradient(700px 410px at 50% 42%,#0b0a08 0%,#050505 58%,#000 100%);opacity:0;transition:opacity .35s ease;pointer-events:none}
|
|
23
|
+
#login.on{display:block;opacity:1}
|
|
24
|
+
.login-grid{position:absolute;inset:0;background-image:linear-gradient(rgba(240,138,29,.055) 1px,transparent 1px),linear-gradient(90deg,rgba(240,138,29,.055) 1px,transparent 1px);background-size:48px 48px;-webkit-mask-image:radial-gradient(circle at 50% 45%,#000 0%,transparent 72%);mask-image:radial-gradient(circle at 50% 45%,#000 0%,transparent 72%);pointer-events:none}
|
|
25
|
+
.login-scanlines{position:absolute;inset:0;background:repeating-linear-gradient(to bottom,rgba(0,0,0,.22) 0 1px,transparent 1px 3px);pointer-events:none;opacity:.45}
|
|
26
|
+
.login-frame{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:min(500px,92vw);text-align:center;font-family:'Consolas','Courier New','Microsoft YaHei',monospace;color:#f08a1d}
|
|
27
|
+
.login-frame:before,.login-frame:after{content:'';position:absolute;width:18px;height:18px;border:1px solid rgba(240,138,29,.5);pointer-events:none}
|
|
28
|
+
.login-frame:before{left:-10px;top:-10px;border-right:0;border-bottom:0}
|
|
29
|
+
.login-frame:after{right:-10px;bottom:-10px;border-left:0;border-top:0}
|
|
30
|
+
.login-meta{display:flex;justify-content:space-between;font-size:clamp(5px,0.5vw,9px);letter-spacing:.22em;color:rgba(240,138,29,.55);text-transform:uppercase}
|
|
31
|
+
.login-line1{margin:clamp(6px,1vh,13px) 0 clamp(5px,.8vh,10px);font-size:clamp(9px,1.4vw,27px);font-weight:700;letter-spacing:.03em;white-space:nowrap;color:#f7a23a;text-shadow:0 0 7px rgba(240,138,29,.3)}
|
|
32
|
+
.login-line1 .l1c{display:inline-block;min-width:.32em}
|
|
33
|
+
.login-line2{position:relative;height:1.5em;font-size:clamp(7px,.9vw,17.3px);letter-spacing:.02em;white-space:nowrap;color:#ffb04d;text-shadow:0 0 6px rgba(240,138,29,.3)}
|
|
34
|
+
.login-l2-track{position:absolute;left:0;top:0;display:inline-flex;align-items:baseline;white-space:nowrap;will-change:transform}
|
|
35
|
+
.login-l2-head{display:inline-flex;align-items:baseline}
|
|
36
|
+
.login-scan-wrap{position:relative;display:inline-block;--p:0%;line-height:1}
|
|
37
|
+
#login-scan-text{display:inline-block;line-height:1;-webkit-mask-image:linear-gradient(to bottom,#000 0 var(--p),transparent var(--p));mask-image:linear-gradient(to bottom,#000 0 var(--p),transparent var(--p))}
|
|
38
|
+
#login-scan-bar{position:absolute;left:-3%;width:106%;height:1px;top:0;background:#ffb04d;box-shadow:0 0 5px 1px rgba(240,138,29,.85);pointer-events:none;opacity:0}
|
|
39
|
+
#login-colon{opacity:0}
|
|
40
|
+
#login-name{color:#f08a1d;display:inline-block;white-space:nowrap}
|
|
41
|
+
.login-line2 .nmc{display:inline-block;text-align:center;vertical-align:baseline;line-height:1}
|
|
42
|
+
.login-line2 .nmc.settled{color:#ffc36b}
|
|
43
|
+
#login-caret{display:inline-block;width:.09em;height:.9em;background:#f08a1d;margin-left:.08em;opacity:0;transform:translateY(.08em)}
|
|
44
|
+
.login-foot{margin-top:clamp(8px,1.4vh,18px);color:rgba(240,138,29,.45)}
|
|
45
|
+
.login-voice-layer{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:2}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schemaVersion": 1,
|
|
3
|
-
"id": "division-bigfish-codex",
|
|
4
|
-
"name": "全景大肥鱼-含彩蛋版",
|
|
5
|
-
"engine": "iframe",
|
|
6
|
-
"entry": "index.html",
|
|
7
|
-
"author": "LeeRolling",
|
|
8
|
-
"description": "全景大肥鱼风格的代码动画(含掉线彩蛋),五句配音可配效果。",
|
|
9
|
-
"duration":
|
|
10
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "division-bigfish-codex",
|
|
4
|
+
"name": "全景大肥鱼-含彩蛋版",
|
|
5
|
+
"engine": "iframe",
|
|
6
|
+
"entry": "index.html",
|
|
7
|
+
"author": "LeeRolling",
|
|
8
|
+
"description": "全景大肥鱼风格的代码动画(含掉线彩蛋),五句配音可配效果。",
|
|
9
|
+
"duration": 33.4
|
|
10
|
+
}
|
package/test/smoke-package.mjs
CHANGED
|
@@ -113,9 +113,40 @@ if (/resetPlayedAfter\(cfg\.loadingStart\)/.test(bigfishApp)) throw new Error('
|
|
|
113
113
|
if (!bigfishApp.includes('cueFailTimer')) throw new Error('重连提示音缺少播放失败的兜底解除门控')
|
|
114
114
|
/* v2.15.15:重连提示音也要走插件的配音效果;line3 顺延,避免和 line2 叠音 */
|
|
115
115
|
if (!bigfishApp.includes("attachVoiceFx('reconnect')")) throw new Error('重连提示音未接入配音效果')
|
|
116
|
-
if (!bigfishApp.includes("[
|
|
117
|
-
if (!bigfishCfg.includes("[
|
|
116
|
+
if (!bigfishApp.includes("[25.0,'line3',3.300]")) throw new Error('app.js 默认时间线未把 line3 顺延到 25.0s')
|
|
117
|
+
if (!bigfishCfg.includes("[25.0,'line3',3.300]")) throw new Error('config.js 时间线未把 line3 顺延到 25.0s')
|
|
118
118
|
/* v2.15.16:掉线彩蛋等当前配音播完再弹出,不硬切语音/字幕 */
|
|
119
119
|
if (!bigfishApp.includes('掉线彩蛋若正好赶上某句配音')) throw new Error('app.js 缺少彩蛋等待当前配音播完的逻辑')
|
|
120
120
|
if (!bigfishApp.includes('eggWait=true')) throw new Error('app.js 缺少 eggWait 等待状态')
|
|
121
|
+
/* v2.15.17:字幕/波形跟随配音真实播放时钟 */
|
|
122
|
+
if (!bigfishApp.includes('__DSH_AUDIO_T__')) throw new Error('app.js 缺少配音真实时钟镜像 __DSH_AUDIO_T__')
|
|
123
|
+
if (!bigfishApp.includes('function eggVoice(){')) throw new Error('app.js 彩蛋字幕未改为音频时钟驱动')
|
|
124
|
+
/* v2.16.0:配音串行播放 + 彩蛋尾部等待(1.5x 加速段避免叠音、最后一句不被截断) */
|
|
125
|
+
if (!bigfishApp.includes('配音串行播放')) throw new Error('app.js 缺少配音串行播放(防叠音)')
|
|
126
|
+
if (!bigfishApp.includes('!__busy')) throw new Error('app.js 未按前一句播完再启动下一句')
|
|
127
|
+
if (!bigfishApp.includes('eggLeft<=6')) throw new Error('app.js 彩蛋等待条件未覆盖动画尾部')
|
|
128
|
+
if (!bigfishApp.includes('!shown&&!eggWait')) throw new Error('app.js 动画收尾未等待彩蛋语音播完')
|
|
129
|
+
|
|
130
|
+
/* v2.16.0:第一节延长 5s + 插入登录 ID 动画;读取段整体后移 */
|
|
131
|
+
if (!bigfishCfg.includes('loginStart:9.2')) throw new Error('config.js 缺少 loginStart=9.2')
|
|
132
|
+
if (!bigfishCfg.includes('loginDur:5.0')) throw new Error('config.js 缺少 loginDur=5.0')
|
|
133
|
+
if (!bigfishCfg.includes("sched:[[4.6,'orig1',2.65],[9.8,'login',1.79],[14.5,'line1',3.375],[18.4,'line2',3.232],[25.0,'line3',3.300],[30.45,'orig3',2.77]]")) throw new Error('config.js 配音时间线未按三段时间轴重排')
|
|
134
|
+
if (!bigfishApp.includes("[14.5,'line1',3.375],[18.4,'line2',3.232]")) throw new Error('app.js 默认配音时间线未同步')
|
|
135
|
+
if (!bigfishApp.includes('var LOGIN=')) throw new Error('app.js 缺少登录 ID 动画模块')
|
|
136
|
+
if (!bigfishApp.includes('voiceVT')) throw new Error('app.js 缺少静音模式的配音时间轴换算 voiceVT')
|
|
137
|
+
if (!bigfishApp.includes('sanitize')) throw new Error('app.js 缺少用户名安全化处理')
|
|
138
|
+
if (!bigfishHtml.includes('id="login"') || !bigfishHtml.includes('id="login-line1"')) throw new Error('index.html 缺少登录 ID 动画节点')
|
|
139
|
+
if (!bigfishHtml.includes('login-scan-text') || !bigfishHtml.includes('login-name')) throw new Error('index.html 缺少登录动画扫描/用户名节点')
|
|
140
|
+
if (Number(tplJson.duration) !== 33.4) throw new Error('template.json duration 未更新为 33.4')
|
|
141
|
+
/* v2.16.0 第二版:5s 登录段、整体 1/3 尺寸、贝塞尔平移、第二段配音 */
|
|
142
|
+
if (!bigfishCfg.includes("login:'assets/voice-login.wav'")) throw new Error('config.js 缺少第二段登录配音资源')
|
|
143
|
+
if (!bigfishCfg.includes("login:'特工身份确认。'")) throw new Error('config.js 缺少登录配音中文字幕')
|
|
144
|
+
if (!fs.existsSync(path.join(root, 'templates/division-bigfish-codex/assets/voice-login.wav'))) throw new Error('缺少第二段登录配音 voice-login.wav')
|
|
145
|
+
if (!bigfishHtml.includes('login-l2-track')) throw new Error('index.html 缺少贝塞尔平移轨道 login-l2-track')
|
|
146
|
+
if (!bigfishHtml.includes('login-voice-layer')) throw new Error('index.html 缺少登录段配音行图层 login-voice-layer')
|
|
147
|
+
if (!bigfishApp.includes('function bezier(')) throw new Error('app.js 缺少贝塞尔缓动实现')
|
|
148
|
+
if (!bigfishApp.includes("track.style.transform='translateX('")) throw new Error('app.js 未用 track 平移实现平滑过渡')
|
|
149
|
+
if (!bigfishApp.includes("renderVoiceRow($('login-voice')")) throw new Error('app.js 登录段未使用配音行 renderVoiceRow')
|
|
150
|
+
if (!skipCss.includes('width:min(500px,92vw)')) throw new Error('style.css 登录框未缩到 1/3 尺寸')
|
|
151
|
+
|
|
121
152
|
console.log('ok package.json version=' + pkg.version + ',无 BOM,关键文件齐全(含更新前回滚 checkpoint)');
|
|
@@ -463,7 +463,7 @@ ok(intervals.every((t) => t.cleared) || intervals.length === 0, '旧的 interval
|
|
|
463
463
|
intervals.map((t) => (t.cleared ? 'cleared' : 'live')).join(','))
|
|
464
464
|
|
|
465
465
|
console.log('\n=== ⑦ v2.13.0 测试钩子 / BUILD ===')
|
|
466
|
-
ok(mod.__BUILD === 'cw-
|
|
466
|
+
ok(mod.__BUILD === 'cw-66', '__BUILD = cw-66(排查浏览器跑的是不是新包)', String(mod.__BUILD))
|
|
467
467
|
ok(mod.__VIDEO_ID === 'dsh-cw-video', '__VIDEO_ID = dsh-cw-video', String(mod.__VIDEO_ID))
|
|
468
468
|
ok(typeof mod.__startShuffle === 'function', '__startShuffle 导出')
|
|
469
469
|
ok(typeof mod.__stopShuffle === 'function', '__stopShuffle 导出')
|
package/tools/build-release.mjs
CHANGED
|
@@ -8,7 +8,7 @@ const stage = fs.mkdtempSync(path.join(os.tmpdir(), 'dsh-release-'));
|
|
|
8
8
|
const out = path.join(root, '..', '03-发布包', 'dsh-boot-suite-win.zip');
|
|
9
9
|
/* code-motion:另一条工作线(动效研究/验证)的文档与媒体,不属于插件本体,发布包不打包 */
|
|
10
10
|
/* docs:主线(编辑器重制/风格库/演示素材)文档与媒体,体积可能非常大(GB 级),不属于插件运行必需,发布包不打包 */
|
|
11
|
-
const skip = new Set(['.git', 'node_modules', '08-备份', 'code-motion', 'docs']);
|
|
11
|
+
const skip = new Set(['.git', 'node_modules', '08-备份', 'code-motion', 'docs', '02-文档', '03-发布包']);
|
|
12
12
|
function copy(src, dst) {
|
|
13
13
|
fs.mkdirSync(dst, { recursive: true });
|
|
14
14
|
for (const e of fs.readdirSync(src, { withFileTypes: true })) {
|