state / harness / camera / pick / ui / sheets / render / urlparams。 经典脚本的顶层 const/let 落在同一个全局词法作用域,所以切片本身不改变任何行为—— 这一步先让"文件边界"与"模块语义"两件事分离:翻 ESM 时若出问题,责任清楚在 import/export,而不是切片切错了行。 切片踩到并修掉的:urlparams.js 被切掉了 IIFE 的收尾 })();(我按 len-2 收边界), node --check 当场报 Unexpected end of input。 截图基线分级也在这一步收敛:工程图/装配向导视图带 feGaussianBlur 发光滤镜, 同一构建两轮就有 ±1 抖动(先前扫描那两轮碰巧逐字节相同,才漏进"稳定"清单, 于是随机假 FAIL)。把 8 张工程图/向导视图连同 3 张线束 x-ray、boss_p07、 p03_mount_loose 一起转像素容差(存参考像素,阈值 mean<=0.02、单像素<=32, 约实测 20x 余量),其余 92 张仍要求逐字节相同。 关卡:92 张逐字节一致 + 13 张在噪声阈内;数据哈希与 IK exact 段一致。
65 lines
2.9 KiB
JavaScript
65 lines
2.9 KiB
JavaScript
/* URL 参数驱动的视图状态(供截图与分享复现) */
|
|
/* ---- url params so views can be scripted / shared: ?expl=60&j1=20&cam=iso&xray=0 ---- */
|
|
(function(){
|
|
const q = new URLSearchParams(location.search);
|
|
if (q.has('expl')) { exp.value = q.get('expl'); setExpl(+exp.value/100);
|
|
if (+exp.value) tog(false, true); }
|
|
for (const id of JNAMES) {
|
|
const k = id.toLowerCase();
|
|
if (q.has(k)) { const el = document.getElementById('s'+id);
|
|
el.value = q.get(k); el.dispatchEvent(new Event('input')); }
|
|
}
|
|
if (q.has('cam')) { const s = document.getElementById('cam'); s.value = q.get('cam'); s.dispatchEvent(new Event('change')); }
|
|
if (q.has('az')) az = +q.get('az');
|
|
if (q.has('po')) po = +q.get('po');
|
|
if (q.has('rd')) rd = +q.get('rd');
|
|
if (q.has('tx')) tx = +q.get('tx');
|
|
if (q.has('ty')) ty = +q.get('ty');
|
|
if (q.has('tz')) tz = +q.get('tz');
|
|
if (q.get('env') === '1') { const b = document.getElementById('bEnv');
|
|
if (b && !b.classList.contains('on')) b.onclick(); }
|
|
if (q.get('xray') === '0') { const b = document.getElementById('bXRay'); if (b && b.classList.contains('on')) b.onclick(); }
|
|
if (q.get('xray') === '1') { const b = document.getElementById('bXRay'); if (b && !b.classList.contains('on')) b.onclick(); }
|
|
if (q.get('wire') === '1') { const b = document.getElementById('bWire'); if (b && !b.classList.contains('on')) b.onclick(); }
|
|
if (q.has('alpha')) {
|
|
const a = +q.get('alpha');
|
|
meshes.forEach(m => {
|
|
if (m.userData.printed) {
|
|
m.material.transparent = true;
|
|
m.material.opacity = a;
|
|
m.material.depthWrite = a > 0.8;
|
|
}
|
|
});
|
|
}
|
|
if (q.get('harn') === '0') { const b = document.getElementById('bHarn'); if (b && b.classList.contains('on')) b.onclick(); }
|
|
/* 视图模式与工程图状态也要能用 URL 驱动:否则工程图/装配向导这两种模式(约占一半
|
|
CSS 与 700 行 JS)没法用 headless 截图回归,改动只能靠人眼抽查。 */
|
|
if (q.has('view')) {
|
|
const t = document.querySelector('.tab[data-view="' + q.get('view') + '"]');
|
|
if (t) t.click();
|
|
}
|
|
if (q.has('sheet')) {
|
|
const b = document.querySelector('#sheetTabs .sheet-tab[data-sheet="' + q.get('sheet') + '"]');
|
|
if (b) b.click();
|
|
}
|
|
if (q.has('theme')) {
|
|
const b = document.querySelector('.sheet-btn[data-theme="' + q.get('theme') + '"]');
|
|
if (b) b.click();
|
|
}
|
|
if (q.has('guide')) { const g = +q.get('guide'); if (isFinite(g)) renderGuideStep(g); }
|
|
if (q.has('j6')) { const el = document.getElementById('sJ6');
|
|
if (el) { el.value = q.get('j6'); el.dispatchEvent(new Event('input')); } }
|
|
if (q.has('hide')) {
|
|
const h = q.get('hide').split(',');
|
|
meshes.forEach(m => {
|
|
const nm = (m.userData && m.userData.name) || '';
|
|
const cn = (m.userData && m.userData.cn) || '';
|
|
if (h.some(k => nm.includes(k) || cn.includes(k))) {
|
|
m.visible = false;
|
|
if (m.chk) m.chk.checked = false;
|
|
}
|
|
});
|
|
}
|
|
requestRender();
|
|
})();
|