差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
en:stpc-exxx-c [2026/11/14 00:30]
wjj 5.12.1 add the Docker image FTP download link (from ShowDoc), drop 'provided separately by us'
en:stpc-exxx-c [2026/11/14 03:52] (当前版本)
wjj 3D 透视配色与透明度终值:蓝灰鬼影 + 内部零件加重
行 276: 行 276:
   #bodyContent .sml-doc p.sml-note{min-width:min(100%,240px)!important;}   #bodyContent .sml-doc p.sml-note{min-width:min(100%,240px)!important;}
 } }
 +.sml-3d{position:absolute;inset:0;display:none;z-index:4;background:#f3f6fa;}.sml-g-stage.on3d{height:430px;}.sml-g-stage.on3d>*:not(.sml-3d){visibility:hidden;}.sml-g-stage.on3d .sml-3d{display:block;}.sml-g-side.on3d{justify-content:flex-start;}.sml-g-side.on3d button.sml-g-thumb{flex:0 0 auto;min-height:38px;}button.sml-g-thumb[data-3d] svg{display:block;width:100%;height:100%;}@media (max-width:900px){.sml-g-stage.on3d{height:330px;}.sml-g-side{flex-wrap:wrap!important;gap:4px!important;}button.sml-g-thumb{flex:1 1 calc(33.333% - 3px)!important;min-width:0;}.sml-g-side.on3d button.sml-g-thumb{min-height:44px;}.sml-g-cap{max-width:calc(100% - 78px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}}
 +.sml-g-side{flex:0 0 168px;}
 </style></html> </style></html>
 <html><script> <html><script>
行 399: 行 401:
 <div class="sml-gallery"> <div class="sml-gallery">
 <div class="sml-g-head"><div><div class="sml-g-kicker">PRODUCT GALLERY / Product Gallery</div><div class="sml-g-title">sTPC-EXXX-C Series · Unit Appearance</div></div><div class="sml-g-note">Using the E156 model as an example · Click a view on the right to switch</div></div> <div class="sml-g-head"><div><div class="sml-g-kicker">PRODUCT GALLERY / Product Gallery</div><div class="sml-g-title">sTPC-EXXX-C Series · Unit Appearance</div></div><div class="sml-g-note">Using the E156 model as an example · Click a view on the right to switch</div></div>
-<div class="sml-g-body"><div class="sml-g-stage"><img id="sml-g-main" class="sml-g-main" src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" alt="Front View · Multi-Point Capacitive Touch Screen"><div class="sml-g-badge">INDUSTRIAL PANEL PC</div><a id="sml-g-zoom" class="sml-g-zoom" href="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" target="_blank" rel="noopener">View Full-Resolution Image ↗</a><div class="sml-g-cap" id="sml-g-cap">Front View · Multi-Point Capacitive Touch Screen</div><div class="sml-g-count" id="sml-g-count">01 / 04</div></div><div class="sml-g-side"><div class="sml-g-side-hd">Unit Views / 04 VIEWS</div><button type="button" class="sml-g-thumb on" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" data-idx="01" data-cap="Front View · Multi-Point Capacitive Touch Screen"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_01.jpg" alt="Front View"></span><span class="sml-g-tx"><b>VIEW 01</b>Front View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp.jpg" data-idx="02" data-cap="Perspective View · Unit Structure and Rear Main Bay"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_02.jpg" alt="Perspective View"></span><span class="sml-g-tx"><b>VIEW 02</b>Perspective View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back.jpg" data-idx="03" data-cap="Rear View · Fully Sealed Rear Cover and VESA Holes"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_03.jpg" alt="Rear View"></span><span class="sml-g-tx"><b>VIEW 03</b>Rear View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io.jpg" data-idx="04" data-cap="Interface View · External I/O Concentrated on the Lower Rear"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_04.jpg" alt="Interface View"></span><span class="sml-g-tx"><b>VIEW 04</b>Interface View</span></button></div></div>+<div class="sml-g-body"><div class="sml-g-stage"><img id="sml-g-main" class="sml-g-main" src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" alt="Front View · Multi-Point Capacitive Touch Screen"><div class="sml-g-badge">INDUSTRIAL PANEL PC</div><a id="sml-g-zoom" class="sml-g-zoom" href="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" target="_blank" rel="noopener">View Full-Resolution Image ↗</a><div class="sml-3d" id="sml-3d"></div><div class="sml-g-cap" id="sml-g-cap">Front View · Capacitive Touch Panel</div><div class="sml-g-count" id="sml-g-count">01 / 05</div></div><div class="sml-g-side"><div class="sml-g-side-hd">Unit Views / 05 VIEWS</div><button type="button" class="sml-g-thumb on" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" data-idx="01" data-cap="Front View · Capacitive Touch Panel"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_01.jpg" alt="Front View"></span><span class="sml-g-tx"><b>SLC</b>Front View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp.jpg" data-idx="02" data-cap="Perspective View · Main Module"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_02.jpg" alt="Perspective View"></span><span class="sml-g-tx"><b>SLC</b>Perspective View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back.jpg" data-idx="03" data-cap="Rear View · Mounting Back Plate"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_03.jpg" alt="Rear View"></span><span class="sml-g-tx"><b>SLC</b>Rear View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io.jpg" data-idx="04" data-cap="Interface View · Power and Network"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_04.jpg" alt="Interface View"></span><span class="sml-g-tx"><b>SLC</b>Interface View</span></button> 
 +<button type="button" class="sml-g-thumb" data-3d="1" data-idx="05" data-zip="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_3d.zip" data-lang="en" data-size="about 3.4 MB" data-rear="0" data-parts="[[&quot;后壳&quot;,&quot;Rear Shell&quot;,&quot;#eef2f5&quot;,1.25,-1],[&quot;前框&quot;,&quot;Front Bezel&quot;,&quot;#e6ebef&quot;,1.55,1],[&quot;显示模组&quot;,&quot;Display Module&quot;,&quot;#0b1015&quot;,1.0,1],[&quot;角部盖板&quot;,&quot;Corner Plate&quot;,&quot;#e2e8ed&quot;,1.7,1],[&quot;触摸屏&quot;,&quot;Touch Panel&quot;,&quot;#151d26&quot;,1.8,1],[&quot;前视窗玻璃&quot;,&quot;Front Glass&quot;,&quot;#0a0d11&quot;,1.95,1],[&quot;主板组件&quot;,&quot;Main Board&quot;,&quot;#2f6f59&quot;,0.7,-1],[&quot;连接器&quot;,&quot;Connector&quot;,&quot;#a45a52&quot;,0.35,-1],[&quot;接口座&quot;,&quot;I/O Socket&quot;,&quot;#a45a52&quot;,0.4,-1],[&quot;接口板&quot;,&quot;I/O Board&quot;,&quot;#2f6f59&quot;,0.5,-1],[&quot;屏蔽板&quot;,&quot;Shield Plate&quot;,&quot;#dfe5ea&quot;,0.5,-1],[&quot;按键座&quot;,&quot;Button Seat&quot;,&quot;#a45a52&quot;,0.35,-1],[&quot;导光件&quot;,&quot;Light Guide&quot;,&quot;#c9a227&quot;,0.3,-1],[&quot;紧固件&quot;,&quot;Fastener&quot;,&quot;#9aa4b0&quot;,0.2,-1],[&quot;显示面板&quot;,&quot;Display Panel&quot;,&quot;#0a0e12&quot;,2.0,1]]" data-cap="3D Teardown · Part Structure"><span class="sml-g-tn"><svg viewBox="0 0 44 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><g fill="none" stroke="#0b5394" stroke-width="1.3" stroke-linejoin="round"><path d="M12 8 L22 3 L32 8 L22 13 Z"/><path d="M12 8 L12 20 L22 25 L22 13"/><path d="M32 8 L32 20 L22 25"/><path d="M17 5.5 L27 10.5" stroke="#8fb2d6" stroke-width="1"/></g></svg></span><span class="sml-g-tx"><b>SLC</b>3D Teardown</span></button></div></div>
 <div class="sml-g-specs"><div class="sml-g-spec"><b>RK3568 / 3576 / 3588</b><em>Three Platforms · up to 6 TOPS NPU</em></div><div class="sml-g-spec"><b>10.1″–21.5″</b><em>Six Sizes · Capacitive Touch</em></div><div class="sml-g-spec"><b>Fanless Fully Sealed</b><em>VESA / Embedded Mounting</em></div><div class="sml-g-spec"><b>Wide-Range Power</b><em>DC 12~24V ±10%</em></div></div> <div class="sml-g-specs"><div class="sml-g-spec"><b>RK3568 / 3576 / 3588</b><em>Three Platforms · up to 6 TOPS NPU</em></div><div class="sml-g-spec"><b>10.1″–21.5″</b><em>Six Sizes · Capacitive Touch</em></div><div class="sml-g-spec"><b>Fanless Fully Sealed</b><em>VESA / Embedded Mounting</em></div><div class="sml-g-spec"><b>Wide-Range Power</b><em>DC 12~24V ±10%</em></div></div>
 <div class="sml-g-apps"><span class="t">Typical Applications</span><span class="chip">Production Line Dashboard</span><span class="chip">Equipment HMI</span><span class="chip">Self-Service Query Terminal</span><span>Long-Term Stable Operation in Industrial Sites</span></div> <div class="sml-g-apps"><span class="t">Typical Applications</span><span class="chip">Production Line Dashboard</span><span class="chip">Equipment HMI</span><span class="chip">Self-Service Query Terminal</span><span>Long-Term Stable Operation in Industrial Sites</span></div>
行 1947: 行 1950:
 Use a ready-made build image; the host does not need Qt installed, isolation is good, and it suits batch compilation. Use a ready-made build image; the host does not need Qt installed, isolation is good, and it suits batch compilation.
  
-**Download:** [[ftp://drv.nodka.com/arm_download/nodka_docker_qt_build_20230223.tar|nodka_docker_qt_build_20230223.tar]] — company FTP (drv.nodka.com), approx. 4.3 GB+**Download:** [[ftp://drv.nodka.com/arm_download/nodka_docker_qt_build_20230223.tar|nodka_docker_qt_build_20230223.tar]] — company FTP (drv.nodka.com)
  
   - Import the image   - Import the image
行 1963: 行 1966:
 </code> </code>
  
-**Note:** The image is about 4.3 GB; after import the image and the original tar each take a copy, so reserve at least 10 GB of free disk. Chrome / Edge no longer open ftp:// links directly — use Windows Explorer, FileZilla or a download manager instead. The container ID (09a37c1b2fc3) is taken from the actual docker images output.+**Note:** The image is large; after import the image and the original tar each take a copy, so reserve at least 10 GB of free disk. Chrome / Edge no longer open ftp links directly — use Windows Explorer, FileZilla or a download manager instead. The container ID (09a37c1b2fc3) is taken from the actual docker images output.
  
 === 5.12.2 Set Up the Qt Build Environment on the Board === === 5.12.2 Set Up the Qt Build Environment on the Board ===
行 2434: 行 2437:
 } }
 </style></html> </style></html>
 +<html><script>
 +/* sTPC 3D 拆解查看器(嵌入版,无外部依赖)
 +   用法:SML3D(hostElement, {url:'...zip', lang:'zh', ...}) */
 +window.SML3D = (function(){
 +"use strict";
 +
 +/* ===== 默认零件表(仅 sTPC-S156-3568B;其它机型由 cfg.parts 传入) ===== */
 +var PARTS_S156 = [
 +  /* 0 */ {n:'机身中框',   e:'Mid Frame',        col:'#b8c2cd', k:0.00, d:[0,0,0]},
 +  /* 1 */ {n:'视窗玻璃',   e:'Front Glass',      col:'#1e2a36', k:1.55, d:[0,0,1]},
 +  /* 2 */ {n:'显示模组',   e:'Display Module',   col:'#3f4d5c', k:1.05, d:[0,0,1]},
 +  /* 3 */ {n:'后盖',       e:'Rear Cover',       col:'#d4dae1', k:1.45, d:[0,0,-1]},
 +  /* 4 */ {n:'主板载板',   e:'Carrier Board',    col:'#2f6f59', k:0.55, d:[0,0,1]},
 +  /* 5 */ {n:'屏线组件',   e:'Panel Cable',      col:'#c9a227', k:0.55, d:[0,0,1]},
 +  /* 6 */ {n:'天线/顶条',  e:'Antenna Bar',      col:'#7b5ea7', k:0.60, d:[0,0,-1]},
 +  /* 7 */ {n:'固定卡扣',   e:'Clip',             col:'#8e99a6', k:0.30, d:[0,0,-1]},
 +  /* 8 */ {n:'固定卡扣',   e:'Clip',             col:'#8e99a6', k:0.30, d:[0,0,-1]},
 +  /* 9 */ {n:'紧固件',     e:'Fastener',         col:'#8e99a6', k:0.30, d:[0,0,-1]},
 +  /*10 */ {n:'下侧接口座', e:'I/O Block',        col:'#a45a52', k:0.45, d:[0,0,-1]},
 +  /*11 */ {n:'接地弹片',   e:'Ground Spring',    col:'#9aa4b0', k:0.20, d:[0,0,-1]},
 +  /*12 */ {n:'竖向排线',   e:'Vertical FPC',     col:'#c9a227', k:0.45, d:[0,0,-1]},
 +  /*13 */ {n:'接地弹片',   e:'Ground Spring',    col:'#9aa4b0', k:0.20, d:[0,0,-1]},
 +  /*14 */ {n:'喇叭',       e:'Speaker',          col:'#a45a52', k:0.45, d:[0,0,-1]},
 +  /*15 */ {n:'主板组件',   e:'Main Board',       col:'#2f6f5c', k:0.75, d:[0,0,-1]},
 +  /*16 */ {n:'前面框',     e:'Front Bezel',      col:'#cbd3dc', k:1.75, d:[0,0,1]}
 +];
 +var REAR_S156 = 3;                  /* 后盖索引 */
 +
 +var UI = {
 +  zh:{open:'打开后盖', close:'装回后盖', xray:'透视', parts:'零件', front:'前视', back:'后视',
 +      side:'侧视', iso:'等轴', reset:'重置', exp:'拆解', hint:'拖拽旋转 · 滚轮缩放 · 点击零件查看',
 +      load:'加载 3D 模型', loading:'正在载入 3D 模型…', size:'约 1.3 MB', all:'全部显示',
 +      faces:'面数', dim:'尺寸', err:'模型载入失败', sorry:'当前浏览器不支持 WebGL,请用 Chrome / Edge 打开'},
 +  en:{open:'Open cover', close:'Close cover', xray:'X-ray', parts:'Parts', front:'Front', back:'Rear',
 +      side:'Side', iso:'Iso', reset:'Reset', exp:'Explode', hint:'Drag to orbit · Scroll to zoom · Click a part',
 +      load:'Load 3D model', loading:'Loading 3D model…', size:'about 1.3 MB', all:'Show all',
 +      faces:'Faces', dim:'Size', err:'Failed to load model', sorry:'WebGL is not available; please use Chrome or Edge'}
 +};
 +
 +var CSS = ''
 ++ '.v3d{position:absolute;inset:0;overflow:hidden;background:radial-gradient(120% 105% at 50% 0%,#fdfefe 0%,#eaeef3 52%,#d9dfe7 100%);font:400 12px/1.45 "Segoe UI","Microsoft YaHei",sans-serif;}'
 ++ '.v3d canvas{display:block;width:100%;height:100%;cursor:grab;touch-action:none;}'
 ++ '.v3d canvas:active{cursor:grabbing;}'
 ++ '.v3d .tbar{position:absolute;left:9px;top:9px;display:flex;gap:5px;flex-wrap:wrap;max-width:calc(100% - 18px);}'
 ++ '.v3d .tb{font:inherit;font-size:11.5px;padding:3px 9px;border:1px solid #c6d0da;background:rgba(255,255,255,.94);color:#26313c;border-radius:3px;cursor:pointer;white-space:nowrap;}'
 ++ '.v3d .tb:hover{background:#eef6fd;border-color:#84aede;}'
 ++ '.v3d .tb.on{background:#0b5394;border-color:#0b5394;color:#fff;}'
 ++ '.v3d .tb.hot{border-color:#0b7a75;color:#0b7a75;}'
 ++ '.v3d .tb.hot.on{background:#0b7a75;color:#fff;}'
 ++ '.v3d .ebar{position:absolute;left:9px;right:9px;bottom:8px;display:flex;align-items:center;gap:8px;padding:5px 9px;background:rgba(255,255,255,.9);border:1px solid #dbe2ea;border-radius:3px;}'
 ++ '.v3d .ebar input{flex:1;height:3px;-webkit-appearance:none;appearance:none;background:#cfd8e2;border-radius:2px;outline:none;}'
 ++ '.v3d .ebar input::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;border-radius:50%;background:#0b5394;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.25);}'
 ++ '.v3d .ebar .lb{font-size:11px;color:#4a5765;white-space:nowrap;}'
 ++ '.v3d .ebar .pv{font-size:11px;color:#0b5394;font-variant-numeric:tabular-nums;min-width:30px;text-align:right;}'
 ++ '.v3d .hint{position:absolute;right:9px;bottom:44px;font-size:10.5px;color:#6b7681;background:rgba(255,255,255,.82);padding:2px 7px;border-radius:2px;}'
 ++ '.v3d .plist{position:absolute;right:9px;top:44px;width:150px;max-height:calc(100% - 96px);overflow:auto;background:rgba(255,255,255,.96);border:1px solid #cbd4de;border-radius:4px;padding:5px;display:none;box-shadow:0 6px 18px rgba(20,40,60,.14);}'
 ++ '.v3d .plist.on{display:block;}'
 ++ '.v3d .pi{display:flex;align-items:center;gap:6px;padding:3px 5px;border-radius:3px;cursor:pointer;font-size:11.5px;color:#26313c;}'
 ++ '.v3d .pi:hover{background:#eef6fd;}'
 ++ '.v3d .pi.sel{background:#dbeafb;box-shadow:inset 2px 0 0 #0b5394;}'
 ++ '.v3d .pi.off{opacity:.36;}'
 ++ '.v3d .pi i{width:9px;height:9px;border-radius:2px;flex:0 0 9px;border:1px solid rgba(0,0,0,.2);}'
 ++ '.v3d .pi span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}'
 ++ '.v3d .tip{position:absolute;padding:5px 9px;background:rgba(23,32,42,.92);color:#fff;font-size:11px;border-radius:3px;pointer-events:none;display:none;max-width:190px;line-height:1.5;}'
 ++ '.v3d .tip.on{display:block;}'
 ++ '.v3d .tip b{color:#8fc2ff;font-weight:600;}'
 ++ '.v3d .cover{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:9px;background:rgba(255,255,255,.92);}'
 ++ '.v3d .cover .b{font:inherit;font-size:12.5px;padding:7px 16px;border:1px solid #0b5394;background:#0b5394;color:#fff;border-radius:3px;cursor:pointer;}'
 ++ '.v3d .cover .b:hover{background:#0a4880;}'
 ++ '.v3d .cover .s{font-size:11px;color:#78838f;}'
 ++ '.v3d .bar{width:150px;height:3px;background:#dde4ec;border-radius:2px;overflow:hidden;}'
 ++ '.v3d .bar>i{display:block;height:100%;width:6%;background:#0b5394;transition:width .18s;}';
 +
 +/* ===== 数学 ===== */
 +function persp(f,a,n,r){var t=1/Math.tan(f/2),d=1/(n-r);return new Float32Array([t/a,0,0,0,0,t,0,0,0,0,(r+n)*d,-1,0,0,2*r*n*d,0]);}
 +function look(e,c,u){
 +  var zx=e[0]-c[0],zy=e[1]-c[1],zz=e[2]-c[2],zl=Math.hypot(zx,zy,zz)||1;zx/=zl;zy/=zl;zz/=zl;
 +  var xx=u[1]*zz-u[2]*zy,xy=u[2]*zx-u[0]*zz,xz=u[0]*zy-u[1]*zx,xl=Math.hypot(xx,xy,xz)||1;xx/=xl;xy/=xl;xz/=xl;
 +  var yx=zy*xz-zz*xy,yy=zz*xx-zx*xz,yz=zx*xy-zy*xx;
 +  return new Float32Array([xx,yx,zx,0,xy,yy,zy,0,xz,yz,zz,0,
 +    -(xx*e[0]+xy*e[1]+xz*e[2]),-(yx*e[0]+yy*e[1]+yz*e[2]),-(zx*e[0]+zy*e[1]+zz*e[2]),1]);
 +}
 +function mmul(a,b){var o=new Float32Array(16);for(var c=0;c<4;c++)for(var r=0;r<4;r++){var s=0;for(var k=0;k<4;k++)s+=a[k*4+r]*b[c*4+k];o[c*4+r]=s;}return o;}
 +function nmat(n){
 +  if(n.matrix)return new Float32Array(n.matrix);
 +  var t=n.translation||[0,0,0],q=n.rotation||[0,0,0,1],s=n.scale||[1,1,1];
 +  var x=q[0],y=q[1],z=q[2],w=q[3],x2=x+x,y2=y+y,z2=z+z,xx=x*x2,xy=x*y2,xz=x*z2,yy=y*y2,yz=y*z2,zz=z*z2,wx=w*x2,wy=w*y2,wz=w*z2;
 +  return new Float32Array([(1-(yy+zz))*s[0],(xy+wz)*s[0],(xz-wy)*s[0],0,(xy-wz)*s[1],(1-(xx+zz))*s[1],(yz+wx)*s[1],0,(xz+wy)*s[2],(yz-wx)*s[2],(1-(xx+yy))*s[2],0,t[0],t[1],t[2],1]);
 +}
 +function ap(m,v){return [m[0]*v[0]+m[4]*v[1]+m[8]*v[2]+m[12],m[1]*v[0]+m[5]*v[1]+m[9]*v[2]+m[13],m[2]*v[0]+m[6]*v[1]+m[10]*v[2]+m[14]];}
 +function hex(h){return [parseInt(h.slice(1,3),16)/255,parseInt(h.slice(3,5),16)/255,parseInt(h.slice(5,7),16)/255];}
 +
 +/* ===== 载入 ===== */
 +function unzip(ab){
 +  var d=new DataView(ab);
 +  if(d.getUint32(0,true)!==0x04034b50)throw new Error('zip');
 +  if(d.getUint16(8,true)!==0)throw new Error('zip mode');
 +  var cs=d.getUint32(18,true),nl=d.getUint16(26,true),el=d.getUint16(28,true),st=30+nl+el;
 +  return ab.slice(st,st+cs);
 +}
 +function parseGLB(ab){
 +  var d=new DataView(ab);
 +  if(d.getUint32(0,true)!==0x46546C67)throw new Error('glb');
 +  var len=d.getUint32(8,true),o=12,j=null,b=null;
 +  while(o<len){
 +    var cl=d.getUint32(o,true),ct=d.getUint32(o+4,true);o+=8;
 +    var c=ab.slice(o,o+cl);
 +    if(ct===0x4E4F534A)j=JSON.parse(new TextDecoder().decode(c));
 +    else if(ct===0x004E4942)b=c;
 +    o+=cl;
 +  }
 +  return {json:j,bin:b};
 +}
 +var CT={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array};
 +function acc(g,i){
 +  var a=g.json.accessors[i],v=g.json.bufferViews[a.bufferView],T=CT[a.componentType];
 +  var it=a.type==='VEC3'?3:a.type==='VEC2'?2:a.type==='SCALAR'?1:4;
 +  var off=(v.byteOffset||0)+(a.byteOffset||0),st=v.byteStride||0;
 +  if(st&&st!==it*T.BYTES_PER_ELEMENT){
 +    var o=new T(a.count*it);
 +    for(var k=0;k<a.count;k++)o.set(new T(g.bin,off+k*st,it),k*it);
 +    return o;
 +  }
 +  return new T(g.bin,off,a.count*it);
 +}
 +function build(g){
 +  var ps=[],pos=[],nrm=[],idx=[],vb=0,ib=0;
 +  var sc=g.json.scenes[g.json.scene||0],stack=[];
 +  (sc.nodes||[]).forEach(function(n){stack.push([n,new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1])]);});
 +  while(stack.length){
 +    var cur=stack.pop(),ni=g.json.nodes[cur[0]],M=mmul(cur[1],nmat(ni));
 +    if(ni.mesh!==undefined){
 +      g.json.meshes[ni.mesh].primitives.forEach(function(p){
 +        var P=acc(g,p.attributes.POSITION),N=p.attributes.NORMAL!==undefined?acc(g,p.attributes.NORMAL):null,
 +            I=p.indices!==undefined?acc(g,p.indices):null;
 +        var start=ib,vc=P.length/3,i,mn=[1e9,1e9,1e9],mx=[-1e9,-1e9,-1e9];
 +        for(i=0;i<P.length;i+=3){
 +          var v=ap(M,[P[i],P[i+1],P[i+2]]);
 +          pos.push(v[0],v[1],v[2]);
 +          for(var a=0;a<3;a++){if(v[a]<mn[a])mn[a]=v[a];if(v[a]>mx[a])mx[a]=v[a];}
 +        }
 +        for(i=0;i<vc;i++){
 +          if(N){var w=ap(M,[N[i*3],N[i*3+1],N[i*3+2]]),l=Math.hypot(w[0],w[1],w[2])||1;nrm.push(w[0]/l,w[1]/l,w[2]/l);}
 +          else nrm.push(0,1,0);
 +        }
 +        if(I)for(i=0;i<I.length;i++)idx.push(I[i]+vb);
 +        else for(i=0;i<vc;i++)idx.push(i+vb);
 +        ps.push({pi:ps.length,start:start,count:idx.length-start,mn:mn,mx:mx,
 +          c:[(mn[0]+mx[0])/2,(mn[1]+mx[1])/2,(mn[2]+mx[2])/2],
 +          size:[mx[0]-mn[0],mx[1]-mn[1],mx[2]-mn[2]],vis:true});
 +        vb+=vc;ib=idx.length;
 +      });
 +    }
 +    (ni.children||[]).forEach(function(ch){stack.push([ch,M]);});
 +  }
 +  var box=[1e9,1e9,1e9,-1e9,-1e9,-1e9];
 +  ps.forEach(function(p){for(var a=0;a<3;a++){box[a]=Math.min(box[a],p.mn[a]);box[a+3]=Math.max(box[a+3],p.mx[a]);}});
 +  return {parts:ps,pos:new Float32Array(pos),nrm:new Float32Array(nrm),idx:new Uint32Array(idx),box:box,
 +    center:[(box[0]+box[3])/2,(box[1]+box[4])/2,(box[2]+box[5])/2],
 +    diag:Math.hypot(box[3]-box[0],box[4]-box[1],box[5]-box[2])};
 +}
 +
 +/* ===== 主函数 ===== */
 +return function(host,cfg){
 +  cfg=cfg||{};
 +  var L=UI[cfg.lang==='en'?'en':'zh'];
 +  var PARTS=cfg.parts||PARTS_S156, REAR=cfg.rear!==undefined?cfg.rear:REAR_S156;
 +  if(!document.getElementById('sml3d-css')){
 +    var st=document.createElement('style');st.id='sml3d-css';st.textContent=CSS;document.head.appendChild(st);
 +  }
 +  var root=document.createElement('div');root.className='v3d';
 +  root.innerHTML=''
 +   +'<canvas></canvas>'
 +   +'<div class="tbar">'
 +   +'<button class="tb" data-v="front">'+L.front+'</button>'
 +   +'<button class="tb" data-v="back">'+L.back+'</button>'
 +   +'<button class="tb" data-v="side">'+L.side+'</button>'
 +   +'<button class="tb on" data-v="iso">'+L.iso+'</button>'
 +   +'<button class="tb hot" data-a="cover">'+L.open+'</button>'
 +   +'<button class="tb" data-a="xray">'+L.xray+'</button>'
 +   +'<button class="tb" data-a="parts">'+L.parts+'</button>'
 +   +'</div>'
 +   +'<div class="plist"></div>'
 +   +'<div class="hint">'+L.hint+'</div>'
 +   +'<div class="ebar"><span class="lb">'+L.exp+'</span><input type="range" min="0" max="100" value="0"><span class="pv">0%</span></div>'
 +   +'<div class="tip"></div>'
 +   +'<div class="cover"><button class="b">'+L.load+'</button><span class="s">'+(cfg.size||L.size)+'</span></div>';
 +  host.appendChild(root);
 +
 +  var cv=root.querySelector('canvas');
 +  var gl=cv.getContext('webgl2',{antialias:true,alpha:true,premultipliedAlpha:false});
 +  if(!gl){root.querySelector('.cover').innerHTML='<span class="s">'+L.sorry+'</span>';return {};}
 +
 +  var VS=['#version 300 es','in vec3 aP;in vec3 aN;uniform mat4 uP,uV;uniform vec3 uO;out vec3 vP;out vec3 vN;',
 +    'void main(){vec3 p=aP+uO;vP=p;vN=aN;gl_Position=uP*uV*vec4(p,1.0);}'].join('\n');
 +  var FS=['#version 300 es','precision highp float;in vec3 vP;in vec3 vN;uniform vec3 uC,uE;uniform float uS,uD,uX,uA;uniform mat4 uV;out vec4 f;',
 +    'void main(){vec3 N=normalize(vN),V=normalize(uE-vP);if(dot(N,V)<0.0)N=-N;',
 +    'mat3 R=mat3(uV);vec3 Nv=normalize(R*N),Vv=normalize(R*V);vec3 L1=normalize(vec3(-0.42,0.58,0.70)),L2=normalize(vec3(0.60,-0.30,0.74));',
 +    'float k1=max(dot(Nv,L1),0.0),k2=max(dot(Nv,L2),0.0);vec3 H=normalize(L1+Vv);',
 +    'float sp=pow(max(dot(Nv,H),0.0),46.0)*0.30;float rm=pow(1.0-max(dot(Nv,Vv),0.0),3.0)*0.20;',
 +    'vec3 c=uC*(0.34+0.52*k1+0.20*k2)+vec3(sp)+vec3(rm)*0.55;',
 +    'if(uS>0.5)c=mix(c,vec3(0.12,0.40,0.85),0.34);if(uX>0.5)c=mix(c,vec3(0.40,0.48,0.58),0.55);else if(uD>0.5)c=mix(c,vec3(0.72,0.76,0.81),0.62);',
 +    'float a=1.0;if(uD>0.5)a*=mix(0.40,1.0,uX);f=vec4(c,a*uA);}'].join('\n');
 +  function sh(t,s){var o=gl.createShader(t);gl.shaderSource(o,s);gl.compileShader(o);
 +    if(!gl.getShaderParameter(o,gl.COMPILE_STATUS))throw new Error(gl.getShaderInfoLog(o));return o;}
 +  var pr=gl.createProgram();
 +  gl.attachShader(pr,sh(gl.VERTEX_SHADER,VS));gl.attachShader(pr,sh(gl.FRAGMENT_SHADER,FS));
 +  gl.bindAttribLocation(pr,0,'aP');gl.bindAttribLocation(pr,1,'aN');gl.linkProgram(pr);gl.useProgram(pr);
 +  var U={};['uP','uV','uO','uC','uE','uS','uD','uX','uA'].forEach(function(n){U[n]=gl.getUniformLocation(pr,n);});
 +
 +  var cam={th:0.60,ph:0.19,dist:3,tgt:[0,0,0],fov:34*Math.PI/180};
 +  var model=null,explode=0,sel=-1,xray=false,coverHidden=false;
 +  var buf={};
 +
 +  function eye(){var cp=Math.cos(cam.ph);return [cam.tgt[0]+cam.dist*cp*Math.sin(cam.th),cam.tgt[1]+cam.dist*Math.sin(cam.ph),cam.tgt[2]+cam.dist*cp*Math.cos(cam.th)];}
 +  function fitDist(){
 +    var w=cv.clientWidth||1,h=cv.clientHeight||1,as=w/h;
 +    var fv=cam.fov,fh=2*Math.atan(Math.tan(fv/2)*as),R=model.diag/2*1.06;
 +    return R/Math.sin(Math.min(fv,fh)/2);
 +  }
 +  /* 视角平滑过渡 */
 +  var tw=null;
 +  function tween(to){
 +    var from={th:cam.th,ph:cam.ph,dist:cam.dist};
 +    var t0=performance.now();
 +    if(to.th!==undefined&&Math.abs(to.th-cam.th)>Math.PI)cam.th+=(cam.th>to.th?1:-1)*2*Math.PI;
 +    from.th=cam.th;
 +    tw={from:from,to:to,t0:t0,dur:420};
 +    if(!tw.run){tw.run=true;(function step(){ if(!tw){return;}
 +      var k=Math.min(1,(performance.now()-tw.t0)/tw.dur),e=k<0.5?2*k*k:1-Math.pow(-2*k+2,2)/2;
 +      cam.th=tw.from.th+(tw.to.th-tw.from.th)*e;
 +      cam.ph=tw.from.ph+(tw.to.ph-tw.from.ph)*e;
 +      cam.dist=tw.from.dist+(tw.to.dist-tw.from.dist)*e;
 +      draw();
 +      if(k<1)requestAnimationFrame(step);else tw=null;
 +    })();}
 +  }
 +  function off(p){
 +    var m=PARTS[p.pi]||{k:0.5,d:[0,0,1]};
 +    var g=explode*model.diag*0.20*(m.k===undefined?0.5:m.k);
 +    return [m.d[0]*g,m.d[1]*g,m.d[2]*g];
 +  }
 +  function col(p){return (PARTS[p.pi]&&PARTS[p.pi].col)||'#9aa4b0';}
 +
 +  function draw(){
 +    var dpr=Math.min(window.devicePixelRatio||1,2),w=cv.clientWidth||1,h=cv.clientHeight||1;
 +    if(cv.width!==w*dpr||cv.height!==h*dpr){cv.width=w*dpr;cv.height=h*dpr;}
 +    gl.viewport(0,0,cv.width,cv.height);
 +    gl.clearColor(0,0,0,0);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
 +    if(xray){gl.disable(gl.DEPTH_TEST);}else{gl.enable(gl.DEPTH_TEST);}gl.disable(gl.CULL_FACE);gl.enable(gl.BLEND);
 +    gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);
 +    var e=eye();
 +    gl.uniformMatrix4fv(U.uP,false,persp(cam.fov,w/h,model.diag*0.01,model.diag*12));
 +    gl.uniformMatrix4fv(U.uV,false,look(e,cam.tgt,[0,1,0]));
 +    gl.uniform3fv(U.uE,e);
 +    gl.bindBuffer(gl.ARRAY_BUFFER,buf.p);gl.enableVertexAttribArray(0);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0);
 +    gl.bindBuffer(gl.ARRAY_BUFFER,buf.n);gl.enableVertexAttribArray(1);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0);
 +    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,buf.i);
 +    var any=sel>=0;
 +    model.parts.forEach(function(p){
 +      if(!p.vis)return;
 +      var c=hex(col(p));
 +      gl.uniform3f(U.uC,c[0],c[1],c[2]);
 +      gl.uniform3fv(U.uO,off(p));
 +      gl.uniform1f(U.uS,p.pi===sel?1:0);
 +      gl.uniform1f(U.uD,(any&&p.pi!==sel)?1:0);
 +      gl.uniform1f(U.uA, xray ? (p.pi===sel ? 1.0 : (Math.max(p.size[0],p.size[1],p.size[2])>0.075?0.20:0.62)) : 1.0);
 +      gl.uniform1f(U.uX,xray&&p.pi!==sel?1:0);
 +      gl.drawElements(gl.TRIANGLES,p.count,gl.UNSIGNED_INT,p.start*4);
 +    });
 +  }
 +
 +  /* 交互 */
 +  var drag=null;
 +  cv.addEventListener('pointerdown',function(e){cv.setPointerCapture(e.pointerId);drag={x:e.clientX,y:e.clientY,m:0,b:e.button};});
 +  cv.addEventListener('pointermove',function(e){
 +    if(!drag)return;
 +    var dx=e.clientX-drag.x,dy=e.clientY-drag.y;drag.x=e.clientX;drag.y=e.clientY;drag.m+=Math.abs(dx)+Math.abs(dy);
 +    if(drag.b===2||e.shiftKey){
 +      var k=cam.dist*0.0016;
 +      cam.tgt[0]-=Math.cos(cam.th)*dx*k;cam.tgt[2]+=Math.sin(cam.th)*dx*k;cam.tgt[1]+=dy*k;
 +    }else{
 +      cam.th-=dx*0.008;cam.ph=Math.max(-1.45,Math.min(1.45,cam.ph+dy*0.006));
 +    }
 +    draw();
 +  });
 +  cv.addEventListener('pointerup',function(e){if(drag&&drag.m<6&&drag.b===0)pick(e);drag=null;});
 +  cv.addEventListener('contextmenu',function(e){e.preventDefault();});
 +  cv.addEventListener('wheel',function(e){
 +    e.preventDefault();
 +    cam.dist*=1+Math.sign(e.deltaY)*0.09;
 +    cam.dist=Math.max(model.diag*0.3,Math.min(model.diag*3.2,cam.dist));
 +    draw();
 +  },{passive:false});
 +
 +  function pick(e){
 +    var r=cv.getBoundingClientRect();
 +    var nx=((e.clientX-r.left)/r.width)*2-1,ny=1-((e.clientY-r.top)/r.height)*2;
 +    var o=eye(),f=[cam.tgt[0]-o[0],cam.tgt[1]-o[1],cam.tgt[2]-o[2]],fl=Math.hypot(f[0],f[1],f[2]);
 +    f=[f[0]/fl,f[1]/fl,f[2]/fl];
 +    var rt=[f[1]*0-f[2]*1,f[2]*0-f[0]*0,f[0]*1-f[1]*0],rl=Math.hypot(rt[0],rt[1],rt[2])||1;
 +    rt=[rt[0]/rl,rt[1]/rl,rt[2]/rl];
 +    var up=[rt[1]*f[2]-rt[2]*f[1],rt[2]*f[0]-rt[0]*f[2],rt[0]*f[1]-rt[1]*f[0]];
 +    var hh=Math.tan(cam.fov/2),hw=hh*(r.width/r.height);
 +    var d=[f[0]+rt[0]*nx*hw+up[0]*ny*hh,f[1]+rt[1]*nx*hw+up[1]*ny*hh,f[2]+rt[2]*nx*hw+up[2]*ny*hh];
 +    var dl=Math.hypot(d[0],d[1],d[2]);d=[d[0]/dl,d[1]/dl,d[2]/dl];
 +    var best=-1,bt=1e12;
 +    model.parts.forEach(function(p){
 +      if(!p.vis)return;
 +      var of=off(p),cx=p.c[0]+of[0],cy=p.c[1]+of[1],cz=p.c[2]+of[2];
 +      var oc=[cx-o[0],cy-o[1],cz-o[2]],tca=oc[0]*d[0]+oc[1]*d[1]+oc[2]*d[2];
 +      var rad=Math.hypot(p.size[0],p.size[1],p.size[2])/2;
 +      if(tca<0)return;
 +      if((oc[0]*oc[0]+oc[1]*oc[1]+oc[2]*oc[2])-tca*tca>rad*rad)return;
 +      for(var i=p.start;i<p.start+p.count;i+=3){
 +        var a=model.idx[i]*3,b=model.idx[i+1]*3,c=model.idx[i+2]*3;
 +        var t=rt3(o,d,
 +          [model.pos[a]+of[0],model.pos[a+1]+of[1],model.pos[a+2]+of[2]],
 +          [model.pos[b]+of[0],model.pos[b+1]+of[1],model.pos[b+2]+of[2]],
 +          [model.pos[c]+of[0],model.pos[c+1]+of[1],model.pos[c+2]+of[2]]);
 +        if(t>0&&t<bt){bt=t;best=p.pi;}
 +      }
 +    });
 +    select(best,e);
 +  }
 +  function rt3(o,d,a,b,c){
 +    var e1=[b[0]-a[0],b[1]-a[1],b[2]-a[2]],e2=[c[0]-a[0],c[1]-a[1],c[2]-a[2]];
 +    var p=[d[1]*e2[2]-d[2]*e2[1],d[2]*e2[0]-d[0]*e2[2],d[0]*e2[1]-d[1]*e2[0]];
 +    var det=e1[0]*p[0]+e1[1]*p[1]+e1[2]*p[2];
 +    if(Math.abs(det)<1e-9)return -1;
 +    var iv=1/det,t=[o[0]-a[0],o[1]-a[1],o[2]-a[2]];
 +    var u=(t[0]*p[0]+t[1]*p[1]+t[2]*p[2])*iv;
 +    if(u<0||u>1)return -1;
 +    var q=[t[1]*e1[2]-t[2]*e1[1],t[2]*e1[0]-t[0]*e1[2],t[0]*e1[1]-t[1]*e1[0]];
 +    var v=(d[0]*q[0]+d[1]*q[1]+d[2]*q[2])*iv;
 +    if(v<0||u+v>1)return -1;
 +    return (e2[0]*q[0]+e2[1]*q[1]+e2[2]*q[2])*iv;
 +  }
 +
 +  var plist=root.querySelector('.plist'),tip=root.querySelector('.tip');
 +  function nm(p){var m=PARTS[p.pi];if(!m)return (cfg.lang==='en'?'Part ':'零件 ')+(p.pi+1);return cfg.lang==='en'?m.e:m.n;}
 +  function buildList(){
 +    plist.innerHTML='';
 +    model.parts.slice().sort(function(a,b){return b.size[0]*b.size[1]-a.size[0]*a.size[1];}).forEach(function(p){
 +      var el=document.createElement('div');
 +      el.className='pi';el.dataset.pi=p.pi;
 +      el.innerHTML='<i style="background:'+col(p)+'"></i><span>'+nm(p)+'</span>';
 +      el.addEventListener('click',function(ev){
 +        if(ev.altKey){p.vis=!p.vis;sync();draw();return;}
 +        select(p.pi===sel?-1:p.pi);
 +      });
 +      el.addEventListener('dblclick',function(){p.vis=!p.vis;sync();draw();});
 +      plist.appendChild(el);
 +    });
 +    sync();
 +  }
 +  function sync(){
 +    plist.querySelectorAll('.pi').forEach(function(el){
 +      var p=model.parts[+el.dataset.pi];
 +      el.classList.toggle('off',!p.vis);el.classList.toggle('sel',p.pi===sel);
 +    });
 +  }
 +  function select(pi,e){
 +    sel=pi;sync();draw();
 +    if(pi<0||!e){tip.classList.remove('on');return;}
 +    var p=model.parts[pi],s=p.size.map(function(v){return Math.round(v*1000);});
 +    tip.innerHTML='<b>'+nm(p)+'</b><br>'+L.dim+' '+s[0]+' × '+s[1]+' × '+s[2]+' mm<br>'+L.faces+' '+(p.count/3|0);
 +    var r=host.getBoundingClientRect();
 +    tip.style.left=Math.min(r.width-200,e.clientX-r.left+12)+'px';
 +    tip.style.top=Math.min(r.height-70,e.clientY-r.top+12)+'px';
 +    tip.classList.add('on');
 +  }
 +
 +  /* 工具栏 */
 +  root.querySelectorAll('.tb').forEach(function(b){
 +    b.addEventListener('click',function(){
 +      var v=b.dataset.v,a=b.dataset.a;
 +      if(v){
 +        root.querySelectorAll('.tb[data-v]').forEach(function(x){x.classList.remove('on');});
 +        b.classList.add('on');
 +        var to={ph:v==='iso'?0.28:0.02,dist:fitDist()};
 +        if(v==='front')to.th=0;
 +        if(v==='back')to.th=Math.PI;
 +        if(v==='side')to.th=-Math.PI/2;
 +        if(v==='iso')to.th=0.60;
 +        cam.tgt=[model.center[0],model.center[1],model.center[2]];
 +        tween(to);return;
 +      }
 +      if(a==='parts'){plist.classList.toggle('on');b.classList.toggle('on');return;}
 +      if(a==='xray'){xray=!xray;b.classList.toggle('on',xray);draw();return;}
 +      if(a==='cover'){
 +        coverHidden=!coverHidden;
 +        model.parts[REAR].vis=!coverHidden;
 +        b.classList.toggle('on',coverHidden);
 +        b.textContent=coverHidden?L.close:L.open;
 +        if(coverHidden){
 +          explode=0.5;root.querySelector('.ebar input').value=50;root.querySelector('.pv').textContent='50%';
 +          tween({th:Math.PI*0.80,ph:0.24,dist:fitDist()*1.02});
 +        }else{
 +          explode=0;root.querySelector('.ebar input').value=0;root.querySelector('.pv').textContent='0%';
 +          tween({th:0.60,ph:0.28,dist:fitDist()});
 +        }
 +        sync();draw();return;
 +      }
 +    });
 +  });
 +  var sld=root.querySelector('.ebar input');
 +  sld.addEventListener('input',function(){
 +    explode=+sld.value/100;root.querySelector('.pv').textContent=sld.value+'%';
 +    if(coverHidden&&explode<0.15){coverHidden=false;model.parts[REAR].vis=true;
 +      var cb=root.querySelector('.tb[data-a=cover]');cb.classList.remove('on');cb.textContent=L.open;}
 +    draw();
 +  });
 +
 +  /* 加载 */
 +  var started=false;
 +  function start(){
 +    if(started)return;started=true;
 +    var cover=root.querySelector('.cover');
 +    cover.innerHTML=L.loading+'<div class="bar"><i></i></div>';
 +    var bar=cover.querySelector('.bar>i');
 +    fetch(cfg.url).then(function(r){
 +      if(!r.ok)throw new Error('HTTP '+r.status);
 +      var tot=+r.headers.get('content-length')||0,got=0,ch=[],rd=r.body.getReader();
 +      return (function pump(){
 +        return rd.read().then(function(x){
 +          if(x.done)return;
 +          ch.push(x.value);got+=x.value.length;
 +          if(tot)bar.style.width=Math.min(94,6+90*got/tot)+'%';
 +          return pump();
 +        });
 +      })().then(function(){
 +        var b=new Uint8Array(got),o=0;ch.forEach(function(c){b.set(c,o);o+=c.length;});
 +        return b.buffer;
 +      });
 +    }).then(function(ab){
 +      model=build(parseGLB(unzip(ab)));
 +      buf.p=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buf.p);gl.bufferData(gl.ARRAY_BUFFER,model.pos,gl.STATIC_DRAW);
 +      buf.n=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buf.n);gl.bufferData(gl.ARRAY_BUFFER,model.nrm,gl.STATIC_DRAW);
 +      buf.i=gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,buf.i);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,model.idx,gl.STATIC_DRAW);
 +      bar.style.width='100%';
 +      cover.style.display='none';
 +      cam.tgt=[model.center[0],model.center[1],model.center[2]];
 +      cam.dist=fitDist();
 +      window.__parts=model.parts;
 +      if(cfg.only!==undefined){model.parts.forEach(function(q){q.vis=q.pi===cfg.only;});}
 +      buildList();draw();
 +      if(cfg.boom!==undefined){
 +        explode=cfg.boom;
 +        root.querySelector('.ebar input').value=Math.round(explode*100);
 +        root.querySelector('.pv').textContent=Math.round(explode*100)+'%';
 +      }
 +      if(cfg.hideCover){
 +        coverHidden=true;model.parts[REAR].vis=false;
 +        var cb=root.querySelector('.tb[data-a=cover]');
 +        cb.classList.add('on');cb.textContent=L.close;
 +        sync();
 +      }
 +      if(cfg.view){cam.th=cfg.view==='back'?Math.PI:cfg.view==='side'?-Math.PI/2:0.60;
 +        cam.ph=cfg.view==='iso'?0.28:0.02;}
 +      draw();
 +    }).catch(function(err){
 +      cover.innerHTML='<span class="s">'+L.err+':'+err.message+'</span>';
 +    });
 +  }
 +  root.querySelector('.cover .b').addEventListener('click',start);
 +  host.__sml3dStart=start;
 +  window.addEventListener('resize',function(){if(model)draw();});
 +  return {start:start,ondraw:draw};
 +};
 +})();
 +
 +</script></html>
 +<html><script>
 +/* 3D 拆解视角:捕获阶段接管图库按钮,不改动本页原有的切换脚本 */
 +(function () {
 +  var host = document.getElementById('sml-3d');
 +  if (!host) return;
 +  var stage = host.parentNode, side = document.querySelector('.sml-g-side');
 +  var v3 = null, on = false;
 +  function parseParts(btn) {
 +    try {
 +      var a = JSON.parse(btn.getAttribute('data-parts') || '[]');
 +      return a.map(function (r) { return {n: r[0], e: r[1], col: r[2], k: r[3], d: [0, 0, r[4]]}; });
 +    } catch (e) { return null; }
 +  }
 +  function enter(btn) {
 +    on = true;
 +    stage.className = 'sml-g-stage on3d';
 +    if (side) side.className = 'sml-g-side on3d';
 +    if (!v3) {
 +      if (!window.SML3D) return;
 +      v3 = window.SML3D(host, {
 +        url: btn.getAttribute('data-zip'),
 +        lang: btn.getAttribute('data-lang'),
 +        size: btn.getAttribute('data-size'),
 +        parts: parseParts(btn),
 +        rear: +btn.getAttribute('data-rear')
 +      });
 +      v3.start();
 +    }
 +  }
 +  function leave() {
 +    if (!on) return;
 +    on = false;
 +    stage.className = 'sml-g-stage';
 +    if (side) side.className = 'sml-g-side';
 +  }
 +  document.addEventListener('click', function (e) {
 +    var t = e.target;
 +    while (t && t !== document && !(t.tagName === 'BUTTON' && /sml-g-thumb/.test(t.className))) t = t.parentNode;
 +    if (!t || t === document) return;
 +    if (t.hasAttribute('data-3d')) {
 +      e.preventDefault();
 +      e.stopPropagation();
 +      var bs = document.querySelectorAll('button.sml-g-thumb');
 +      for (var i = 0; i < bs.length; i++) bs[i].className = (bs[i] === t ? 'sml-g-thumb on' : 'sml-g-thumb');
 +      var cap = document.getElementById('sml-g-cap'), cnt = document.getElementById('sml-g-count');
 +      if (cnt) cnt.textContent = t.getAttribute('data-idx') + ' / ' + (bs.length < 10 ? '0' + bs.length : bs.length);
 +      if (cap) cap.textContent = t.getAttribute('data-cap');
 +      enter(t);
 +    } else {
 +      leave();
 +    }
 +  }, true);
 +})();
 +</script></html>
  
导航

首页
帮助
联系我们

打印/导出