# 模型来源与导入方案(2026-10-07 核实) > **背景**:用户实测「搜到网址但**没有建模文件可下载**」,并指出外部库到底哪些能连。 > 本文把**核实过的**来源、格式能力、以及集成方案落盘。 > > **★ 结论先行**:**`step.parts` 是唯一一个「公共 API + 免鉴权 + 直接给 GLB + 覆盖板卡模块」的来源。** > 它推翻了本文档早先「几何散、要转 STEP、许可各异」的判断 —— 三个问题它一次解决。 > > ⚠️ **但它的覆盖有明确边界(2026-10-08 复核,见 §2)**:**板卡/模块 + 机械件 + PCB 封装**, > **不含裸芯片的实体模型**(`BME280`/`DHT22`/`SHT31`/`MPU6050` 全部 0 结果; > `Bosch` 只返回 LGA **焊盘封装**)。⇒ 芯片级几何本来就买不到,这正是"用户导入"路线成立的原因。 --- ## 1. 来源核实结果 | 来源 | 公共 API | 免登录 | 给的格式 | 覆盖板卡/模块? | 判定 | |---|---|---|---|---|---| | **★ step.parts** | ✅ **有**(`api.step.parts/v1`) | ✅ | **GLB(每件都有 `glbUrl`)** | ✅ **有** | **首选** | | Printables / Thingiverse | ❌ | ✅ | STL | ✅ 有 | 可作补充(已支持 STL) | | KiCad 官方 3D 库 | ❌(GitLab 直取文件) | ✅ | STEP + **WRL** | ❌ **只有芯片封装** | 芯片级可用 | | GrabCAD | ❌ | ❌ **要登录** | STEP 为主 | ✅ 有 | 手动兜底 | | SnapEDA / SnapMagic | 部分 | 号称免登录 | STEP 等 | ⚠️ 国内覆盖 <30% | 待验 | | Ultra Librarian | ❌ | ❌ **要注册** | STEP | ⚠️ | 待验 | **⇒ 「外部库到底能连的有?」的答案是:** - **能程序化直连的只有一个:`step.parts`**(其余要么要登录、要么没有 API、要么格式要转) - **能免费免登录手动下载的**:Printables / Thingiverse(STL)、KiCad 3D(WRL/STEP,芯片) --- ## 2. ★ step.parts API(已实测,可直接对接) **基础**:`https://api.step.parts/v1` ─ 免鉴权 ─ 仓库 MIT ─ 目录 `partCount: 16847` ### 搜索 ```http GET https://api.step.parts/v1/parts?q=<查询词>&pageSize=&page= # 也支持结构化过滤: GET .../v1/parts?category=electronics&family=raspberry-pi GET .../v1/parts?q=M3&tag=screw GET .../v1/parts?q=lengthMm%2012 ``` **机读文档**:`/v1/openapi.json`、`/v1/catalog/schema`、`/v1/catalog/parts.index.json` ### 响应形状(实测节选) ```jsonc { "catalog": { "partCount": 16847, "openApiUrl": "...", "schemaUrl": "..." }, "items": [{ "id": "raspberry_pi_4_model_b", "name": "Raspberry Pi 4 Model B", "description": "Raspberry Pi 4 Model B single-board computer.", "category": "electronics", "family": "raspberry-pi", "tags": ["board", "single-board-computer", "sbc"], "aliases": ["Pi 4B", "RPi 4B", "Raspberry Pi 4B"], "attributes": { "manufacturer": "Raspberry Pi", "model": "Raspberry Pi 4 Model B", "formFactor": "credit-card-sbc", "boardLengthMm": 85, "boardWidthMm": 56, // ★ 板卡尺寸!可直接当 size 的初值 "gpioHeader": "40-pin", "wireless": true }, "stepUrl": "https://media.githubusercontent.com/.../catalog/step/...step", "glbUrl": "https://8ljrorjug0ps5al0.public.blob.vercel-storage.com/preview/glb/raspberry_pi_4_model_b-.glb", "pngUrl": "https://.../preview/png/....png", "byteSize": 52486607, // ⚠️ 这是 **STEP** 的大小,不是 GLB!实际 GLB 仅 5.7MB —— 见 §4.1 "sha256": "1906d615...", "pageUrl": "https://www.step.parts/parts/raspberry_pi_4_model_b", "apiUrl": "https://api.step.parts/v1/parts/raspberry_pi_4_model_b" }], "page": 1, "pageSize": 5, "total": 24, "totalPages": 5, "facets": { "categories": [...], "families": [...], "tags": [...], "standards": [...] } } ``` ### 覆盖度(facets + 检索实测,2026-10-08 复核) **总目录 16,847 件**,但**必须看清它到底装了什么** —— 否则会以为"什么都搜得到": | 类别 | 件数 | 实际内容 | |---|---|---| | `electronics` | 7,822 | **绝大部分是排针/排母/连接器**(各间距各 278 条),不是芯片 | | `power-transmission` / `fastener` / `mechanical-hardware` | 2,488 / 2,118 / 826 | 同步带、螺丝、机械件 | | `spacer` / `motion` / `actuator` / `enclosure` / `thermal` | 434 / 570 / 339 / 294 / 275 | 结构件 | | **★ 板卡模块**(我们真正要的) | **≈242** | 见下表 | **板卡家族(5 个,共 ≈242 件):** ``` raspberry-pi 15 Pi 5 / Pi 4B (85x56) · Pico / Pico H / W / WH / 2 / 2 with headers (51x21) · CM5 (55x40) · Camera Module 3 ×2 · Touch Display 2 ×2 · Bumper · Radio Module 2 arduino 17 UNO Q / UNO R4 WiFi · Nano R4 / Nano Matter / Nano ESP32 · GIGA R1 WiFi · Portenta C33 / H7 Lite / H7 Lite Connected / X8 · Nicla Sense ME / Vision / Voice / Sense Env · Opta RS485-WiFi / Opta Lite · Stella adafruit 87 sparkfun 120 nvidia-jetson 3 Jetson Thor · AGX Orin (P3701) · Orin NX / Orin Nano ``` ⇒ **板卡与模块的覆盖是够用的**,而且**恰好是我们场景要的那些**(树莓派/Arduino/Adafruit/SparkFun/Jetson)。 每件都有 `glbUrl`(GLB 免转换)与 `pngUrl`(预览图)。 #### ⚠️ 但它**没有裸芯片的实体模型**(这条会直接影响界面文案) 实测检索: | 查询 | `total` | 说明 | |---|---|---| | `BME280` / `bme280` | **0** | 我们的参照型号恰好搜不到 | | `DHT22` / `SHT31` / `MPU6050` | **0** | 常见传感器芯片全无 | | `temperature sensor` | **0** | | | `Bosch` | 5 | 全是 **LGA 封装**:`Bosch LGA-14 3x2.5mm P0.5mm` 等 | | `ESP32` | 8 | 是 **Arduino Nano ESP32 / ESP32-C3-WROOM 模组**,不是芯片裸片 | | `sensor` | 28 | 是 Arduino Nicla 这类**板卡** | **`Bosch` 返回的是 `LGA-14 / LGA-16 / LGA-8` 封装 —— 那是 PCB 焊盘图形(land pattern),不是实体元件。** 这与 `docs/03` 的既有结论**同源**:EDA 生态索引的是**芯片的封装**,不是"你手上那个东西"。 **⇒ 界面必须有空结果提示**(否则用户搜 BME280 看到空列表会以为功能坏了): > 「step.parts 只收**板卡/模块/机械件**,**裸芯片不在其中** —— 请用上面的外链自行下载后导入。」 **⇒ 也解释了为什么"用户导入"是对的路子**:芯片级的几何本来就买不到, 而用户手上那台设备(不管是板卡还是自制模块)他可以自己建模/下载。 #### ★★ 由此得出一条结构性结论:step.parts 与 EDA 元件库**互补,而非重叠** 这条值得单独记,因为它解释了整个方案的形状(也是 2026-10-08 与并行会话一起确认的): | 来源 | 给什么 | 给不了什么 | |---|---|---| | **EDA 元件库**(EasyEDA / LCSC / KiCad 3D) | **芯片的封装**(land pattern / footprint) | **实体元件** —— 我们要的恰恰是这个 | | **step.parts** | **板卡/模块的实体几何**(242 件,含 GLB) | **裸芯片** —— `BME280`/`DHT22`/`MPU6050` 全部 0 | | —— | —— | **"芯片的实体模型"两边都没有** | **⇒ 三件事同时成立:** 1. 我们**没有**找错来源 —— step.parts 给的正是场景真正要的东西(板卡与模块) 2. 它也**不是**"元件库的替代品" —— 数量级(242 板卡 vs 7,822 电子件里绝大部分是排针)说明它是**板卡模块库** 3. **芯片级实体几何在公开生态里就是不存在** ⇒ 只能由用户提供 **⇒ 所以"用户导入"不是退而求其次的兜底,而是这条路径上的正解。** (与 `docs/03` 的三条反驳结论一致:那三条否掉的是"我们去采集 EDA 库",不是"用户导入自己的模型"。) ### ★★ 为什么它是关键:`glbUrl` 让 STEP 转换这堵墙消失 我们此前的核心障碍是「现成模型多为 STEP,而 three.js **没有** STEP loader」。 **step.parts 为每件都生成了 GLB 预览**,所以: > **不需要任何 CAD 转换管线** —— 直接下 GLB,three.js 原生可读。 (它自己的流水线里用 `npm run catalog:add` 做 STEP→GLB,但**那是它的活,不是我们的**。) --- ## 3. 我们能渲染哪些格式(实测本机 three) `node_modules/three/examples/jsm/loaders/` 下**存在**: ```text GLTFLoader / STLLoader / OBJLoader / PLYLoader / 3MFLoader / ColladaLoader / FBXLoader / USDZLoader / VRMLLoader ``` **不存在**:`STEP` / `IGES`(已反复确认) ⇒ 已把可导入格式从 `glb|gltf` **放开为**: `glb / gltf / stl / obj / ply / 3mf / dae / fbx / wrl`(见 `contracts/protocol.ts` 的 `ModelFormat`) **判据是「three 有没有 loader」,不是「看起来像不像 3D」。** STEP 明确拒绝并给出说明 —— 收下来渲染不了,只会让用户以为成功了。 **内容嗅探**(`core/models/store.ts` 的 `detectFormat`,不看扩展名、不信 content-type): GLB 魔数 / glTF 的 `"asset"` / PLY 头 / 3MF 的 zip 魔数 / Collada 的 ` ⚠️ **本节原先的标题是「当前 32 MiB,而 Raspberry Pi 4B 的 GLB 是 52 MB」,这是错的。** > 52,486,607 是 **STEP 源文件**的大小,不是 GLB 的。保留这段更正,因为它极易误读 —— > 实测**连看过上下文的人都把 `byteSize` 当成了 GLB 尺寸**,并据此推出"这个件注定被拒"。 **实测(同一件 `raspberry_pi_4_model_b`):** | 量 | 大小 | |---|---| | `byteSize`(**STEP**) | 52,486,607 B | | **实际下载到的 GLB** | **5,978,508 B(5.7 MB)** | GLB 是 step.parts 生成的**预览用简化几何**,比 STEP 小一个数量级。 **落地方案:两道闸门,量的是不同的东西** | 闸门 | 量什么 | 阈值 | 失败时 | |---|---|---|---| | **预检** | 元数据 `byteSize`(**STEP**) | `precheckBytes` = **512 MiB** | **根本不去下载**,直接拒(只挡明显离谱的) | | **实检** | 下载后的**实际字节数** | `MODEL_MAX_BYTES` = **64 MiB** | 拒,并说明"已丢弃" | ⇒ **不能拿 `byteSize` 卡 `maxBytes`** —— 那会拒掉一大批其实装得下的件。 (回归测试:`tests/step-parts.test.ts` 里用 `maxBytes=32MiB` 造出这个情形,断言 **52MB STEP / 5.7MB GLB 必须放行**。) **✅ 已实测导入成功**:`rpi-4b` ← 5,978,508 B,GLB 魔数 `glTF` v2、declared length 与实际一致。 **原选项丙(用 `pngUrl` 预览)仍然保留** —— 让用户看着图决定,比盲下好;`ModelCandidate.previewUrl` 已带出。 ### 4.2 `attributes` 里的板卡尺寸可以直接当 `size` 的初值 `boardLengthMm: 85, boardWidthMm: 56` —— 这正是我们契约里 `size` 需要的(85×56mm)。 ⇒ **「bbox 作初值 + 用户确认」那条(`docs/03` §6.3 的甲方案)现在有了更好的数据源**: 不用从 GLB 反推 bbox,直接用厂商给的毫米数。**厚度仍缺**(需从 GLB 量或人工补)。 > ⚠️ **但只有树莓派有这两个字段** —— 见 §2 的覆盖度实测:`arduino` 17 件、`nvidia-jetson` 3 件 > **一个都没有**。所以"尺寸未知"是**多数情况**而不是边缘情况,界面必须处理这条路径, > **不要默认填一个猜的厚度**。 ### 4.3 许可:仓库 MIT,但**第三方模型各有各的许可** step.parts 的 README 明说: > The MIT License does **not** relicense third-party-derived STEP/model files. > See `THIRD_PARTY_NOTICES.md`. ⇒ **我们不能把它的模型打进插件包分发**。但**用户自己导入**这条路径仍然干净(我们不采集、不分发)。 **这条与既有结论一致,不改变方案。** ### 4.4 直连下载要不要做 有了 `glbUrl`,可以做**一键导入**:面板里搜到 → 点一下 → 模型直接进场景,**完全不用跳浏览器**。 这正是用户要的。 **但必须注意 SSRF**:不能让前端传任意 URL 给宿主去抓。 **建议做法**:宿主侧接口**只收 `partId`**,由宿主自己去 `api.step.parts` 查 `glbUrl` 再抓 —— **URL 从不由客户端提供,SSRF 面为零**。 --- ## 5. 建议的集成方案(待用户确认后开工) ``` 面板搜索框 ↓ GET /api/model-search?q= 宿主:调 api.step.parts/v1/parts?q= → 归一化成候选列表 ↓ 返回 [{ id, name, manufacturer, category, previewUrl(pngUrl), byteSize, importable:true }] 面板显示:预览图 + 名称 + 厂商 + 大小 + 「导入」按钮 ↓ POST /api/model-import { modelKey, partId } 宿主:查 api.step.parts/v1/parts/ → 取 glbUrl → 下载 → 校验格式 → 存入 ModelStore ↓ 场景换装(归一化到契约的 size) ``` **关键性质**: - **全程不跳浏览器** —— 直接解决用户的抱怨 - **URL 由宿主从 API 推导,客户端只给 `partId`** —— 无 SSRF 面 - **glbUrl 是 GLB** —— 无需 STEP 转换 - 仍需**用户确认**(`docs/03` §6.3 甲方案):`attributes` 的 mm 尺寸作初值,界面上显示长宽比供核对 **兜底**:step.parts 搜不到时,回退到现有的 `ctx.web.search`(通用搜索)+ 外链。 --- ## 6. 用户已提出的界面问题(未处理) 1. **「为啥要把这几个单独列出来」** —— 现在每个 `modelKey` 一行(`rpi-4b` / `bme280` / …)。 功能上必要(模型按型号存),但呈现方式让用户困惑。 **建议改成**:先搜索/选择模型,再选"给哪个型号用"。 2. **「搜到网址但没有建模文件可下载」** —— 已由 step.parts 直连方案解决(§5)。 3. 界面上的加载态(通用搜索实测约 **5–6 秒**)。