Files
Robot_Arm/webapp/styles/sheet-hud.css
T
cbb 531a293688 refactor(viewer): 单文件查看器拆成 webapp/ 多文件,走本地 http;Worker 换成真文件
前端不再是"一个 16MB HTML + 一个 2955 行模板"。现在:
  webapp/index.html      343 行 DOM 骨架,零内联数据
  webapp/styles/*.css    811 行 CSS 按段切成 8 个文件
  webapp/js/app.js       原内联主脚本逐字搬出(仍是普通脚本,S5 才改 ESM)
  webapp/js/ik-solver.js / ik-glue.js / vendor/three.min.js(原 web/ 三个文件)
  webapp/workers/ik.worker.js  真 Worker 文件
  webapp/generated/00_data.js  生成物(网格/工程图/行程/碰撞/螺钉)
  dist/机器人手臂3D查看器.html  分发用单文件,由 build_viewer 内联上面这些文件产出

入口:python -m arm.viewer.serve 后开 http://127.0.0.1:8123/
(serve 带 no-store,改完刷新即新构建,不再需要 Ctrl+F5;显式 MIME,
 .js 被 Windows 注册表判成 text/plain 会让模块静默不执行)

删掉 src/viewer_tpl.html 与 web/ 目录(旧产物移入 backups/pre_split_20261015/)。
工程图不再维护第二份 sheets.jsdata —— 直接读 draw_sheet 写出的 4 个真 SVG。

实测中修掉的问题:
- serve 的 / 原先"内部映射"到 webapp/index.html,导致文档基址是 /、相对路径的
  8 个 CSS 与 4 个 JS 全部 404(整页无样式无脚本)。改成 302 跳转。
- file:// 下 new Worker('workers/…') 构造阶段不抛错、错误以异步 onerror 到达,
  所以"构造失败才试 Blob 兜底"永远不会触发;改为按协议选路。两条路径都已实测
  backend=worker(http 走文件、file:// 走 Blob)。
- Worker 握手 3s 在 headless 并发下会误判"没起来"(截图里红徽标即此),放宽到 10s,
  并把后端状态暴露成 window.__IK_BACKEND / __IK_BACKEND_LOG 供测试直读。
- 截图竞态:4 并发 × 每页 14MB 数据时,虚拟时间预算会在页面加载完成前到期,
  拍到半初始化画面(且能"稳定地坏",旧基线里 m9_motion 就是这么混进来的)。
  并发降到 2、预算 40s、serve 加 HTTP/1.1+大缓冲+字节缓存,并用"同一构建两轮"
  重新界定稳定性:99 张逐字节一致、6 张属噪声改走像素容差(mean<=0.02、单像素<=32)。
- 关卡自身两处假通过已修:node 输出被 GBK 解码炸掉时不再算 PASS;
  线束干涉测试读不到通道源码时会 exit 2,而不是"零通道=零穿透=通过"。

关卡结果:python -m arm.build_model 退出码 0;10 项数据哈希与基线一致;
IK exact 段逐字节一致;99 张截图逐字节一致 + 6 张在噪声阈内;线束干涉测试 1800 点 0 穿透。
2026-10-15 04:31:31 +08:00

129 lines
3.0 KiB
CSS

/* 悬停 Tooltip 与 SVG 零件高亮 */
/* 悬停 Tooltip HUD */
.sheet-tooltip {
position: absolute;
z-index: 99;
background: rgba(15, 17, 21, 0.94);
backdrop-filter: blur(10px);
border: 1px solid var(--ac);
border-radius: 7px;
padding: 8px 12px;
font-size: 12px;
color: var(--tx);
box-shadow: 0 10px 28px rgba(0,0,0,.6);
pointer-events: none;
display: none;
max-width: 310px;
line-height: 1.5;
}
.sheet-tooltip.pinned {
pointer-events: auto;
border-color: #38bdf8;
box-shadow: 0 12px 36px rgba(0, 168, 255, 0.35);
}
.sheet-tooltip .st-title {
font-size: 13px;
font-weight: bold;
color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-bottom: 4px;
padding-bottom: 4px;
border-bottom: 1px solid rgba(255,255,255,.1);
}
.sheet-tooltip .st-tag {
font-size: 10px;
padding: 1px 5px;
border-radius: 3px;
font-weight: normal;
}
.st-tag.pr { background: rgba(61,220,151,.2); color: var(--ok); }
.st-tag.ex { background: rgba(255,180,84,.2); color: var(--warn); }
.sheet-tooltip .st-row {
display: flex;
justify-content: space-between;
gap: 12px;
font-size: 11px;
color: var(--dim);
margin: 2px 0;
}
.sheet-tooltip .st-row span:last-child {
color: var(--tx);
text-align: right;
}
.sheet-tooltip .st-btn {
margin-top: 6px;
width: 100%;
padding: 4px 0;
font-size: 11px;
background: #1d4ed8;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
transition: background .15s;
}
.sheet-tooltip .st-btn:hover {
background: #2563eb;
}
/* SVG 交互高亮样式 */
.sheet-part-path {
cursor: pointer;
transition: stroke .12s, stroke-width .12s, filter .12s;
}
.sheet-part-path.is-hovered {
stroke: #00d2ff !important;
stroke-width: 2.8px !important;
fill: rgba(0, 210, 255, 0.16) !important;
filter: drop-shadow(0 0 5px #00a8ff) !important;
}
.sheet-balloon {
cursor: pointer;
transition: transform .15s ease;
}
.sheet-balloon:hover .balloon-circle,
.sheet-balloon.is-hovered .balloon-circle {
fill: #0284c7 !important;
stroke: #ffffff !important;
stroke-width: 2px !important;
filter: drop-shadow(0 0 6px rgba(2,132,199,.8)) !important;
}
.sheet-balloon:hover .balloon-text,
.sheet-balloon.is-hovered .balloon-text {
fill: #ffffff !important;
font-weight: bold !important;
}
.sheet-leader.is-hovered {
stroke: #00d2ff !important;
stroke-width: 1.8px !important;
}
.sheet-legend-row {
cursor: pointer;
}
.sheet-legend-row:hover .legend-row-bg,
.sheet-legend-row.is-hovered .legend-row-bg {
fill: rgba(2, 132, 199, 0.3) !important;
}
.sheet-legend-row:hover text,
.sheet-legend-row.is-hovered text {
fill: #00d2ff !important;
font-weight: bold !important;
}
.joint-geom-part {
cursor: pointer;
transition: all .15s;
}
.joint-geom-part:hover, .joint-geom-part.is-hovered {
stroke: #00d2ff !important;
stroke-width: 2.2px !important;
fill: rgba(0, 210, 255, 0.15) !important;
}