URDF Studio 私有化部署教程
URDF Studio 是一个运行在浏览器中的机器人建模环境:处理机器人拓扑(link/joint)、视觉/碰撞几何体、硬件参数与多文件工作区,并完成多格式导出交付,不需要每次操作都直接手写 XML。
核心能力:
- 拓扑编辑:通过 link/joint 工具构建与编辑运动学树,3D 画布实时预览;
- 几何与碰撞:编辑 visual mesh、collision mesh,测量与碰撞优化;
- 硬件配置:配置电机型号、传动比、阻尼、摩擦与硬件元数据;
- 多机器人组装:将多个机器人装配到同一工作区,通过 bridge joint 连接;
- 多格式导入/导出:支持
URDF、MJCF(MuJoCo)、USD、SDF、Xacro,以及 CSV/BOM、PDF 报告、ZIP 与.usp项目归档;- AI 助手(可选):自然语言生成机器人结构、自动化检查与代码审阅,需自备 OpenAI API key。
技术栈为 React 19 + TypeScript + Vite + Three.js,纯前端 SPA,无后端、无数据库、无 GPU 依赖——私有化部署只需要一台能跑 Docker 的机器。项目地址:OpenLegged/URDF-Studio(Apache 2.0)。
本教程讲两件事:怎么把源码构建成镜像跑起来,以及一个容易忽略的 nginx 配置(不配会导致 USD 功能在浏览器里失效)。
一、架构总览
浏览器 ──► Docker 容器 urdf-studio(nginx,宿主机端口 3890,容器内 80)
│
▼
静态文件 dist/(宿主机本地构建产物)
没有后端。nginx 只做三件事:提供静态文件、SPA 路由回退、设置跨域隔离响应头。所有数据(机器人模型等)都存在浏览器本地,不进服务器。
| 层 | 职责 | 组件 |
|---|---|---|
| 构建层 | 源码 → 静态文件 | Node 20 + npm run build |
| 服务层 | 静态文件 + SPA 路由 + 安全头 | nginx(Docker 容器) |
部署后的访问方式:
- 部署机本机:
http://localhost:3890/ - 局域网设备:
http://<部署机IP>:3890/ - 如需公网 HTTPS 访问(USD 功能需要,见第三节),可再前置一层反向代理,本文不展开。
二、本地构建
2.1 为什么不在容器里构建
一个自然的想法是写个两阶段 Dockerfile:
FROM node:20-alpine AS build
WORKDIR /app
COPY . .
RUN npm ci && npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
这条路线不推荐:
npm install要拉几百个包,容器内网络不稳定时构建经常卡死或失败;- 每次改代码都重新拉基础镜像、重新装依赖,迭代慢;
- 构建环境的网络问题(代理、镜像源)在容器里更难排查。
实际做法:宿主机上构建,Dockerfile 只负责把 dist 丢进 nginx。构建是一次性动作(代码不变就不用重建),网络问题也隔离在宿主机侧。
2.2 构建步骤
# 1. 拉取源码
git clone https://github.com/OpenLegged/URDF-Studio.git
cd URDF-Studio
# 2. 安装依赖(国内网络建议走 npmmirror)
npm install --registry=https://registry.npmmirror.com
# 3. 构建
npm run build
产物在 dist/ 目录。
Node 版本要求 20+。
如果npm install慢或失败,可全局设置镜像源npm config set registry https://registry.npmmirror.com,或配代理npm install --proxy http://127.0.0.1:7890(按实际代理端口)。
三、容器化:nginx 镜像
3.1 Dockerfile
# 单阶段 — 只挂载已有 dist
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx.d/ /etc/nginx/conf.d/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
基础镜像 nginx:alpine 拉不到时,换任意可达镜像源/本地 registry 的等价镜像即可。
3.2 nginx.conf(主配置)——关键部分
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# ⚠️ 关键:COOP/COEP 跨域隔离头
add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;
add_header Cross-Origin-Resource-Policy same-site;
include /etc/nginx/conf.d/*.conf;
}
为什么必须有这三行:
URDF Studio 的 USD 场景功能依赖 Web 的 SharedArrayBuffer(多线程 3D 渲染)。浏览器规范规定 SharedArrayBuffer 只在跨域隔离(cross-origin isolated)的页面上可用,必须同时满足:
- 页面通过 HTTPS(或 localhost)访问;
- 响应头包含
Cross-Origin-Opener-Policy: same-origin和Cross-Origin-Embedder-Policy: require-corp。
缺任何一条,USD 相关功能在浏览器直接失效,页面通常会报 “SharedArrayBuffer is only available for cross-origin isolated contexts”。这三行不是可选优化,是功能前提。
Cross-Origin-Resource-Policy: same-site是配套资源头,防止子资源被跨站嵌入。
3.3 nginx.d/default.conf(站点配置)
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
# SPA 路由回退:未命中的路径都返回 index.html
try_files $uri $uri/ /index.html;
}
}
try_files ... /index.html 是 SPA 部署的标准写法,保证刷新 /settings 等深层路由不会 404。
3.4 构建并运行
docker build -t urdf-studio:latest .
docker run -d
--name urdf-studio
--restart unless-stopped
-p 3890:80
urdf-studio:latest
3.5 验证
# 状态码
curl -s -o /dev/null -w "%{http_code}n" http://localhost:3890/
# 期望 200
# COOP/COEP 头是否下发
curl -sI http://localhost:3890/ | grep -i "cross-origin"
# 期望看到三行 Cross-Origin-* 头
浏览器打开 http://localhost:3890/,DevTools → Application 里看 crossOriginIsolated:
- localhost 访问:应为
true,SharedArrayBuffer 可用,USD 功能完整(浏览器豁免 localhost); - 局域网
http://<IP>:3890访问:应为false(HTTP + 非 localhost),USD 功能不可用——这是浏览器规范限制,不是部署错误。需要完整 USD 功能就走 HTTPS 入口(前置反向代理 + 证书)。
四、踩坑记录
| # | 现象 | 原因 | 处理 |
|---|---|---|---|
| 1 | 两阶段 Dockerfile 构建卡死/失败 | 容器内 npm install 网络不稳定 |
宿主机本地构建 + 单阶段镜像挂载 dist |
| 2 | USD 功能报 SharedArrayBuffer 错误 | 缺 COOP/COEP 响应头,或页面非 HTTPS/localhost | nginx 加三行跨域隔离头;公网访问必须 HTTPS |
| 3 | 局域网 HTTP 访问 USD 不可用 | 浏览器只豁免 HTTPS 和 localhost | 预期行为;要完整功能用 HTTPS 入口 |
| 4 | 深层路由(如 /settings)刷新 404 |
nginx 缺 SPA 回退 | try_files $uri $uri/ /index.html; |
| 5 | 国内机器 npm install 极慢 |
默认 registry 是 npmjs.org | --registry=https://registry.npmmirror.com 或配代理 |
| 6 | 拉不到 nginx:alpine 基础镜像 |
网络问题 | 换镜像源或本地 registry 等价镜像 |
五、运维要点
- 镜像更新:代码改动 → 本地
npm run build→docker build→docker rm urdf-studio后重新docker run。镜像是纯静态、无状态、无数据卷,重建零成本。 - 进程守护:
--restart unless-stopped,宕机自动拉起。 - 数据安全:用户数据存浏览器本地(localStorage / IndexedDB),服务器不接触任何用户数据。如需公网访问,建议用 Nginx/Caddy 等反向代理前置 + Let’s Encrypt 签发 TLS 证书。
- 资源占用:nginx 容器内存占用 ~10MB 量级。部署机唯一硬性要求是 Docker + 构建时的 Node 20 环境(构建完 Node 可以卸掉)。
附:文件清单
URDF-Studio/
├── Dockerfile # 单阶段:nginx:alpine + dist + 配置
├── nginx.conf # 主配置:COOP/COEP 跨域隔离头
├── nginx.d/
│ └── default.conf # 站点配置:SPA 回退
└── dist/ # npm run build 产物(不入库)
附:在线示例与使用方法
作者部署的在线示例:https://urdf.gooney.fun/(按本教程部署,HTTPS 入口,USD 功能完整可用)。
使用方式(浏览器端操作,不涉及服务器):
- 导入:打开首页后通过 File 菜单/拖拽导入 URDF、MJCF、USD、Xacro、SDF 文件,也支持整个文件夹、ZIP 包或
.usp项目归档(包含 mesh 等多文件的完整工程)。 - 编辑:左侧文件树/结构树选择 link 或 joint,在 3D 画布中直接变换(transform controls 拖拽),右侧属性面板修改几何尺寸、质量、惯性、电机与硬件参数;顶部标签页在拓扑编辑、几何/碰撞/测量、硬件配置之间切换。
- 碰撞:在碰撞编辑模式下调整 collision mesh,检查 link 间的干涉,应用碰撞优化策略。
- 组装:导入多个机器人后通过 bridge joint 把它们装配进同一工作区,做组件级管理。
- 导出:选择目标格式(URDF / MJCF / USD / SDF / Xacro / CSV·BOM / PDF / ZIP /
.usp归档)导出;多文件工程用 ZIP 或.usp归档,保证 mesh 等资源不丢。 - AI 助手(可选):在设置里填入 OpenAI API key 后,可用自然语言生成机器人结构、跑自动化检查并导出 PDF/CSV 报告。
- 数据保存:所有数据存在浏览器本地(localStorage/IndexedDB),刷新页面不丢,但换浏览器或清浏览器数据会丢失未导出的工程——重要成果请及时导出归档。
USD 功能(.usd 预览/导出)仅在 HTTPS 或 localhost 入口可用(SharedArrayBuffer 限制);用 HTTP 直连 IP 访问时该部分不可用,属预期行为。
