面向客户交流的可回收物分拣中心三维数字孪生:一座完整厂房、两条分拣线、四类可回收物、进出货双向物流,以及按约 130 秒班次无缝循环的全流程动画。设备可点选查看状态与读数,参数干预默认关闭、开启后真实改变仿真结果。
在线演示(GitHub Pages) · 完整复现提示 · 发布验证记录
桐乡实际产线运行动画:基于实际 CAD 和已确认的 17 台设备工艺,提供独立动画、料仓联锁与共用打包流程。原演示保持独立,详见实际产线说明。
这是面向客户的概念演示,不是分选设备的控制或监控系统。 所有产能、识别率、节拍、吨位都是演示设定;光学分选与高光谱识别不接真实传感器、模型或 PLC / MES / WMS / 称重系统;机械臂抓取是动画概念,不是运动学或抓取力学仿真;叉车按预设航点行驶,没有自动调度、实时避障或碰撞物理。
逐字保留本次项目中可核验的初始用户请求,不把后续实现规格冒充历史提示。
参考其他子项目开发一个新的项目,做一个可回收物分拣中心数字孪生演示项目,面向客户进行展示,在执行前先和我讨论相关细节。我的想法是:能够看到完整的分拣中心,和全流程的运行动画,分拣中心里主要体现四类可回收物——塑料瓶、纺织品、纸板、杂项;其中塑料瓶分拣线包含:震动上料机(将压缩的塑料瓶打散便于分拣)、爬坡机(抬升塑料瓶高度便于后续分拣、使塑料瓶均匀分布),两台光选设备串联(通过摄像头识别并通过气吹分拣出不同材质的塑料瓶),输送带(负责将塑料瓶运送到不同的料仓),两个料仓(用于存储不同材质的塑料瓶——PET、HDPE),压缩打包机(当料仓储存量达到阈值时进行打包);纺织品分拣线包含:上料平铺机构(用于将进来的纺织物在输送带上进行平铺),高光谱分拣设备(通过高光谱识别出不同材质的纺织品),机械臂分选流水线(将不同材质的纺织品抓取到对应料仓中),料仓(用于存放不同材质纺织品——棉、涤纶、混纺);纸板和杂项只体现存储在分拣中心内即可,另外分拣中心内部还需要有叉车和运货车辆,运货车辆拥有进出货的功能,叉车则用于搬运进货车辆的进货到对应的处理位置以及搬运压缩打包机的出料到运货车辆上进行出货。全流程动画为从运货车辆进货开始,先根据进货类别(塑料瓶、纺织品)经过不同的分拣线进行识别分拣,最后打包完成出货。另外为了体现数字孪生的作用,针对以上提到的设备都可以通过点击查看对应的工作状态和模拟控制情况,以及一些其他的数据展示(每日进出货量、工作情况等等)
项目按用户要求先讨论方案,再执行。以下是逐字保留的决策答复:
按默认执行
用户在讨论稿上确认的四项关键选择:
1. 目录名与卡片标题:recycling-mrf-digital-twin
2. 技术栈:React 19 + TypeScript + React Three Fiber
3. 设备控制深度:分层,默认只读,可选「干预」模式
4. 播放模式:循环班次 + 时间轴可拖动 + 1/2/4 倍速
讨论稿中提出的其余细节按默认值执行,并记录在 复现提示 中:纸板配一台液压打包机、杂项只做存储与转运;三个纺织料仓共用一台打包机;设备名使用中文工艺名 + 英文缩写;异常演示开关三个;窄屏按仓库惯例折叠;数据看板含当日进出货量、回收率、分品类进出存、料仓水位、打包计数、车辆任务与近 7 日趋势。
视觉风格原定为「低多边形平涂」,2026-10-16 经客户反馈「建模比较简陋」后改为程序化微缩沙盘质感:保留「全部几何与贴图由代码生成、零外部资源」这条硬约束,改为用真阴影 + 程序化环境光 IBL + 三点光 + 自发光 + 程序化贴图 + 更高构件密度来提升观感。2026-10-19 的第二轮视觉验收又把色彩阶调整体压深一档、补光下调、背景改深(详见下文「验证与边界」),三维画面才第一次有了真实的暗部。改动记录见验证记录。
- 一条塑料瓶线:震动上料机打散瓶料包 → 爬坡机抬升并单层化 → 光选机 #1 识别 PET 气吹分流 → 光选机 #2 识别 HDPE 气吹分流 → 输送带把三路(PET / HDPE / 尾料)送入对应料仓 → 料仓达阈值后压缩打包机压成瓶砖。两级光选的次序不可颠倒:先分 PET,再分 HDPE。
- 一条纺织品线:上料平铺机构把织物摊成单层 → 高光谱分选设备按材质(棉 / 涤纶 / 混纺)给出目标料仓 → 机械臂分选流水线逐件抓取投放;无法识别的物料从尾料口转入杂项区。
- 纸板与杂项:不进入分拣线,只体现为存储区的堆存、打包与转运,进出量计入库存与台账。
- 双向物流:进货货车 A 运来塑料与纺织料包、转运货车 B 运来纸板与杂项并回程装走杂项、出货货车 C 在出货月台装走全部成品打包块后过磅离场。两台叉车按各自责任区搬运,跨区必须通过单行主通道,同一时刻只允许一台进入。
- 设备点选:左侧列表、三维场景与右侧详情三处联动;每台设备给出状态(运行 / 等待 / 待机 / 报警 / 已停机)、实时读数、上下游关系与工艺说明。
- 分层控制:默认只读;开启「干预模式」后才能修改带速、给料速率、识别阈值、气吹压力、抓取节拍、打包周期与料仓阈值,改动会真实影响后续仿真(例如把气吹压力降到 2 bar,瓶料会开始落入尾料区)。
- 异常演示:光选误判、料仓满溢预警(把报警线提前一包)、紧急停机三个开关,可一键演示异常与恢复;开关在暂停状态下也会立即反映到状态与报警上。
- 生产看板:顶栏给出当日进料 / 出货量、回收率、运行设备数与班次进度;右侧看板给出分品类进出存、料仓水位条(含阈值与预警线刻度)、本班次打包数与叉车趟数、搬运任务列表、转入杂项的尾料包数、丢失计数(应恒为 0),以及近 7 日进出货趋势(演示数据)。
- 时间轴:约 130 秒一个班次无缝循环,可拖动到任意时刻、可 1/2/4 倍速、可暂停复位,八个里程碑(进货车辆入场 / 塑料来料上线 / 首次光选分选 / 纺织来料上线 / 首件打包 / 首件成品装车 / 转运车离场 / 出货过磅)可直接点击跳转到该时刻;后台标签页不推进也不补算;系统偏好「减少动态效果」时默认暂停。
- 相机:默认「自由视角」,打开即可拖动旋转、滚轮缩放(竖屏会按宽高比自动拉远,整块沙盘入画);「俯瞰全厂」一键回到标准机位,「跟随选中设备」把机位推到所选设备近景。三种视角可随时切换,自由视角下不抢用户的镜头。
- 响应式:宽屏三栏并排(设备列表 / 场景与时间轴 / 详情与看板);≤1180 px 时右侧面板移到场景下方;≤820 px 时三块纵向堆叠、由页面统一滚动。里程碑标签会按导轨实际宽度自动错行,相机按钮浮在画布左下角,任何宽度下都不会出现按钮压时间轴或标签互相压字。
使用 Node.js 22 或更新版本,以及支持 WebGL 的现代浏览器。
cd recycling-mrf-digital-twin
npm ci
npm run dev -- --host 127.0.0.1 --port 5199 --strictPort以终端实际输出的地址为准;不要直接双击 index.html,请用 HTTP 访问。安装依赖需要网络,安装构建完成后页面运行不需要任何 CDN、在线模型、在线字体或第三方接口。
npm test # Vitest:仿真不变量、场景几何、整机联动、UI 组件、发布产物自包含
npm run build # tsc -b && vite build → dist/
npm run preview -- --host 127.0.0.1 --port 5200 --strictPortdist/ 是已提交的静态产物,使用相对 Vite base(base: './'),可以直接作为独立站点的根路径,也能挂到任意子路径下(例如放在另一个静态服务的子目录里)。
本项目是独立仓库,源码、发布产物与在线站点都只在自己这一处维护,不再挂在任何合集仓库里:
| 位置 | 地址 | 用途 |
|---|---|---|
| 仓库 | github.com/yuhaoxiong/recycling-mrf-digital-twin | 源码与发布产物 |
| 在线站点 | yuhaoxiong.github.io/recycling-mrf-digital-twin | 免安装、点开即看(GitHub Pages,HTTPS) |
发布方式是 GitHub Actions,工作流在 .github/workflows/deploy.yml:推到 main 后自动 npm ci → npm run build → npm test → 上传 dist/ → 发布到 Pages。先构建再测试,是为了让 tests/dist.test.ts 那组「发布产物自包含」断言真正执行——缺 dist/ 时它们会被静默跳过。
只想发到自己的服务器时,不需要 Actions:npm run build 产物就是 dist/ 三个文件,用任意静态服务器指向它即可(nginx 需要 try_files $uri $uri/ /index.html;)。不要用 file:// 直接双击 dist/index.html,ES module 需要 HTTP。
操作:打开即为「自由视角」,鼠标左键拖动旋转、滚轮缩放即可绕着厂房看;点「俯瞰全厂」回到标准机位,选中设备后可点「跟随选中设备」推到近景。点击设备查看状态;快捷键 空格 播放/暂停、1/2/4 切换倍速、R 复位、Esc 取消选中。
React 19、TypeScript、Vite 6、Three.js 0.177、React Three Fiber 9、Drei 10、@react-three/postprocessing 3(Bloom 与暗角)、Lucide 图标;Vitest 与 Testing Library 用于逻辑、几何与组件回归。全部几何为程序化生成的基础体,纹理由 scene/textures.ts 在运行时用 Canvas2D 画出来(混凝土地坪、彩钢瓦、橡胶皮带、纸板、木托盘、警示斜纹、文字贴花),环境光用 three 自带的 RoomEnvironment 经 PMREM 预卷积,界面使用系统字体回退——没有任何外部图片、模型或在线字体。设备同时给出中文工艺名、英文缩写(如 NIR-1)与英文全称,便于对照真实厂区的位号表。
src/
App.tsx 共享时钟、播放/倍速/拖动、选中状态、干预日志、键盘快捷键
types.ts 领域类型:物料、设备、料仓、车辆、叉车、命令、指标
simulation/
data.ts 设备清单、品类与折算质量、料仓容量与阈值、班次时刻表、控制项定义
prng.ts 种子化随机(mulberry32)——任何路径都不允许 Math.random
runtime.ts 干预日志求值、电源/效率模型、初始状态构造、物料守恒台账
lines.ts 塑料瓶线与纺织品线的输送与识别、机械臂、阈值打包、纸板打包
logistics.ts 货车进出货、叉车任务队列、单行主通道互斥、回程归位
readouts.ts 每台设备的状态与读数、KPI 与分品类统计
index.ts 定步引擎:createInitialState / stepOnce / stateAtStep / Simulation 时钟
context.ts React 上下文(仅承载时钟实例,不参与仿真逻辑)
spatial/layout.ts 全厂统一坐标基准:厂房、月台、皮带锚点、货位、路径航点与主通道
scene/ 三维表现层,只读仿真状态
MrfScene.tsx Canvas、三点光与阴影、雾与背景、相机机位与聚焦、后处理、失败提示
Environment.tsx RoomEnvironment + PMREM,程序化环境光(无 HDR 文件)
PostFX.tsx Bloom 与暗角(@react-three/postprocessing)
Factory.tsx 沙盘底座、地坪与划线、分区、钢柱、屋面桁架、卷帘门、雨棚、栏杆、灯带
Lines.tsx 塑料瓶线 8 台设备、纺织品线 4 台设备、五个料仓、三台打包机、地磅
Vehicles.tsx 三辆货车、两台叉车、物料单元、打包块与气吹特效
kit.tsx 构件原语:倒角板、方管/圆管、护栏、脚座、电机、百叶、螺栓排、控制柜、状态灯
palette.ts 全场景唯一色彩事实源
materials.ts 表面类型 → roughness / metalness / envMapIntensity
textures.ts Canvas2D 程序化贴图:地坪、环氧通道、彩钢瓦、皮带、纸板、木托盘、警示斜纹、文字
unitPositions.ts 物料在皮带上的位置(与仿真行程 s 同源)
parts.tsx 设备外壳(点选与高亮)与皮带变换
anchors.ts 每台设备的相机聚焦锚点
ui/
TopBar.tsx 指标摘要、播放与倍速、视角切换、干预模式开关
DeviceList.tsx 按产线分组的设备列表与搜索
EquipmentPanel.tsx 设备详情、读数、上下游、分层控制、异常开关、干预记录
Dashboard.tsx 分品类进出存、料仓水位、搬运任务、近 7 日趋势
Timeline.tsx 班次进度、里程碑跳转、事件流
styles.css 全部界面样式(深色工业风,含窄屏断点)
tests/ 仿真不变量、干预与清场重放、场景几何、里程碑一致性、整机联动、UI 组件、发布产物自包含
docs/ 复现规格与发布验证记录
整个演示是时间与干预日志的纯函数:状态只沿固定步长(1/30 s)前进,因此
- 暂停不改变轨迹,倍速只是每帧推进更多步,拖动时间轴回到任意时刻都得到完全相同的现场;
- 干预以「发生时刻 + 设备 + 参数 = 值」记入日志,重放时在记录时刻生效;拖到干预之前,历史状态自然还原;清除干预即回到默认轨迹;
- 一个班次是闭环:结束时全部物料都已随打包块或回程车辆出厂,料仓、存储区、任务队列全部清空,车辆离场、叉车回到起始位——所以循环播放不会出现漏料或视觉跳变。
关于闭环,有一处需要明说的演示约定:默认参数下现场在班末之前就已经自然清空,测试对此有断言;但如果通过干预把给料速率、带速或抓取节拍调得很低,一班之内无法处理完所有来料,此时 118 s 起的「班末清场」会把仍在厂内的物料一次性计入出场(日志会记录这一事件),以保证循环无缝衔接。这是为了让循环演示不出现残留,不是真实工厂的行为。
tests/simulation.test.ts 与 tests/replay.test.ts 把这些性质写成断言,包括:物料守恒(收到的每一包要么在厂内、要么已出厂,误差 0,丢失计数恒为 0)、料仓容量有界、只在阈值或班末清仓触发打包、PET 必须先于 HDPE 被分出、降低气吹压力只会把瓶料变成尾料而不会让物料消失、单行主通道互斥且确实发生过等待、两台叉车永不同位、同一步数状态完全一致、暂停/倍速/重置/拖动/带干预重放结果一致、默认参数下无需清场即闭合、极端干预与紧急停机下班次仍能收尾、看板每一行「进料 = 出货 + 在厂」、第二个班次与第一个班次逐位一致。
自动测试覆盖仿真不变量、场景几何(皮带变换与物料位置同源、同一时刻的可见物料互不重叠、跨区路径必经主通道、每台设备都有相机锚点)、UI 组件(列表↔详情联动、默认只读与干预分层、异常开关、看板与时间轴)、整机联动(选中/干预/异常/拖动/快捷键/搜索)以及发布产物的自包含性(只引用相对资源、无 CDN 主机名、无在线字体、无 sourcemap 引用)。
视觉验收(本轮补做):用 agent-browser(headless Chromium)对生产构建做了桌面 1440×900、1024×768、900×800 与窄屏 390×844 四档视口的截图与几何审计,截图见 docs/screenshots/,过程数据见 验证记录。结果为:页面错误 0 条、控制台 0 条输出、网络请求只有同源 3 条(文档 / JS / CSS,无任何外部主机或字体),四档视口下里程碑标签、相机按钮与时间轴、三栏之间的两两重叠面积均为 0。验收同时发现并修复了 5 处布局缺陷(相机按钮压住时间轴、里程碑标签压字、窄屏三栏互相叠盖、时间轴被挤出视口底部、窄屏提示压图例与料仓名截断)。
画质升级(2026-10-16):视觉风格从「低多边形平涂」改为「程序化微缩沙盘质感」,硬约束(零外部图片/模型/字体/CDN)未变:贴图全部由 Canvas2D 运行时生成,环境光用 three 自带的 RoomEnvironment。加了真阴影、程序化 IBL、三点光、Bloom 与暗角、构件原语库、厂房结构(桁架/墙板/卷帘门/雨棚/划线/栏杆)、设备细节(每台 20–60 个构件)与地面贴花文字。代价是构建产物从 1219.63 kB(gzip 344.81 kB)增至 1341.38 kB(gzip 379.51 kB),新增依赖 @react-three/postprocessing 3.2.0 + postprocessing 6.39.5。
第三轮修改(2026-10-19,客户反馈):①吊顶灯带的实体几何整组删除(8 组自发光长条横在视线上挡设备),只留不可见的补光;②整体提亮并提高饱和度——地坪 #b9c1c5、墙板 #d5dbde、背景 #9fb2bd,设备蓝 #3f7fa3 配安全黄 #f5c62d/橙 #ef8a2c,曝光 1.08;③按「几何审计」重排布局与动线:货车停靠点整体移到墙外的园区前场(车尾贴门、车身不再伸进厂房)、12 个叉车航点全部移到设备正面、修掉高光谱/平铺机构/取件带的「幻影几何」(装饰件曾堆在厂区原点刺进打包机)、纺织三仓与存储区重新让位、38 m 通栏栏杆改成短段——重排后 21 个实体包围盒两两零重叠、主通道无侵入。
仍未验证(如实记录):跨浏览器矩阵(Safari / Firefox)与真实触控手势未测;帧率只在 headless Chromium(ANGLE D3D11 / RTX 4070 Laptop)上测过(1440×900:暂停 151 FPS、1 倍速 122 FPS;headless 的 rAF 不受 vsync 限制,这两个数是渲染上限而不是屏幕刷新率,结论不可外推);未测显存占用与低端设备表现;约 130 秒班次只抽查了 0.0 s / 40 s / 100.0 s 三张静帧与一段 4 倍速播放;相机手感需真人在真实鼠标下体验;微缩视角下的观感未经多位客户样本人眼评价,直方图只能证明「不再浮白」,证明不了「好看」;构建产物未做拆包优化。
- 演示规模:每个班次进厂 16 个物料单元(塑料瓶 6、纺织 6、纸板 2、杂项 2),按各品类真实料包质量折算约 2.28 t。规模被压缩到能在一个班次内看清全流程;真实分拣中心的日处理量远高于此。
- 识别与分选是概率化的概念模型(阈值 × 气吹压力 × 异常开关),不模拟近红外光谱、气吹阀响应、物料姿态或分选精度标定。
- 机械臂是单臂串行抓取的动画概念,没有逆运动学解算、抓取力学、碰撞检测或视觉标定。
- 叉车按预设航点与固定主通道规则行驶,没有多车调度优化、动态避障、载重动力学或碰撞物理;采样式几何检查不能替代连续碰撞检测。
- 打包阈值、打包周期、料仓容量均为演示设定,不代表真实设备的液压曲线或产能标定。
- 看板数字全部为本地仿真值,不接入真实称重、PLC、MES、WMS、ERP 或任何后端服务,也不构成设备选型、产能测算、投资决策或工程验收依据。
- 浏览器图形上下文中断时会给出等待恢复提示;若初始化失败,设备列表、读数与看板仍可使用。
代码以 MIT License 发布(Copyright © 2026 yuhaoxiong),第三方依赖遵循各自许可证。
项目没有需要单独授权的素材:全部几何由代码生成,纹理由 scene/textures.ts 在运行时用 Canvas2D 绘制,环境光用 three 自带的 RoomEnvironment,界面只用系统字体——仓库里不存在外部图片、模型、字体或音视频文件。项目名称、设备位号与看板文案均为演示自拟,不对应任何真实厂区或品牌。