Skip to content

Vue 集成 ​

@tripo3d/engine/vue 提供两个薄适配:

  • Canvas:接管 Engine Canvas 的 DOM、start/stop 与最终 dispose;
  • createPluginVue():在构造期 markRaw Engine 初始公共 identity。

它们不把 Core 改造成 Vue runtime,也不提供内置 provide/inject。

Canvas ​

vue
<script setup lang="ts">
import { createEngine } from '@tripo3d/engine';
import { Canvas, createPluginVue } from '@tripo3d/engine/vue';
import { markRaw, onMounted, shallowRef } from 'vue';
import type { Engine } from '@tripo3d/engine';

const engine = shallowRef<Engine | null>(null);

onMounted(() => {
  engine.value = markRaw(createEngine({
    plugins: [createPluginVue()],
  }));
});
</script>

<template>
  <Canvas v-if="engine" :engine="engine">
    <div class="hud">普通 Vue overlay</div>
  </Canvas>
</template>

<style scoped>
.hud {
  pointer-events: auto;
}
</style>

Canvas 只接受一个必填 engine prop:

  1. mounted 时确认该 Engine Canvas 没有其他 DOM parent;
  2. 把 Canvas 插入内部 root 并调用 engine.start();
  3. prop identity 更换时先 stop/dispose/detach 旧 Engine,再接纳新 Engine;
  4. unmount 时自动 stop、dispose 并分离 Canvas。

Canvas 接纳 Engine 后取得最终 dispose authority。不要在父组件的 onBeforeUnmount 再重复销毁。

默认 slot 位于覆盖 Canvas 的 overlay 中;overlay 默认 pointer-events: none,交互控件需局部设置 pointer-events: auto。这样既保留 HUD,又不会让空白 overlay 阻断 Engine Pointer。

createPluginVue ​

ts
const engine = createEngine({
  plugins: [createPluginVue()],
});

Plugin markRaw 的初始 identity 包括 Engine、Canvas、renderer、默认 Camera/World/root/Scene、Pipeline、默认 View、Pointer 与 Raycaster。

它不处理之后动态创建的 Entity、Object3D、Camera、Pass 或业务状态。原因是 Plugin 静态且 Core 不提供实例拦截器。

响应式边界 ​

推荐只让 Vue 跟踪 UI 真正需要的少量标量:

ts
const engine = shallowRef(markRaw(createEngine()));
const selected = shallowRef<Entity | null>(null);
const ui = reactive({
  loading: false,
  selectedName: '',
});

function select(entity: Entity | null) {
  selected.value = entity === null ? null : markRaw(entity);
  ui.selectedName = entity?.object.name ?? '';
}
  • Engine/Entity/World/Camera/Material 等外部 identity 用 shallowRef;
  • 对即将进入 Vue state 的动态 Three.js/Engine 对象显式 markRaw;
  • 不要用 reactive(engine) 或普通 ref(threeObject);
  • Component/System/Script setup 返回值是普通业务 identity,若需要模板响应性,直接在业务 setup 中返回 Vue ref/reactive,或在组合层维护 UI state。

取消 Vue Plugin 也可以,只要业务始终用 shallowRef/markRaw 管理边界;Plugin 是便利性保护,不是 Core 正确性的前提。

页面结构建议 ​

Page.vue                    # 只组合 Canvas 与 controls
├── useEngineScene.ts       # 创建 Engine、场景与生命周期
├── engine/scene.ts         # 纯 Engine/Three Definition
└── SceneControls.vue       # props down / emits up,不持有 Engine

路由页保持组合层,副作用放 composable,Engine 领域定义保持纯 TypeScript。控制组件只接收可序列化状态并发出用户意图,避免 UI 树到处持有 renderer/scene。

SSR / Nuxt ​

Engine 模块导入 SSR-safe,但 createEngine() 需要 browser document/WebGL。VitePress/Nuxt 中在 mounted 后构造,并用 ClientOnly 避免服务端渲染 Canvas:

vue
<ClientOnly>
  <Canvas v-if="engine" :engine="engine" />
</ClientOnly>

若 Canvas 还未接纳前构造流程失败,创建者负责 dispose candidate;一旦 Canvas 接纳,最终销毁由 Canvas 负责。

下一步 ​

基于 MIT 协议发布(内部使用)