5 分钟接入
本页从零创建一个会旋转、可点击的 Entity。Engine 只在调用 createEngine() 时访问浏览器与 WebGL;模块导入本身保持 SSR-safe。
1. 安装
pnpm add @tripo3d/engine threethree 由宿主提供,版本需满足 >=0.183.0。
2. 创建 Engine
import { createEngine } from '@tripo3d/engine';
const engine = createEngine();Engine 已创建并暴露:
engine.canvas:Engine 唯一拥有的 Canvas;engine.renderer:原生WebGLRenderer;engine.world/engine.view/engine.camera:默认 World、全屏 View 与透视 Camera;engine.pipeline/engine.pointer:管线和鼠标事件控制面。
此时帧循环尚未启动。
默认 Canvas antialias 与 Pipeline 离屏 samples 都关闭。需要抗锯齿时,可按画质与性能要求显式启用 FXAA 或离屏 MSAA;两项设备配置彼此独立。
3. 接纳 Object3D 子树
import {
AmbientLight,
BoxGeometry,
DirectionalLight,
Group,
Mesh,
MeshStandardMaterial,
} from 'three';
const root = new Group();
const cube = new Mesh(
new BoxGeometry(),
new MeshStandardMaterial({ color: 0x4f8cff }),
);
root.add(cube, new AmbientLight(0xffffff, 1.5));
const keyLight = new DirectionalLight(0xffffff, 3);
keyLight.position.set(2, 3, 4);
root.add(keyLight);
// 一次性为 root 的完整 Object3D 子树建立 Entity binding。
const rootEntity = engine.createEntity(root);
engine.world.root.add(rootEntity);
const cubeEntity = engine.getEntity(cube)!;createEntity(root) 要求 root.parent === null,并全量绑定整棵子树。接纳后,层级变化只通过 Entity.add/remove/attach/clear/removeFromParent 完成;不要再直接调用原生 Object3D.add/remove/attach。
4. 添加 Component、System 与 Script
import {
createComponent,
createEvent,
createScript,
createSystem,
} from '@tripo3d/engine';
const Rotation = createComponent('rotation-speed', ({ entity, onDestroy }) => {
const state = { speed: 1 };
const name = entity.object.name;
onDestroy(() => console.log(`${name} rotation state removed`));
return state;
});
const selected = createEvent<string>('selected');
const SpinSystem = createSystem('spin', ({ engine, onUpdate }) => {
const query = engine.world.createQuery(Rotation);
onUpdate(({ delta }) => {
query.forEach((entity) => {
entity.object.rotation.y += entity.getComponent(Rotation)!.speed * delta;
});
});
}, { order: 0 });
const Selectable = createScript('selectable', ({ emitEvent, entity, onDestroy }) => {
const off = entity.onPointer('click', () => {
emitEvent(selected, entity.object.name);
});
onDestroy(off);
});
cube.name = 'Cube';
const rotation = cubeEntity.addComponent(Rotation);
rotation.speed = 1.2;
cubeEntity.addScript(Selectable);
engine.addSystem(SpinSystem);
engine.onEvent(selected, name => console.log('selected:', name));Component、System 与 Script 都是同步 setup Definition。Component 为每个 Entity 建立局部状态并通过 onDestroy 持有 cleanup;System 服务整个 Engine;Script 服务一个 Entity。addComponent() 直接返回 setup 创建的原始对象,因此可以立即配置它。
5. 放入 DOM 并启动
const host = document.querySelector<HTMLElement>('#app')!;
host.append(engine.canvas);
engine.start();
// 暂停但保留场景和 GPU 资源:
engine.stop();
// 再次测量 Canvas 并继续:
engine.start();
// 最终释放:
engine.dispose();Engine 使用 Canvas 的 CSS content-box 作为逻辑尺寸来源。请给 host 与 Canvas 可测量的宽高;Engine 会处理 renderer、内部 Composer、默认 Camera aspect 与 DPR。
dispose() 是不可逆终态。它会销毁所有 Entity,并释放接纳子树的标准 geometry、material、direct texture 与 skeleton 资源;业务创建且借给 Pipeline 的 Camera 和原生 Pass 仍由业务释放。