
上个月帮一个同事看数据大屏需求甲方点名要 3D 地球、飞线、柱状图、动态指标卡最好还能用鼠标拖拽旋转。他的第一反应是 Vue 3 配 Three.js结果光是搭环境、调 Canvas 尺寸、处理组件卸载时的 WebGL 上下文就耗了大半天真正往场景里“放东西”还没开始。我建议他用 Trae 的 Agent 能力和 Skill 机制重新试一遍——不是让 AI 一键生成整套系统而是把 3D 可视化里最常见的几个流程拆成可复用的技能再让 AI 按技能执行。试完一圈后一个更清晰的判断出来了用 Trae Skill Vue Three.js 搭 3D 可视化大屏真正的难点从来不是“让 AI 写出一个能转的 3D 场景”而是“把 AI 生成的结果放进工程化流程里稳定运行”。Skill 的长期价值也不是帮你省一次写代码的时间而是让每一次调试经验都能沉淀成下一次复用的起点。1. 3D 数据大屏是一个“看着简单、做着麻烦”的典型项目1.1 大屏需求的复杂性被严重低估了很多第一次接大屏需求的人会以为3D 可视化大屏就是“放一个地球插几根柱子把数字贴上去”。真正动手之后才会发现一个能交付的大屏至少要同时处理五类问题数据怎么来接口字段、模拟数据、实时推送、历史数据回放。坐标怎么映射经纬度、指标数值、类别如何映射到 3D 场景中的位置、高度、颜色。视觉怎么统一大屏通常有深色背景、科技感边框、动态光效3D 场景要嵌进去需要考虑背景透明、灯光强度和材质风格。交互怎么做鼠标悬停、点击选中、摄像机视角切换、数据钻取。性能怎么兜底大屏通常要 7x24 小时挂在会议室或展厅的屏幕上内存泄漏、帧率下降、GPU 上下文耗尽都是很现实的问题。这些问题的复杂度在需求评审时通常被压缩成一句“做个 3D 大屏”但在开发阶段会全部展开。1.2 没有 AI 辅助时团队怎么开发这类项目过去做这类大屏主流程通常是前端工程师先搭 Vue 或 React 工程。单独引入 Three.js再安装一个轨道控制器OrbitControls方便演示。手写一个基础的场景初始化函数创建场景、相机、渲染器、灯光写动画循环。根据设计稿和数据结构用BufferGeometry或第三方模型做地球、飞线、柱体。把 2D 图表ECharts 之类和大屏 UI 面板拼在一起。反复调整相机位置、材质颜色、光效和交互。这个流程最大的问题是每一步都在做重复劳动。场景初始化、生命周期清理、响应式 resize、飞线动画、柱状图生成——这些代码在不同项目里高度相似但你每次还是得重新写一遍。团队成员如果有人写过一次可以复制粘贴如果没人写过就只能在 Stack Overflow 和官方文档之间来回横跳。1.3 AI 真正能帮上忙的点在哪儿用 AI 编程工具做过前端的人会有一种共鸣让 AI 生成“一段能运行的 Three.js 代码”很容易难的是让代码符合你的工程习惯、数据结构和性能要求。我试下来的体感是AI 在三个环节能明显提速快速生成基础场景场景、相机、渲染器、灯光、动画循环这些脚手架代码描述清楚就能生成。按需调整 API 写法Three.js 版本更新很快不同版本 API 有变化AI 可以帮你按当前依赖版本调整写法。批量生成重复组件多个面板、多组柱状图、多条飞线只要给出数据和样式约定AI 能按套路产出。但这里有个前提你必须先理解场景、相机、坐标系、生命周期这些基础概念。否则 AI 生成一个能看的旋转立方体你不知道怎么改成地球AI 把渲染器放进组件里你不知道为什么页面切走再切回来就报 WebGL context lost。2. 技术栈选择为什么是 Trae、Skill、Vue 3、Three.js2.1 Trae 在这种工作流里扮演什么角色Trae 本质上是一个 AI 原生的 IDE它不只是“对话框里生成代码”这么简单。它可以理解当前打开工程的结构知道你现在用的是 Vue 3 还是 React知道你的依赖文件里有什么然后基于整个上下文去修改代码。对大屏开发来说这个能力比“生成一段孤立的代码”重要得多。因为 3D 大屏不是单文件项目而是涉及组件、路由、数据接口、样式文件的综合工程。如果 AI 只能生成代码片段最后还是要靠人把它们拼起来如果 AI 能理解工程结构就能直接帮你在src/components下新建组件在router里加路由在package.json里加依赖。这并非说 Trae 能替代人。实际用下来它的输出更像一个“理解力不错但需要审查的实习生”。你给它明确的目标、约束、参考文件它产出的代码基本能跑但你让它自由发挥它可能写出一个很炫但不符合业务结构的组件。所以要把它当成“加速器”而不是“外包”。你负责定方向、做架构、兜边界它负责按方向快速落地。2.2 Skill把“一次性提示词”变成“可复用工作流”Trae 这类 AI IDE 里的 Skill可以理解为一段封装好的“技能声明”。它把完成某类任务所需要的角色设定、执行步骤、输出格式、参考约定写下来之后每次触发同类任务时AI 会按照这份声明去执行。举一个很直白的类比过去你在 ChatGPT 里写一大段提示词指定“你是一个 3D 前端工程师请用 Three.js 生成一个场景”这只能解决一次。Skill 相当于把这段提示词沉淀成一份团队内部的操作手册下次不用重新写一遍直接说“用 Three.js 大屏技能生成一个地球场景”AI 就能自动按手册走。常见的 Skill 描述文件会包含以下信息技能名称和描述什么时候该用这个技能。适用技术栈Vue 3 Vite Three.js 还是 React ECharts。执行步骤先做什么、再做什么、最后输出什么。代码规范组件命名、目录结构、样式方案。关键约定比如渲染器必须开启 antialias、容器尺寸必须跟随父元素、组件卸载时必须销毁 WebGL 上下文。不同工具对 Skill 的具体格式定义会有些差异有的用 Markdown 描述文件有的支持 JSON/YAML 配置有的还允许挂载可执行脚本或外部工具。落地之前第一件事是先看当前使用的 Trae 版本支持哪种格式再照着官方文档建一个最小可用的示例不要凭感觉写。从长期看Skill 最有价值的不是“给 AI 下指令”而是把团队的开发经验标准化。新成员加入时不需要把积累了三年的踩坑点背下来只需要按 Skill 的约定执行就能避开大部分低层级问题。2.3 Vue 3 Three.js 为什么是合适的组合很多人在 Three.js 官方文档里看到的示例都是纯 JavaScript 写的直接在一个 HTML 文件里创建场景。到了真实项目里这样做基本不可用因为页面状态、组件生命周期、数据更新都没办法管。Vue 3 和 Three.js 是互补的关系Vue 负责属于页面的部分大屏的标题、指标卡、图表面板、路由跳转、数据请求和状态管理。Three.js 负责属于 GPU 的部分3D 场景、相机、模型、材质、灯光、动画、拾取。两者通过 Vue 组件的ref和onMounted/onBeforeUnmount生命周期建立连接。实际开发中我会把 Three.js 封装成一个相对独立的 Vue 组件组件只对外暴露一些必要的方法或事件比如setData、flyTo、onItemClick。外层业务逻辑不直接操作 Three.js 对象而是通过组件接口驱动。这样 3D 场景可以复用到多个大屏项目里数据层和渲染层也能解耦。2.4 什么情况下不适合用这个组合这个组合不是万能的。如果你的需求只是用圆柱体展示几个指标或者只需要炫酷的边框和渐变直接用 ECharts 加 CSS 效果可能更快也更稳定。如果场景里需要实时渲染几千个动态物体比如城市级粒子、海量飞线那么“Vue 组件 Three.js 对象”这种高层封装反而可能成为瓶颈更多时候需要直接在 Three.js 底层做 InstancedMesh 或自定义 Shader这时候前端的框架介入程度要更轻。所以选型时要先问一个问题这个 3D 是核心还是点缀如果只是视觉装饰用 Three.js 会带来不少维护成本如果是核心业务表达比如地理数据分析和城市态势展示那么它值得进场。3. 从 0 到 1先用 Trae 和 Skill 搭出一个能跑的最小场景3.1 环境准备先跑通本地开发链路开始之前先确认本地环境是通的。以 Vue 3 Vite 为例通常需要Node.js 版本建议 18 以上具体以当前 Vite 和 Vue 版本要求为准。包管理器使用 npm、pnpm 或 yarn 任意一种。安装 Trae确认当前版本支持 Skill 和 Agent 模式。准备一个空工程目录。创建 Vue 工程时可以走 Vite 脚手架npm create vitelatest my-3d-dashboard -- --template vue进入工程目录后安装 Three.jscd my-3d-dashboard npm install three有些版本还需要安装types/three主要看你的项目是否使用 TypeScript。如果是 JavaScript 项目可以不装类型包但装了也不影响。需要特别提醒的是Three.js 的版本更新速度非常快不同版本的 API 会有调整。安装之后先到node_modules/three或者官方文档里确认你拿到的是哪个版本不要盲目相信网上的旧示例代码。这种版本差异最常见的影响就是某些方法被废弃、默认值被修改以及 WebGL 渲染器的参数行为变化。3.2 在 Trae 里创建一个可复用的 Skill创建一个最小可用的 Skill核心是定义一份“任务手册”。先不管复杂的工具调用就从一个简单的 Markdown 描述文件开始。很多 AI 编程工具会扫描项目目录下的.trae、.skills或类似目录读取其中的SKILL.md你需要根据实际工具文档确认路径和格式。一个示意结构大概是这样的--- name: vue-three-basic-scene description: 在 Vue 3 组件中创建 Three.js 基础场景包含渲染器、相机、灯光和动画循环 --- ## 适用场景 当你需要在 Vue 3 项目里创建一个 Three.js 3D 场景时使用本技能。 ## 执行步骤 1. 确认目标组件使用 script setup 语法。 2. 从 three 包引入需要的模块。 3. 在模板中创建一个根容器 div refcontainerRef。 4. 在 onMounted 中创建场景、相机、渲染器并挂载到容器。 5. 设置渲染器 antialias: true。 6. 设置 renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))。 7. 添加相机、灯光、基础几何体。 8. 启动动画循环。 9. 在 onBeforeUnmount 中取消动画循环、移除 resize 监听、销毁 renderer。 ## 输出约定 - 组件命名使用 PascalCase。 - 容器样式为 width: 100%; height: 100%。 - 所有 Three.js 对象创建逻辑放在 initScene 函数内。这里的字段和格式不需要死记因为不同产品会有自己的约定。关键是理解它的设计思路你希望 AI 在“创建三维场景”这件事上每次都能按同样的规范来执行而不是自由发挥。3.3 让 Skill 生成第一个 Three.js 组件创建好 Skill 之后可以在 Trae 的对话窗口里输入一个清晰的任务描述。比如“使用 vue-three-basic-scene 技能在 src/components 下新建 ThreeScene.vue实现一个带旋转立方体的基础 3D 场景。容器使用模板 ref渲染器开启抗锯齿组件卸载时释放资源。”Trae 会根据 Skill 里的步骤生成代码。生成的组件结构通常是这样template div refcontainerRef classthree-container/div /template script setup import { ref, onMounted, onBeforeUnmount } from vue import * as THREE from three const containerRef ref(null) let renderer null let animationId null function initScene() { const container containerRef.value if (!container) return const scene new THREE.Scene() const camera new THREE.PerspectiveCamera( 45, container.clientWidth / container.clientHeight, 0.1, 1000 ) camera.position.set(5, 4, 6) camera.lookAt(0, 0, 0) renderer new THREE.WebGLRenderer({ antialias: true }) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) renderer.setSize(container.clientWidth, container.clientHeight) container.appendChild(renderer.domElement) const box new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial({ color: 0x4f7cff }) ) scene.add(box) const light new THREE.AmbientLight(0xffffff, 1) scene.add(light) function animate() { animationId requestAnimationFrame(animate) box.rotation.x 0.01 box.rotation.y 0.01 renderer.render(scene, camera) } animate() } function handleResize() { if (!containerRef.value || !renderer) return const width containerRef.value.clientWidth const height containerRef.value.clientHeight renderer.setSize(width, height) } onMounted(() { initScene() window.addEventListener(resize, handleResize) }) onBeforeUnmount(() { cancelAnimationFrame(animationId) window.removeEventListener(resize, handleResize) if (renderer) { renderer.dispose() renderer.domElement.remove() } }) /script style scoped .three-container { width: 100%; height: 100%; } /style这只是示意代码实际版本可能略有差异。重点是整套生成流程是可控的先生成基础场景确认它能运行再让它继续扩展。这里有一个很关键的体感不要一上来就让 AI 生成一个包含 20 个功能点的完整大屏场景。AI 一旦同时处理太多需求很容易遗漏生命周期清理、resize 处理、资源释放这类“细节”而这些细节恰恰是大屏项目最容易出问题的地方。正确做法是先跑通最小场景再一步一步叠加能力。3.4 把场景接进 Vue 大屏页面场景组件生成之后就可以把大屏的其余部分拼接进来。典型的大屏页面结构是顶部标题栏左侧指标面板右侧图表面板中间是 Three.js 场景页面宽度通常按 1920 设计通过 CSStransform: scale()适配不同分辨率。Three.js 场景放在中间区域时要注意容器高度不能是 0否则 Canvas 不会被正确渲染。如果大屏系统有多个页面比如总览、详情、配置页就需要 Vue Router。使用路由时要注意部署到服务器子路径时createWebHistory的base要配置正确否则刷新后 404。大屏页面之间切换时3D 组件会在beforeUnmount和mounted之间反复执行要确认没有注册重复的 resize 监听器也没有创建多个 WebGL 上下文。4. 把大屏从“能看”变成“能用”数据、交互和性能4.1 数据从哪里来接口、静态 JSON 和真实业务的边界3D 可视化大屏的数据通常来自后端接口但开发初期很少有稳定可用的接口。更合理的做法是先用静态 JSON 模拟一套数据结构跑通渲染逻辑再切换到真实接口。设计数据结构时要考虑 3D 场景需要什么而不是直接把后端返回字段塞进去。比如一个飞线图需要的是{ links: [ { from: [116.4, 39.9], to: [121.47, 31.23], value: 100 } ], points: [ { name: 北京, lon: 116.4, lat: 39.9, value: 100 } ] }这类数据通常要经过一个适配层把后端字段转换成前端渲染需要的结构。如果后端字段变化只需改适配层不要改 Three.js 渲染逻辑。这里最容易踩的坑是有一个字段是 null导致坐标计算变成 NaN然后你看到的是场景里少了一根柱子、一条线而不是报错。这种情况排查起来很费时间所以要在一开始就做数据校验和兜底。4.2 坐标系统经纬度、数值和 3D 位置的映射地理数据驱动的 3D 可视化最核心的一步是把经纬度映射到 Three.js 坐标系。如果是平面地图可以使用一个缩放函数把经纬度线性映射到平面上如果是球状地球就需要把经纬度转换成球面坐标通常用到三角函数function latLonToPosition(lon, lat, radius) { const phi (90 - lat) * Math.PI / 180 const theta (lon 180) * Math.PI / 180 return new THREE.Vector3( -radius * Math.sin(phi) * Math.cos(theta), radius * Math.cos(phi), radius * Math.sin(phi) * Math.sin(theta) ) }这不是唯一写法但它是常见的思路。这里的radius就是地球模型的半径你需要根据场景尺寸来定。指标数值比如 GDP、流量、用户数映射到柱体高度时通常需要做归一化避免某个超大值把场景撑爆。常见做法是取最大最小值做一个线性映射或使用对数映射处理跨度很大的数据。要特别注意3D 场景里柱状图的高度和真实数值之间不是简单的“1:1”关系而是视觉比例关系。调参时先固定一个基准值再根据整体视觉效果微调不要花时间精确计算像素对应关系。4.3 交互点击、悬停和视角切换大屏不是“只能看”的演示动画通常还需要点击柱子、飞线或模型查看详情。Three.js 里最常用的交互方式是 Raycaster基本原理是从摄像机发射一条射线经过鼠标位置检测射线和场景中哪些物体相交。const raycaster new THREE.Raycaster() const pointer new THREE.Vector2() function onPointerMove(event) { const el renderer.domElement const rect el.getBoundingClientRect() pointer.x ((event.clientX - rect.left) / rect.width) * 2 - 1 pointer.y -((event.clientY - rect.top) / rect.height) * 2 1 raycaster.setFromCamera(pointer, camera) const intersects raycaster.intersectObjects(clickableObjects, true) // 根据 intersects 结果触发 Vue 事件 }交互逻辑不建议全部写在 Three.js 组件里。更好的做法是Three.js 组件只负责检测到“用户点击了某个对象”然后把对象 ID 或数据索引通过自定义事件抛出去由外层 Vue 组件负责展示详情面板、跳转路由或更新图表。视角切换也是大屏常用的交互。可以使用 OrbitControls 让用户自由旋转也可以自己写一段相机飞行动画在点击某个区域时让镜头平滑移动过去。相机动画的难度不高但要注意避免和 OrbitControls 的默认操作冲突。4.4 性能优化锯齿、像素比、帧率和大屏长跑问题大屏需要长时间运行性能不是“能动就行”而是要稳定。实际开发中最常见的性能问题是渲染锯齿和帧率波动。如果你的 Three.js 版本更新到较新版本后发现场景边缘出现明显锯齿很多人第一反应是“版本变了”。其实更常见的原因是项目里的渲染器没有开抗锯齿或者像素比设置不合理。排查建议按顺序来确认new THREE.WebGLRenderer({ antialias: true })写法是否正确。检查renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))如果设成 1在高分屏上会发糊。检查 CSS 是否用transform: scale()放大了 Canvas缩放会导致渲染清晰度下降。如果以上都没问题再检查系统和浏览器是否启用了 GPU 硬件加速。帧率问题最常见的来源是渲染了太多不必要的物体。比如飞线效果如果每根线都用独立几何体几百条以后就有明显压力更合理的做法是用LineSegments或InstancedMesh合并绘制。大屏挂机一个晚上后内存持续上涨通常不是硬件的锅而是代码泄漏。比较常见的泄漏点有更新场景数据时创建了新对象但没有移除旧对象。监听器重复绑定。组件卸载时没有销毁 renderer。定时器或requestAnimationFrame没有在组件卸载时取消。检查这类问题最直接的方式是打开浏览器开发者工具观察 Performance 面板里有没有持续增长的 GPU 显存或内存占用。5. 真正决定成败的不是 AI而是工程化兜底能力5.1 从“AI 生成代码跑不起来”开始的排查链路用 Trae 写 3D 大屏遇到问题不要慌更不要反复让 AI“猜一下哪里错了”。比较靠谱的做法是建立一套固定的排查顺序。第一步先看现象。是编译报错还是运行时黑屏还是页面崩掉现象不同排查方向完全不同。第二步看依赖和版本。Vue 3、Vite、Three.js 之间是否兼容是否存在 API 变更。很多所谓“生成代码跑不起来”其实不是代码逻辑错而是版本语法不兼容。第三步看容器尺寸。Three.js 的 Canvas 渲染区域由父容器撑开如果父容器高度为 0场景不会显示但也不报错。这是 3D 大屏最常见的“黑屏”原因。第四步看生命周期。组件从挂载到卸载再到重新挂载是否产生了多个 WebGL 上下文。浏览器的 WebGL 上下文数量有限一旦超过就会报错或直接空白。第五步看数据。场景里没有柱子、没有飞线大概率是数据为空或者经纬度格式不正确导致坐标计算变成 NaN。最后一步用最小化复现路径验证。新建一个只包含一个 BoxGeometry 的空组件确认基础场景能渲染然后再逐步加入模型、灯光、飞线、数据绑定。这一步可以帮你把问题边界快速缩小。5.2 常见坑点构建产物、模型资源和部署路径开发环境正常打包部署后大屏空白这类问题在大屏项目里很常见。多数组件是静态资源路径没有配置好。如果使用 Vite 构建项目部署在服务器的子目录下就必须在vite.config.js里配置baseexport default defineConfig({ base: /your-sub-path/ })如果加载外部模型文件比如glb或gltf优先把文件放在public/models目录下然后使用相对路径。不要放到src/assets里然后用绝对路径加载因为构建后的 hash 文件和资源复制逻辑不一样容易出问题。另一个隐蔽问题是“大屏页面在开发环境流畅部署到展厅以后卡顿”。这通常不是代码问题而是展厅的电脑没有开启 GPU 加速或者运行的是旧版浏览器。走访验收的时候可以先在设备上打开一个最简单的 Three.js 示例确认基础渲染正常再打开大屏这样能快速区分是性能问题还是环境问题。5.3 把一次搭建经验沉淀成团队可复用的 Skill当项目跑通之后最值得做的事不是庆祝而是把整个过程中的操作手册、参数约定和踩坑点整理进 Skill。比如你的团队已经确定了“Three.js 场景组件卸载时必须调用 renderer.dispose()”这个约定那么把它写进 Skill 描述文件里AI 在下一次生成代码时就会遵守。如果某次发现“渲染器必须开启 antialias”也把它写进去。这样 Skill 会随着项目经验增长越来越像团队的“内化规范”。这里要特别注意Skill 不是写了就自动生效的。不同的 AI IDE 对 Skill 的加载机制、触发方式、工具调用权限都有不同实现你需要先验证当前工具是否真的在任务执行时读取了这份描述。如果不生效调整格式和存放路径而不是继续往里面堆内容。还有一类风险要提醒网上有时候会出现各种“skill 插件包”“skill 脚本”“兑换码生成器”之类的东西来路不明。不要为了图方便直接下载未知来源的 Skill 脚本或插件。Skill 本质上是一段描述和可执行指令你执行它之前至少要能看懂它做了什么。涉及账号、鉴权、数据上报的行为尤其要警惕。5.4 这个方案的适用边界这个组合最适合的场景是中小规模的数据可视化大屏数据量不大、模型数量可控、主要展示地理信息或指标分布、运行设备正常。快速原型、内部管理大屏、ToB 项目的前期演示用它都能明显提速。不太适合的场景包括实时渲染几千上万个动态对象且需要极高帧率。复杂物理模拟或高精度建模。需要深度定制渲染管线比如自定义 Shader、后处理特效组合非常复杂。只需要一个好看的 2D 图表大屏没有真 3D 需求。在这些场景下团队需要的是更偏图形学或游戏引擎的解决方案而不是用 Vue 组件去套 Three.js。另外即使 AI 帮忙生成了代码项目的长期可维护性仍然取决于人。AI 生成的组件如果没有任何注释、没有统一命名规范、没有按团队结构组织三个月后维护的人还是要重读一遍。所以 Skill 里不仅要约束代码生成还要约束代码的可读性和工程规范。6. 回到最初的经验先跑通最小场景再做规模化那次帮同事调完大屏后他问了我一句话“既然 Trae 这么厉害是不是以后大屏项目可以完全交给 AI”我的回答是如果你只想要一个打开五分钟、演示完就关掉的 Demo也许可以如果你交付的是一个要长期在展厅运行、数据每天更新、业务人员要点击交互的系统那 AI 只能帮助你解决其中一部分效率问题真正的工程兜底还是得人来定。我一般会建议开发者在真正进入业务开发之前花半小时过一遍 Three.js 的基础概念场景、相机、渲染器、坐标系、生命周期、资源释放。理解了这些AI 生成代码时你才知道哪里需要改、哪里需要坚持、哪里需要把它挡住。下一步先建一个空的 Vue 工程放一个能旋转的立方体把环境跑通再让 Trae 用 Skill 生成一个带地球和飞线的场景最后接入你的真实数据和交互。不要急着把所有需求压进一次对话里。AI 编码的上限通常取决于你给它的上下文清晰度而你自己的工程判断力才是让这个组合真正变强的关键。