拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Codex与tldraw结合:自然语言生成3D地球可视化应用

最近在探索 AI 与前端可视化结合的新玩法时发现了一个令人兴奋的技术组合通过 Codex 的自然语言指令直接操控 tldraw 画布实现一句话生成复杂的 3D 地球应用。这种描述即生成的开发模式正在改变我们构建交互式应用的方式。本文将完整介绍如何搭建这个技术栈从环境配置到核心代码实现带你一步步掌握用自然语言生成 3D 可视化应用的完整流程。无论你是前端开发者想探索 AI 赋能还是对 3D 可视化感兴趣的技术爱好者都能从本文获得实用的开发方案。1. 技术栈核心概念解析1.1 Codex自然语言到代码的桥梁Codex 是 OpenAI 开发的 AI 模型专门用于理解和生成代码。它能够将自然语言描述转换为可执行的代码片段支持多种编程语言。在本文的应用场景中Codex 负责解析用户对 3D 地球的描述如创建一个带有经纬线网格的蓝色地球并将其转换为 Three.js 或类似 3D 库的代码。Codex 的核心价值在于大幅降低了 3D 图形编程的门槛。传统上创建复杂的 3D 场景需要深厚的图形学知识和大量的代码编写而现在通过自然语言指令就能快速生成基础框架。1.2 tldraw无限画布与协作白板tldraw 是一个开源的无限画布应用提供丰富的绘图工具和协作功能。它采用可扩展的架构设计允许开发者通过插件方式扩展其功能。在我们的项目中tldraw 不仅作为绘图界面更重要的是作为用户与 Codex 交互的载体。用户可以在 tldraw 画布上绘制草图或添加文字描述这些内容会被实时捕获并发送给 Codex 进行处理。tldraw 的实时协作特性也为多人共同设计 3D 场景提供了可能。1.3 Three.jsWeb 3D 渲染引擎Three.js 是当前最流行的 Web 3D 库基于 WebGL 技术提供了高级的 3D 图形渲染能力。它封装了复杂的底层图形 API让开发者能够用相对简单的 JavaScript 代码创建复杂的 3D 场景、模型和动画。在我们的应用中Three.js 负责将 Codex 生成的 3D 地球代码渲染到网页中提供旋转、缩放、平移等交互功能确保用户能够从不同角度查看生成的 3D 地球。2. 环境准备与项目搭建2.1 开发环境要求确保你的开发环境满足以下要求Node.js 16.0 或更高版本npm 或 yarn 包管理器现代浏览器支持 WebGL稳定的网络连接用于调用 Codex API2.2 创建项目结构首先初始化一个新的 Node.js 项目# 创建项目目录 mkdir codex-tldraw-3d-earth cd codex-tldraw-3d-earth # 初始化 package.json npm init -y # 安装核心依赖 npm install tldraw tldraw/tldraw three types/three npm install --save-dev vite vitejs/plugin-react typescript创建项目文件结构codex-tldraw-3d-earth/ ├── src/ │ ├── components/ │ │ ├── TldrawCanvas.tsx │ │ ├── ThreeEarth.tsx │ │ └── CodexIntegration.tsx │ ├── utils/ │ │ ├── codexClient.ts │ │ └── threeHelpers.ts │ ├── App.tsx │ └── main.tsx ├── index.html ├── vite.config.ts ├── tsconfig.json └── package.json2.3 配置 Vite 开发环境创建vite.config.ts配置文件import { defineConfig } from vite import react from vitejs/plugin-react export default defineConfig({ plugins: [react()], server: { port: 3000, open: true }, build: { outDir: dist, sourcemap: true } })配置 TypeScript 编译选项tsconfig.json{ compilerOptions: { target: ES2020, useDefineForClassFields: true, lib: [ES2020, DOM, DOM.Iterable], module: ESNext, skipLibCheck: true, moduleResolution: bundler, allowImportingTsExtensions: true, resolveJsonModule: true, isolatedModules: true, noEmit: true, jsx: react-jsx, strict: true, noUnusedLocals: true, noUnusedParameters: true, noFallthroughCasesInSwitch: true }, include: [src], references: [{ path: ./tsconfig.node.json }] }3. 核心组件实现3.1 tldraw 画布组件创建src/components/TldrawCanvas.tsximport React, { useCallback } from react import { Tldraw, TDAsset, TDBinding, TDShape, TDDocument, TDUser, useFileSystem } from tldraw/tldraw interface TldrawCanvasProps { onShapeChange: (shapes: TDShape[]) void onTextChange: (text: string) void } export const TldrawCanvas: React.FCTldrawCanvasProps ({ onShapeChange, onTextChange }) { const handlePersist useCallback((document: TDDocument) { // 提取画布上的所有形状 const shapes Object.values(document.pages[document.currentPageId].shapes) onShapeChange(shapes) // 提取文本内容 const textContent shapes .filter(shape shape.type text) .map(shape (shape as any).text) .join( ) if (textContent) { onTextChange(textContent) } }, [onShapeChange, onTextChange]) const handleMount useCallback((editor: any) { // 设置画布初始提示文本 editor.createShapes([ { type: text, x: 100, y: 100, props: { text: 在这里描述你想要的3D地球...\n例如蓝色地球带有经纬线网格, color: black, size: m, font: draw, align: start, scale: 1, }, }, ]) }, []) return ( div style{{ width: 100%, height: 600px, border: 1px solid #ccc }} Tldraw onMount{handleMount} onPersist{handlePersist} showMenu{false} showPages{false} showStyles{false} showZoom{false} showUI{true} / /div ) }3.2 Codex 集成服务创建src/utils/codexClient.tsinterface CodexRequest { prompt: string max_tokens?: number temperature?: number } interface CodexResponse { choices: Array{ text: string index: number logprobs: any finish_reason: string } } export class CodexClient { private apiKey: string private baseURL: string https://api.openai.com/v1 constructor(apiKey: string) { this.apiKey apiKey } async generateThreeJSCode(description: string): Promisestring { const prompt 根据以下描述生成Three.js代码来创建一个3D地球 描述: ${description} 要求 1. 使用Three.js最新语法 2. 包含相机控制、光照和基础材质 3. 代码要完整可运行 4. 添加适当的注释 Three.js代码 const response await this.makeRequest({ prompt, max_tokens: 1500, temperature: 0.7 }) return response.choices[0]?.text?.trim() || } private async makeRequest(request: CodexRequest): PromiseCodexResponse { const response await fetch(${this.baseURL}/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${this.apiKey} }, body: JSON.stringify({ model: code-davinci-002, prompt: request.prompt, max_tokens: request.max_tokens, temperature: request.temperature }) }) if (!response.ok) { throw new Error(Codex API请求失败: ${response.statusText}) } return response.json() } } // 环境变量配置示例实际使用时请使用环境变量 export const codexClient new CodexClient(your-api-key-here)3.3 Three.js 地球渲染组件创建src/components/ThreeEarth.tsximport React, { useRef, useEffect, useState } from react import * as THREE from three interface ThreeEarthProps { earthCode?: string onRenderComplete?: () void } export const ThreeEarth: React.FCThreeEarthProps ({ earthCode, onRenderComplete }) { const mountRef useRefHTMLDivElement(null) const [scene, setScene] useStateTHREE.Scene | null(null) const [camera, setCamera] useStateTHREE.PerspectiveCamera | null(null) const [renderer, setRenderer] useStateTHREE.WebGLRenderer | null(null) useEffect(() { if (!mountRef.current) return // 初始化Three.js场景 const initScene () { const width mountRef.current!.clientWidth const height mountRef.current!.clientHeight // 创建场景 const scene new THREE.Scene() scene.background new THREE.Color(0x000000) // 创建相机 const camera new THREE.PerspectiveCamera(75, width / height, 0.1, 1000) camera.position.z 5 // 创建渲染器 const renderer new THREE.WebGLRenderer({ antialias: true }) renderer.setSize(width, height) mountRef.current!.appendChild(renderer.domElement) setScene(scene) setCamera(camera) setRenderer(renderer) // 添加基础光照 const ambientLight new THREE.AmbientLight(0x404040) scene.add(ambientLight) const directionalLight new THREE.DirectionalLight(0xffffff, 1) directionalLight.position.set(1, 1, 1) scene.add(directionalLight) return { scene, camera, renderer } } const { scene, camera, renderer } initScene() // 动画循环 const animate () { requestAnimationFrame(animate) if (scene camera) { renderer.render(scene, camera) } } animate() // 清理函数 return () { if (mountRef.current renderer?.domElement) { mountRef.current.removeChild(renderer.domElement) } renderer?.dispose() } }, []) useEffect(() { if (earthCode scene) { try { // 清空现有场景 while (scene.children.length 0) { scene.remove(scene.children[0]) } // 执行生成的代码 const createEarth new Function( THREE, scene, earthCode ) createEarth(THREE, scene) onRenderComplete?.() } catch (error) { console.error(执行生成的3D代码时出错:, error) // 创建默认地球作为回退 createDefaultEarth(scene) } } }, [earthCode, scene, onRenderComplete]) const createDefaultEarth (scene: THREE.Scene) { // 创建默认的蓝色地球 const geometry new THREE.SphereGeometry(2, 32, 32) const material new THREE.MeshPhongMaterial({ color: 0x1e90ff, specular: 0x555555, shininess: 30 }) const earth new THREE.Mesh(geometry, material) scene.add(earth) // 添加经纬线网格 const gridGeometry new THREE.SphereGeometry(2.02, 32, 32) const gridMaterial new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true, transparent: true, opacity: 0.3 }) const grid new THREE.Mesh(gridGeometry, gridMaterial) scene.add(grid) } return ( div ref{mountRef} style{{ width: 100%, height: 600px, border: 1px solid #ccc, background: linear-gradient(to bottom, #001122, #003344) }} / ) }4. 集成与交互逻辑4.1 主应用组件集成创建src/App.tsximport React, { useState, useCallback } from react import { TldrawCanvas } from ./components/TldrawCanvas import { ThreeEarth } from ./components/ThreeEarth import { codexClient } from ./utils/codexClient import ./App.css const App: React.FC () { const [earthCode, setEarthCode] useStatestring() const [isGenerating, setIsGenerating] useStateboolean(false) const [generationHistory, setGenerationHistory] useStatestring[]([]) const handleTextChange useCallback(async (text: string) { if (text.length 10) return // 忽略过短的文本 setIsGenerating(true) try { const generatedCode await codexClient.generateThreeJSCode(text) setEarthCode(generatedCode) setGenerationHistory(prev [...prev, text]) } catch (error) { console.error(生成3D代码失败:, error) alert(代码生成失败请检查API密钥和网络连接) } finally { setIsGenerating(false) } }, []) const handleShapeChange useCallback((shapes: any[]) { // 可以在这里处理图形变化比如根据绘制的形状生成对应的3D模型 console.log(画布形状变化:, shapes) }, []) const handleRenderComplete useCallback(() { console.log(3D地球渲染完成) }, []) return ( div classNameapp header classNameapp-header h1Codex tldraw 3D地球生成器/h1 p在左侧画布描述或绘制你想要的3D地球右侧将实时生成/p /header div classNameapp-content div classNamecanvas-section h2设计画布/h2 TldrawCanvas onShapeChange{handleShapeChange} onTextChange{handleTextChange} / div classNamegeneration-status {isGenerating ? 正在生成3D代码... : 准备就绪} /div /div div classNamepreview-section h23D预览/h2 ThreeEarth earthCode{earthCode} onRenderComplete{handleRenderComplete} / div classNamecode-preview h3生成的Three.js代码/h3 pre{earthCode || // 生成的代码将显示在这里}/pre /div /div /div {generationHistory.length 0 ( div classNamehistory-section h3生成历史/h3 ul {generationHistory.map((item, index) ( li key{index}{item}/li ))} /ul /div )} /div ) } export default App4.2 样式文件配置创建src/App.css.app { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; max-width: 1400px; margin: 0 auto; padding: 20px; } .app-header { text-align: center; margin-bottom: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 10px; } .app-header h1 { margin: 0 0 10px 0; font-size: 2.5em; } .app-header p { margin: 0; opacity: 0.9; font-size: 1.1em; } .app-content { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px; } .canvas-section, .preview-section { background: white; border-radius: 10px; padding: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .canvas-section h2, .preview-section h2 { color: #333; margin-top: 0; border-bottom: 2px solid #667eea; padding-bottom: 10px; } .generation-status { margin-top: 15px; padding: 10px; background: #f8f9fa; border-radius: 5px; text-align: center; font-weight: bold; color: #495057; } .code-preview { margin-top: 20px; } .code-preview h3 { margin-bottom: 10px; color: #333; } .code-preview pre { background: #f8f9fa; padding: 15px; border-radius: 5px; overflow-x: auto; max-height: 200px; font-size: 0.9em; border: 1px solid #dee2e6; } .history-section { background: white; border-radius: 10px; padding: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .history-section h3 { margin-top: 0; color: #333; } .history-section ul { list-style: none; padding: 0; } .history-section li { padding: 8px 12px; margin-bottom: 5px; background: #f8f9fa; border-radius: 5px; border-left: 4px solid #667eea; } media (max-width: 768px) { .app-content { grid-template-columns: 1fr; } .app-header h1 { font-size: 2em; } }5. 应用启动与测试5.1 主入口文件创建src/main.tsximport React from react import ReactDOM from react-dom/client import App from ./App ReactDOM.createRoot(document.getElementById(root)!).render( React.StrictMode App / /React.StrictMode )创建index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleCodex tldraw 3D地球生成器/title style body { margin: 0; padding: 0; background: #f5f5f5; } #root { min-height: 100vh; } /style /head body div idroot/div script typemodule src/src/main.tsx/script /body /html5.2 启动开发服务器在package.json中添加启动脚本{ scripts: { dev: vite, build: tsc vite build, preview: vite preview } }启动开发服务器npm run dev访问http://localhost:3000即可看到应用界面。5.3 测试用例验证测试不同的自然语言描述验证生成效果基础地球测试输入创建一个蓝色的3D地球带有经纬线网格预期生成蓝色球体带有白色网格线详细特征测试输入创建有陆地海洋区别的地球陆地绿色海洋蓝色添加云层效果预期生成有纹理差异的地球可能带有透明云层高级效果测试输入创建带自转动画的逼真地球有大气层光晕效果预期生成自动旋转的地球带有光晕特效6. 常见问题与解决方案6.1 Codex API 相关问题问题1API 密钥配置错误现象控制台报错 Codex API请求失败解决方案检查 API 密钥是否正确配置确认 API 密钥有足够的额度验证网络连接是否正常// 正确的API密钥配置方式 // 方式1环境变量推荐 const apiKey import.meta.env.VITE_OPENAI_API_KEY // 方式2配置文件 const apiKey process.env.REACT_APP_OPENAI_API_KEY问题2生成代码质量不稳定现象生成的 Three.js 代码有时无法运行解决方案优化提示词prompt的准确性调整 temperature 参数0.3-0.7 之间添加代码验证和错误处理机制6.2 Three.js 渲染问题问题13D 场景不显示现象画布空白控制台无报错解决方案检查 WebGL 支持detector.webgl验证相机位置和朝向确认光照设置正确// 检测WebGL支持 if (!Detector.webgl) { Detector.addGetWebGLMessage() }问题2性能问题现象3D 场景卡顿帧率低解决方案减少几何体面数使用 LODLevel of Detail技术优化材质和纹理大小6.3 tldraw 集成问题问题1画布事件不触发现象绘制内容变化时没有回调解决方案检查组件挂载顺序验证事件监听器是否正确绑定确认 tldraw 版本兼容性问题2自定义形状支持现象需要扩展 tldraw 支持更多图形类型解决方案实现自定义工具Tools扩展形状定义ShapeUtil注册自定义组件7. 高级功能扩展7.1 实时协作功能实现多用户同时编辑和查看 3D 生成结果// 使用Socket.io实现实时协作 import { io, Socket } from socket.io-client class CollaborationService { private socket: Socket constructor() { this.socket io(http://localhost:3001) } joinRoom(roomId: string) { this.socket.emit(join-room, roomId) } onEarthCodeUpdate(callback: (code: string) void) { this.socket.on(earth-code-update, callback) } broadcastEarthCode(code: string) { this.socket.emit(earth-code-broadcast, code) } }7.2 3D 模型导出功能添加将生成的 3D 地球导出为标准格式的功能import { GLTFExporter } from three/examples/jsm/exporters/GLTFExporter class ModelExporter { static exportToGLTF(scene: THREE.Scene): PromiseBlob { return new Promise((resolve) { const exporter new GLTFExporter() exporter.parse(scene, (gltf) { const blob new Blob([JSON.stringify(gltf)], { type: application/json }) resolve(blob) }) }) } static downloadBlob(blob: Blob, filename: string) { const url URL.createObjectURL(blob) const link document.createElement(a) link.href url link.download filename link.click() URL.revokeObjectURL(url) } }7.3 提示词优化模板创建针对不同 3D 效果的专用提示词模板const promptTemplates { basicEarth: 生成一个基础的3D地球模型包含以下特征 - 球体几何体 - 蓝色材质表示海洋 - 经纬线网格 - 适当的光照设置, realisticEarth: 生成一个逼真的3D地球模型包含 - 高分辨率纹理贴图 - 法线贴图增强立体感 - 镜面反射效果 - 大气层光晕 - 自转动画, stylizedEarth: 生成一个风格化的3D地球模型 - 卡通渲染风格 - 鲜艳的色彩 - 简化的几何形状 - 特殊的着色器效果 } export class AdvancedCodexClient extends CodexClient { async generateWithTemplate(templateType: keyof typeof promptTemplates, customDescription: string) { const basePrompt promptTemplates[templateType] const fullPrompt ${basePrompt}\n用户额外要求: ${customDescription} return this.generateThreeJSCode(fullPrompt) } }8. 生产环境部署8.1 构建优化配置优化 Vite 构建配置以提高性能// vite.config.prod.ts import { defineConfig } from vite import react from vitejs/plugin-react export default defineConfig({ plugins: [react()], build: { outDir: dist, sourcemap: false, minify: terser, terserOptions: { compress: { drop_console: true, drop_debugger: true } }, rollupOptions: { output: { manualChunks: { vendor: [react, react-dom], three: [three], tldraw: [tldraw/tldraw] } } } } })8.2 环境变量管理创建环境配置文件# .env.development VITE_OPENAI_API_KEYyour_dev_api_key VITE_API_BASE_URLhttp://localhost:3001 # .env.production VITE_OPENAI_API_KEYyour_prod_api_key VITE_API_BASE_URLhttps://api.yourdomain.com8.3 部署脚本创建自动化部署脚本#!/bin/bash # deploy.sh echo 开始构建生产版本... npm run build echo 检查构建结果... if [ -d dist ]; then echo 构建成功开始部署... # 这里添加你的部署逻辑 # 例如rsync到服务器、上传到CDN等 echo 部署完成 else echo 构建失败请检查错误信息 exit 1 fi通过本文的完整实现你已经掌握了使用 Codex 和 tldraw 创建智能 3D 地球应用的核心技术。这种自然语言驱动的前端开发模式为快速原型设计和创意表达提供了新的可能性。在实际项目中你可以根据具体需求进一步扩展功能如支持更多 3D 模型类型、集成更多 AI 能力或优化用户体验。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门