u-space 0.0.30 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/getTransferables-C97JPUVf.cjs +1 -0
- package/dist/getTransferables-DrzSmiCR.js +43 -0
- package/dist/index.cjs +3 -3
- package/dist/index.js +1549 -1026
- package/dist/modelDecodeProtocol-D1Apm9iG.cjs +1 -0
- package/dist/modelDecodeProtocol-wDB7ksYw.js +56 -0
- package/dist/src/loaders/ModelDecodeWorkerClient.d.ts +31 -0
- package/dist/src/loaders/ModelLoaderManager.d.ts +15 -2
- package/dist/src/loaders/buildDecodedGltfModel.d.ts +4 -0
- package/dist/src/loaders/index.d.ts +1 -0
- package/dist/src/objects/Model.d.ts +1 -0
- package/dist/src/worker/decodeGltfModel.d.ts +10 -0
- package/dist/src/worker/getTransferables.d.ts +1 -0
- package/dist/src/worker/index.d.ts +1 -0
- package/dist/src/worker/installWorkerImageLoader.d.ts +3 -0
- package/dist/src/worker/model-decoder.d.ts +13 -0
- package/dist/src/worker/modelDecodeProtocol.d.ts +205 -0
- package/dist/src/worker/workerImageUtils.d.ts +8 -0
- package/dist/worker/index.cjs +1 -1
- package/dist/worker/index.js +8 -6
- package/dist/worker/model-decoder.cjs +1 -0
- package/dist/worker/model-decoder.js +339 -0
- package/dist/worker/runtime.cjs +1 -1
- package/dist/worker/runtime.js +202 -208
- package/dist/workerImageUtils-lmOMyTQN.cjs +1 -0
- package/dist/workerImageUtils-mQD3TQ1N.js +105 -0
- package/docs/api-viewer.md +45 -1
- package/docs/changelog.md +15 -0
- package/docs/examples-guide.md +9 -3
- package/docs/getting-started.md +1 -1
- package/docs/index.md +1 -1
- package/docs/mcp.md +5 -3
- package/docs/release.md +5 -3
- package/package.json +9 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const s = {
|
|
2
|
+
colorSpaceConversion: "none",
|
|
3
|
+
premultiplyAlpha: "none"
|
|
4
|
+
};
|
|
5
|
+
function o(n, t) {
|
|
6
|
+
return n[t] | n[t + 1] << 8 | n[t + 2] << 16;
|
|
7
|
+
}
|
|
8
|
+
function c(n, t) {
|
|
9
|
+
return n[t] | n[t + 1] << 8;
|
|
10
|
+
}
|
|
11
|
+
function d(n, t) {
|
|
12
|
+
return n[t] | n[t + 1] << 8 | n[t + 2] << 16 | n[t + 3] << 24;
|
|
13
|
+
}
|
|
14
|
+
function f(n) {
|
|
15
|
+
return n === 192 || n === 193 || n === 194 || n === 195 || n === 197 || n === 198 || n === 199 || n === 201 || n === 202 || n === 203 || n === 205 || n === 206 || n === 207;
|
|
16
|
+
}
|
|
17
|
+
async function l(n, t, e) {
|
|
18
|
+
return new Uint8Array(await n.slice(t, t + e).arrayBuffer());
|
|
19
|
+
}
|
|
20
|
+
async function w(n) {
|
|
21
|
+
let t = 2;
|
|
22
|
+
for (; t + 4 <= n.size; ) {
|
|
23
|
+
const e = await l(n, t, Math.min(16, n.size - t));
|
|
24
|
+
let r = 0;
|
|
25
|
+
for (; r < e.length && e[r] === 255; ) r++;
|
|
26
|
+
if (r === 0 || r >= e.length) return null;
|
|
27
|
+
const h = e[r], i = r + 1, a = t + i;
|
|
28
|
+
if (h === 216 || h === 1 || h >= 208 && h <= 215) {
|
|
29
|
+
t = a;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (h === 217 || h === 218 || i + 1 >= e.length) return null;
|
|
33
|
+
const u = e[i] << 8 | e[i + 1];
|
|
34
|
+
if (u < 2) return null;
|
|
35
|
+
if (f(h))
|
|
36
|
+
return i + 6 >= e.length ? null : {
|
|
37
|
+
width: e[i + 5] << 8 | e[i + 6],
|
|
38
|
+
height: e[i + 3] << 8 | e[i + 4]
|
|
39
|
+
};
|
|
40
|
+
t = a + u;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
async function p(n) {
|
|
45
|
+
const t = await l(n, 0, Math.min(32, n.size));
|
|
46
|
+
if (t.length < 10) return null;
|
|
47
|
+
if (t[0] === 255 && t[1] === 216) return w(n);
|
|
48
|
+
if (t.length >= 24 && t[0] === 137 && t[1] === 80 && t[2] === 78 && t[3] === 71) {
|
|
49
|
+
const i = new DataView(t.buffer, t.byteOffset, t.byteLength);
|
|
50
|
+
return { width: i.getUint32(16), height: i.getUint32(20) };
|
|
51
|
+
}
|
|
52
|
+
if (t[0] === 71 && t[1] === 73 && t[2] === 70 && t[3] === 56) return { width: c(t, 6), height: c(t, 8) };
|
|
53
|
+
if (t.length >= 30 && t[0] === 82 && t[1] === 73 && t[2] === 70 && t[3] === 70 && t[8] === 87 && t[9] === 69 && t[10] === 66 && t[11] === 80) {
|
|
54
|
+
const i = String.fromCharCode(t[12], t[13], t[14], t[15]);
|
|
55
|
+
if (i === "VP8X")
|
|
56
|
+
return { width: o(t, 24) + 1, height: o(t, 27) + 1 };
|
|
57
|
+
if (i === "VP8 " && t[23] === 157 && t[24] === 1 && t[25] === 42)
|
|
58
|
+
return {
|
|
59
|
+
width: c(t, 26) & 16383,
|
|
60
|
+
height: c(t, 28) & 16383
|
|
61
|
+
};
|
|
62
|
+
if (i === "VP8L" && t[20] === 47) {
|
|
63
|
+
const a = d(t, 21);
|
|
64
|
+
return { width: (a & 16383) + 1, height: (a >>> 14 & 16383) + 1 };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
function g(n, t, e = 8192) {
|
|
70
|
+
if (n <= e && t <= e) return null;
|
|
71
|
+
const r = e / Math.max(n, t);
|
|
72
|
+
return {
|
|
73
|
+
width: Math.max(1, Math.round(n * r)),
|
|
74
|
+
height: Math.max(1, Math.round(t * r))
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async function m(n, t = {}) {
|
|
78
|
+
const e = {
|
|
79
|
+
...s,
|
|
80
|
+
...t,
|
|
81
|
+
colorSpaceConversion: "none"
|
|
82
|
+
}, r = await p(n), h = r ? g(r.width, r.height) : null;
|
|
83
|
+
if (h)
|
|
84
|
+
return createImageBitmap(n, {
|
|
85
|
+
...e,
|
|
86
|
+
resizeWidth: h.width,
|
|
87
|
+
resizeHeight: h.height,
|
|
88
|
+
resizeQuality: "high"
|
|
89
|
+
});
|
|
90
|
+
const i = await createImageBitmap(n, e), a = g(i.width, i.height);
|
|
91
|
+
if (!a) return i;
|
|
92
|
+
try {
|
|
93
|
+
return await createImageBitmap(i, {
|
|
94
|
+
...s,
|
|
95
|
+
resizeWidth: a.width,
|
|
96
|
+
resizeHeight: a.height,
|
|
97
|
+
resizeQuality: "high"
|
|
98
|
+
});
|
|
99
|
+
} finally {
|
|
100
|
+
i.close();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export {
|
|
104
|
+
m as c
|
|
105
|
+
};
|
package/docs/api-viewer.md
CHANGED
|
@@ -273,7 +273,7 @@ viewer.dispose();
|
|
|
273
273
|
|
|
274
274
|
## OffscreenCanvas Worker(实验性)
|
|
275
275
|
|
|
276
|
-
`u-space/worker` 提供一个独立入口,可将 `Viewer`、Three.js
|
|
276
|
+
`u-space/worker` 提供一个独立入口,可将 `Viewer`、Three.js 场景、相机控制和 WebGPU 渲染全部放入 dedicated render Worker。主线程只负责持有可见 canvas、转发输入事件与尺寸,并接收状态或渲染统计。模型默认仍在 render Worker 内加载;大型静态 glTF/SBMX 场景还可以 opt-in 第二个 decode Worker,让网络读取、SBMX 字节还原、JSON/base64 解析和图片解码不阻塞相机与已有场景的渲染。
|
|
277
277
|
|
|
278
278
|
Worker runtime 入口仅提供 ESM,需使用 `{ type: 'module' }` 创建 Worker。构建工具也必须保留 ES module 输出;Vite 项目需配置 `worker: { format: 'es' }`,否则 IIFE Worker 无法编译 top-level await。
|
|
279
279
|
|
|
@@ -304,6 +304,50 @@ await host.init();
|
|
|
304
304
|
|
|
305
305
|
`await host.init()` 只等待 Worker 创建 `Viewer`、完成 `await viewer.init()` 并发送 `initialized`,此时 WebGPU renderer 和内置 command 已可用,但 HDR、业务模型、editable batch、pipeline 预热和业务首帧可能仍在继续。`initialized` 事件与 `host.init()` resolve 表示同一个边界;`ready` 是业务层边界,只会在 Worker 代码显式调用一次 `worker.ready(detail)` 后触发。因此应在 `host.init()` 之前注册 `ready` / `status` / `stats` 等监听,业务 command 则通常在 `ready` 后调用。
|
|
306
306
|
|
|
307
|
+
### Worker 超大贴图保护
|
|
308
|
+
|
|
309
|
+
`createWorkerViewer()` 会在创建 `Viewer` 前安装 Worker 图片加载兼容层,同时覆盖 Three.js `ImageLoader` 和 glTF 常用的 `ImageBitmapLoader`。JPEG、PNG、GIF、WebP 在解码前读取编码尺寸;任一边超过 WebGPU 默认可移植上限 `8192` 时,会在第一次 `createImageBitmap()` 解码时按原宽高比缩小。无法预读尺寸的格式会在首次解码后检查,超限时生成缩放后的 bitmap,并立即 `close()` 临时原图。
|
|
310
|
+
|
|
311
|
+
该处理保留 `ImageBitmapLoader.setOptions()`、Three.js Cache、request headers、credentials 和 Loader/LoadingManager abort 语义,也不会修改磁盘或服务端源贴图。它避免在默认 `maxTextureDimension2D = 8192` 的 WebGPU device 上触发 `Texture size`,以及随后连续出现的 `Invalid TextureView`、`Invalid BindGroup` 和 `Invalid CommandBuffer`。即使 adapter 支持 `16384`,runtime 也不会强制申请更高 limit,以保持不同 GPU 的可移植性并限制超大贴图的显存占用。
|
|
312
|
+
|
|
313
|
+
自动缩放只覆盖经 `ImageLoader` / `ImageBitmapLoader` 加载的普通图片;KTX2 等压缩纹理由各自 loader 处理,业务仍应在资产管线中确保其尺寸不超过目标设备 limit。
|
|
314
|
+
|
|
315
|
+
### 独立模型 Decode Worker
|
|
316
|
+
|
|
317
|
+
在拥有 Three.js/WebGPU 的 render Worker 中,把一个专用 Worker 交给 `ModelLoaderManager`:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { ModelLoaderManager } from 'u-space';
|
|
321
|
+
import { createWorkerViewer } from 'u-space/worker/runtime';
|
|
322
|
+
|
|
323
|
+
const worker = await createWorkerViewer();
|
|
324
|
+
const modelDecodeWorker = new Worker(
|
|
325
|
+
new URL('./model.decode.worker.ts', import.meta.url),
|
|
326
|
+
{ type: 'module' },
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
const disposeModelDecodeWorker = ModelLoaderManager.setDecodeWorker(modelDecodeWorker);
|
|
330
|
+
worker.onDispose(disposeModelDecodeWorker);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
专用 decode Worker 入口不创建 `Viewer`,只安装解码协议:
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import { installModelDecodeWorker } from 'u-space/worker/model-decoder';
|
|
337
|
+
|
|
338
|
+
installModelDecodeWorker();
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
启用后,`ModelLoaderManager.loadAsync()` 会把受支持的静态 `.gltf`、`.glb` 和 `.sbmx` 请求排入 decode Worker。decode Worker 负责 fetch/Cache Storage、SBMX nibble swap、glTF JSON/base64/buffer 解析、普通图片解码和超大图片等比缩放;完成后以 transferable `ArrayBuffer` / `ImageBitmap` 把纯数据包发送给 render Worker。render Worker 才创建 `BufferGeometry`、`MeshStandardMaterial`、`Texture` 和 `Object3D`,因此 Three.js 对象和 GPU 资源仍只有一个 owner。
|
|
342
|
+
|
|
343
|
+
协议采用串行队列和 ACK backpressure:render Worker 重建完当前模型后才允许发送下一个大数据包,避免消息队列同时堆积多个模型副本。相同图片会按 SHA-256 内容身份复用已转移的 `ImageBitmap`,保持与 Three.js loader cache 一致的材质签名和 editable batching 数量;身份索引使用有界 LRU,不会随不同贴图持续增长。传输层直接使用浏览器 structured clone/transferable,没有额外二进制序列化依赖。
|
|
344
|
+
|
|
345
|
+
外部 buffer/贴图 URL 会回到 render Worker 经 `LoadingManager.resolveURL()` 处理,并完整触发 `itemStart` / `itemEnd` / `itemError`。模型请求的 headers 与 credentials 只会传给同源依赖;URL modifier 把依赖改写到其他 origin 时会自动去掉敏感 headers 并使用 `credentials: 'omit'`,避免授权信息泄漏给资产文件中声明的第三方地址。
|
|
346
|
+
|
|
347
|
+
当前快速路径只接受无 animation、skin、morph target、camera、sparse accessor、glTF extension/压缩扩展且 primitive mode 为 triangles 的 glTF 2 静态模型;节点图还必须满足无重复 child、无多父节点、无环及安全深度限制。其他受支持但不适合快速路径的模型会自动回退现有 `GLTFLoader` / `SBMXLoader`,不会降级功能;decode Worker 致命错误也会摘除失效 client 并回退当前请求。`ModelLoaderManager` 拥有传入的 Worker;再次调用 `setDecodeWorker()` 或传入 `null` 会 dispose 并 terminate 旧 Worker。`setDecodeWorker(worker)` 返回与该实例绑定的 disposer,建议交给 render runtime 的 `onDispose()`,避免旧清理回调误终止后来替换的 Worker。AbortSignal 同时覆盖 decode Worker 快速路径、普通 loader 顶层 fetch 和 glTF/SBMX 外部资源加载。
|
|
348
|
+
|
|
349
|
+
这个能力也可以在主线程的普通 `Viewer` 中启用,但它的主要收益是在 Offscreen render Worker 中把模型解码进一步拆开,使场景已可交互时仍能继续流式装载。它不减少网络体积、最终 GPU 内存或 draw calls;这些仍由资源压缩、instancing、editable batching、LOD 和裁剪解决。
|
|
350
|
+
|
|
307
351
|
### `OffscreenViewerHost`
|
|
308
352
|
|
|
309
353
|
构造选项:
|
package/docs/changelog.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## 未发布
|
|
4
4
|
|
|
5
|
+
## 0.0.31
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
|
|
9
|
+
- **嵌套模型 Decode Worker** — 新增 `u-space/worker/model-decoder` 和 `ModelLoaderManager.setDecodeWorker()`;静态 glTF/GLB/SBMX 可在 render Worker 之外完成 fetch/cache、SBMX 还原、JSON/base64/buffer 与图片解码,再以 transferable `ArrayBuffer` / `ImageBitmap` 交回 Three.js owner。协议使用单包 ACK backpressure、AbortSignal 和贴图内容身份复用,复杂 glTF 特性自动回退原 loader;Offscreen UManager 示例默认启用,并支持 `?modelDecodeWorker=off` A/B。
|
|
10
|
+
|
|
11
|
+
### 修复与优化
|
|
12
|
+
|
|
13
|
+
- **Offscreen 在线示例** — Vercel 发布现在通过专用 Vite 配置构建 `examples/offscreen/test_umanager2_offscreen.html`,输出可直接运行的主线程 JavaScript、ES module Worker 和 Draco/Basis WASM 资源,不再让生产页面直接加载 TypeScript;Worker 的 HDR URL 同时兼容本地 `/textures/` 与线上 `/examples/textures/` 路径。
|
|
14
|
+
- **Offscreen Worker 超大贴图** — Worker runtime 同时覆盖 Three.js `ImageLoader` 与 `ImageBitmapLoader`;JPEG/PNG/GIF/WebP 任一边超过 WebGPU 默认 `8192` 上限时,在首次 `createImageBitmap()` 解码时等比缩小并保留 loader options/cache/abort 语义,避免 `Texture size` 继续级联为 `Invalid TextureView`、`Invalid BindGroup` 和 `Invalid CommandBuffer`。未知格式在解码后缩放并释放临时原图,源资产不会被修改。
|
|
15
|
+
- **Offscreen UManager 设备调试** — 增加上一个/下一个设备、飞向、高亮和清除命令;语义楼层、墙体、空间、门窗和设备默认全部显示,设备切换、飞向和清除不再改变其他对象显隐。
|
|
16
|
+
- **模型 Decode Worker 稳定性与安全性** — 外部 buffer/贴图恢复 `LoadingManager.resolveURL()` 和完整 item 生命周期,跨域依赖不再继承模型请求的授权 headers/credentials;增加 glTF 节点图规模、深度、环、多父节点与重复 child 校验,并把贴图内容身份缓存改为有界 LRU。decode Worker 崩溃会自动摘除并回退当前请求,`setDecodeWorker()` 返回实例绑定 disposer,AbortSignal 也覆盖普通 loader 路径;失败的 `Model` 内存缓存 Promise 会被清除以允许重试。
|
|
17
|
+
|
|
18
|
+
## 0.0.30
|
|
19
|
+
|
|
5
20
|
### 新增
|
|
6
21
|
|
|
7
22
|
- **AO 示例** — 新增 `examples/test_ao.html`,通过 SSGI 的 `giIntensity: 0` 默认开启纯 AO,并提供遮蔽强度、半径和厚度实时调节。
|
package/docs/examples-guide.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## 运行方式与版本
|
|
6
6
|
|
|
7
|
-
示例统一通过 `examples/importmap.js` 注入 Import Map。本地通过 `localhost`、`127.0.0.1`、`0.0.0.0` 或 `192.168.x.x` 访问时会加载仓库里的 `../dist/` 构建产物;在线部署或非本地域名访问时会从 jsDelivr 加载当前发布版本 `u-space@0.0.
|
|
7
|
+
示例统一通过 `examples/importmap.js` 注入 Import Map。本地通过 `localhost`、`127.0.0.1`、`0.0.0.0` 或 `192.168.x.x` 访问时会加载仓库里的 `../dist/` 构建产物;在线部署或非本地域名访问时会从 jsDelivr 加载当前发布版本 `u-space@0.0.31`。Vercel 文档部署会继续把 `__VERSION__` 占位符替换为 `package.json` 中的版本号,源码里的 `0.0.31` 作为直接托管 `examples/` 时的 fallback。
|
|
8
8
|
|
|
9
9
|
插件示例可以在页面加载 `importmap.js` 前通过 `window.__IMPORTS__` 声明额外依赖。将 `u-space/plugins/<name>` 的值设为 `true` 时,`importmap.js` 会自动在本地和 CDN 路径之间切换。
|
|
10
10
|
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
|
|
103
103
|
## 8. `test_umanager2_offscreen.html`:OffscreenCanvas Worker + editable batching
|
|
104
104
|
|
|
105
|
-
该示例是 `test_umanager2.html` 的 Worker 版本。完整 `Viewer
|
|
105
|
+
该示例是 `test_umanager2.html` 的 Worker 版本。完整 `Viewer`、Three.js 对象重建、editable batch 构建、相机控制和 WebGPU 渲染运行在 dedicated render Worker;主线程只持有可见 canvas、转发输入/resize,并显示 Worker 返回的状态与统计。静态 SBMX/glTF 的 fetch、字节/JSON/base64 解析和图片解码继续拆到 render Worker 创建的第二个 decode Worker,因此加载新模型时已有 3D 场景仍可响应输入。
|
|
106
106
|
|
|
107
107
|
通过专用 Vite 配置启动:
|
|
108
108
|
|
|
@@ -110,12 +110,18 @@
|
|
|
110
110
|
pnpm example:offscreen
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
然后访问 `http://127.0.0.1:5510/offscreen/test_umanager2_offscreen.html`。该示例的 HTML、主线程入口、Worker 入口和专用 Vite 配置集中在 `examples/offscreen/`
|
|
113
|
+
然后访问 `http://127.0.0.1:5510/offscreen/test_umanager2_offscreen.html`。该示例的 HTML、主线程入口、Worker 入口和专用 Vite 配置集中在 `examples/offscreen/` 目录。可用 `pnpm build:example:offscreen` 验证生产构建。
|
|
114
|
+
|
|
115
|
+
[在线演示](https://u-space-phi.vercel.app/examples/offscreen/test_umanager2_offscreen.html)由一键发布流程单独打包:HTML 加载生成的 JavaScript,Worker 保持 ES module 格式,Draco/Basis WASM 等资源写入 `/examples/assets/`。线上页面不直接执行源码 `.ts`,HDR 则复用 `/examples/textures/puresky_1k.hdr`。
|
|
114
116
|
|
|
115
117
|
### 核心要点:
|
|
116
118
|
|
|
117
119
|
- 主线程使用 `OffscreenViewerHost` 调用 `transferControlToOffscreen()`,以 structured-clone 消息转发 pointer、wheel、resize 和业务 command。
|
|
118
120
|
- Worker 在模块顶层通过 `const worker = await createWorkerViewer()` 创建真正的 `Viewer`,随后以顺序式代码加载 HDR、`SemanticLoader` 和 `SceneLoader`,无需把整个入口包进 setup callback。
|
|
121
|
+
- render Worker 通过 `ModelLoaderManager.setDecodeWorker()` 启用 `test_umanager2_offscreen.decode.worker.ts`,并把返回的实例绑定 disposer 注册到 runtime 清理;decode Worker 从 `u-space/worker/model-decoder` 调用 `installModelDecodeWorker()`,以 transferable `ArrayBuffer` / `ImageBitmap` 返回静态 glTF 数据,Three.js/GPU 对象仍只在 render Worker 创建。外部 buffer/贴图继续经过 render Worker 的 LoadingManager URL modifier 与加载统计,跨域依赖不会继承模型请求的敏感 headers/credentials。
|
|
122
|
+
- 解码队列一次只允许一个待确认数据包;render Worker 重建后发送 ACK 再取下一项,防止 1GB 级场景同时堆积多个模型副本。相同图片通过有界 LRU 内容指纹复用 bitmap 身份,避免把原本 25 个 editable material batches 拆成大量重复批次,同时不永久持有所有历史贴图。
|
|
123
|
+
- animation、skin、morph、camera、sparse accessor、glTF extension/压缩扩展和非 triangle primitive 不进入快速路径,会自动使用现有 loader。访问 `?modelDecodeWorker=off` 可关闭嵌套 Worker,与原始 loader 做画面、批次和加载响应 A/B 对比;默认开启。
|
|
124
|
+
- Worker runtime 同时接管 Three.js `ImageLoader` 与 `ImageBitmapLoader`:JPEG/PNG/GIF/WebP 任一边超过 WebGPU 默认 `8192` 上限时,会在第一次 `createImageBitmap()` 解码时等比缩小,保留 loader options/cache/abort 语义且不修改源文件,避免 `Texture size` 引发的 WebGPU validation 级联错误。
|
|
119
125
|
- `await host.init()` / `initialized` 只表示 Worker 内 `viewer.init()` 完成;HDR、模型、editable batch、pipeline 预热和业务首帧完成后,Worker 才显式调用一次 `worker.ready(detail)`。主线程应先注册 `ready` 监听,再执行 `host.init()`,并在 `ready` 后调用业务 command。
|
|
120
126
|
- `SceneLoader.setEditableBatching()` 在 Worker 中完成 Geometry 克隆、变换烘焙、合并和 TSL 状态纹理创建;透明、蒙皮、morph、自定义 shader 等不支持子集保持 fallback。
|
|
121
127
|
- 首帧前关闭 controls invalidation 并等待 `renderer.compileAsync()`,预热 WebGPU 合批管线后再显示完整画面。
|
package/docs/getting-started.md
CHANGED
|
@@ -125,7 +125,7 @@ box.addEventListener('pointerleave', (e) => {
|
|
|
125
125
|
|
|
126
126
|
```typescript
|
|
127
127
|
import { version } from 'u-space';
|
|
128
|
-
console.log(version); // e.g. '0.0.
|
|
128
|
+
console.log(version); // e.g. '0.0.31'
|
|
129
129
|
|
|
130
130
|
// 也可以通过全局变量访问
|
|
131
131
|
console.log(window.__USPACE__.version);
|
package/docs/index.md
CHANGED
|
@@ -32,7 +32,7 @@ features:
|
|
|
32
32
|
|
|
33
33
|
| 文档 | 说明 |
|
|
34
34
|
| :--- | :--- |
|
|
35
|
-
| [Viewer](./api-viewer) |
|
|
35
|
+
| [Viewer](./api-viewer) | 核心类:渲染器、场景、相机、控制器、事件,以及带超大贴图保护的实验性 OffscreenCanvas Worker runtime |
|
|
36
36
|
| [CameraControls](./api-camera-controls) | 相机控制:飞行、视角切换、视点过渡 |
|
|
37
37
|
| [CSSRenderer](./api-css-renderer) | CSS 渲染器:CSS2D / CSS2.5D / CSS3D 叠加 HTML 元素 |
|
|
38
38
|
| [RenderPipeline](./api-render-pipeline) | 后处理管线:Bloom、SSGI、SSR 时空降噪、TRAA、自定义后处理 |
|
package/docs/mcp.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# u-space MCP
|
|
2
2
|
|
|
3
|
-
`u-space-mcp` 是面向 `u-space` 文档的 Model Context Protocol(MCP)服务器。它把当前文档打包成只读 MCP 工具,方便 Mastra、Claude Desktop、Cursor 等 MCP 客户端在回答 `u-space` API、插件和示例问题时直接检索官方文档,包括实验性 `u-space/worker` OffscreenCanvas runtime、`OffscreenViewerHost`、top-level await `createWorkerViewer()`、Worker command
|
|
3
|
+
`u-space-mcp` 是面向 `u-space` 文档的 Model Context Protocol(MCP)服务器。它把当前文档打包成只读 MCP 工具,方便 Mastra、Claude Desktop、Cursor 等 MCP 客户端在回答 `u-space` API、插件和示例问题时直接检索官方文档,包括实验性 `u-space/worker` OffscreenCanvas runtime、`OffscreenViewerHost`、top-level await `createWorkerViewer()`、Worker command/事件桥接、`ModelLoaderManager.setDecodeWorker()` + `u-space/worker/model-decoder` 嵌套静态模型解码、transferable/ACK backpressure、普通图片超过 WebGPU `8192` 上限时的解码前缩放、Three.js 原生静态场景矩阵策略及其与 `setEditableBatching()` 的组合;核心 `src/batches` 导出的 `ModelInstancedLayer` 与 `EditableGeometryBatchLayer`;`u-manager` 的 `UManagerLoader` 一体化加载入口、`SceneLoader` 语义去重、path-based model instancing 和 scene-specific editable batching adapter、Semantic/Facilities API,以及 atmosphere 和 fire 插件的 WebGPU 效果。
|
|
4
4
|
|
|
5
5
|
## 安装与启动
|
|
6
6
|
|
|
@@ -86,7 +86,7 @@ export const codingAgent = new Agent({
|
|
|
86
86
|
|
|
87
87
|
## 示例检索
|
|
88
88
|
|
|
89
|
-
MCP 文档索引包含 `examples/test_umanager_loader.html`、`examples/test_umanager_dynamic_instances.html`、`examples/test_umanager2.html` 和 `examples/offscreen/test_umanager2_offscreen.html` 的说明。检索 `UManagerLoader example`、`test_umanager_loader` 或 `UManagerLoader 用法` 可以找到一体化加载示例;检索 `dynamic instances`、`getInstanceById` 或 `test_umanager_dynamic_instances` 可以找到运行时实例编辑示例;检索 `setEditableBatching`、`SceneEditableBatchLayer`、`SceneEditableBatchFallback`、`editable batching`、`materialize` 或 `test_umanager2` 可以找到大型静态场景合批及其与 `SceneInstancedLayer` fallback 的关系;检索 `OffscreenCanvas`、`OffscreenViewerHost`、`host.init`、`initialized`、`ready`、`createWorkerViewer`、`top-level await`、`u-space/worker`、`Worker WebGPU` 或 `test_umanager2_offscreen` 可以找到 Worker
|
|
89
|
+
MCP 文档索引包含 `examples/test_umanager_loader.html`、`examples/test_umanager_dynamic_instances.html`、`examples/test_umanager2.html` 和 `examples/offscreen/test_umanager2_offscreen.html` 的说明。检索 `UManagerLoader example`、`test_umanager_loader` 或 `UManagerLoader 用法` 可以找到一体化加载示例;检索 `dynamic instances`、`getInstanceById` 或 `test_umanager_dynamic_instances` 可以找到运行时实例编辑示例;检索 `setEditableBatching`、`SceneEditableBatchLayer`、`SceneEditableBatchFallback`、`editable batching`、`materialize` 或 `test_umanager2` 可以找到大型静态场景合批及其与 `SceneInstancedLayer` fallback 的关系;检索 `OffscreenCanvas`、`OffscreenViewerHost`、`host.init`、`initialized`、`ready`、`createWorkerViewer`、`ModelLoaderManager.setDecodeWorker`、`model-decoder`、`decode Worker`、`transferable`、`ACK backpressure`、`ImageBitmapLoader`、`maxTextureDimension2D`、`oversized texture`、`top-level await`、`u-space/worker`、`Worker WebGPU` 或 `test_umanager2_offscreen` 可以找到 Worker 渲染、嵌套静态模型解码、生命周期、事件/command 桥接、超大贴图缩放、editable batching、pipeline 预热和主线程/GPU 性能边界。
|
|
90
90
|
|
|
91
91
|
## OffscreenCanvas Worker 检索范围
|
|
92
92
|
|
|
@@ -94,7 +94,9 @@ MCP 文档索引包含 `examples/test_umanager_loader.html`、`examples/test_uma
|
|
|
94
94
|
| :----------- | :--------- |
|
|
95
95
|
| `OffscreenViewerHost` | 主线程 canvas 所有权、完整构造选项/方法/事件、`transferControlToOffscreen()`、pointer/wheel/resize 转发、renderer 滚动统计和 `request()` command 调用;`host.init()` / `initialized` 只等待 `viewer.init()`,业务资源完成由一次性 `ready` 表示。还包括 init canvas transfer/post 失败或初始化期间 dispose 的 Promise rejection/资源清理,以及 dispose 后忽略迟到业务消息的语义。 |
|
|
96
96
|
| `createWorkerViewer` | module Worker 顶层可直接 await 的命令式入口;同步安装 host 消息监听,完成 OffscreenCanvas/`viewer.init()` 后返回 `WorkerViewerRuntime`,提供状态、事件、command、逆序 dispose 和一次性业务 ready 生命周期、ready 前 fatal cleanup、去重 ArrayBuffer transfer,以及内置 `getStats` / `getViewpoint` / `setViewpoint` / `render` 命令。 |
|
|
97
|
-
| `
|
|
97
|
+
| `ModelLoaderManager.setDecodeWorker` / `u-space/worker/model-decoder` | render Worker 创建第二个模型 decode Worker 的接线方式;静态 glTF/GLB/SBMX 支持范围,fetch/cache/SBMX/JSON/base64/ImageBitmap 工作边界,transferable 数据包、串行 ACK backpressure、有界贴图内容身份复用、LoadingManager URL/item 生命周期、跨域凭据隔离、节点图安全校验、完整 AbortSignal、故障回退,以及实例绑定的 Worker disposer。 |
|
|
98
|
+
| `test_umanager2_offscreen` | UManager Worker 示例启动方式、HDR/语义/场景加载、默认启用嵌套模型 decode Worker、`?modelDecodeWorker=off` A/B 开关、`setEditableBatching()`、`compileAsync()` 首帧预热、滚动帧率 HUD、标准透明合成、静态场景矩阵冻结/显式提交,以及默认显示全部语义对象且设备选择/飞向/高亮不改变其他对象显隐的调试策略。 |
|
|
99
|
+
| `ImageLoader` / `ImageBitmapLoader` / `maxTextureDimension2D` | Worker 普通图片加载兼容层、JPEG/PNG/GIF/WebP 编码尺寸预读、超过默认 `8192` limit 时的首次解码等比缩放、未知格式 fallback、源 bitmap 释放,以及 loader options/cache/request headers/abort 语义。 |
|
|
98
100
|
| `matrixWorldAutoUpdate` / `updateMatrixWorld` / `updateWorldMatrix` | 使用 Three.js 原生 API 冻结静态 Scene,按需提交单个对象或新增子树,并通过 `viewer.invalidate()` 请求新帧;单个 `InstanceObject.updateWorldMatrix(true, false)` 或父 Group 的 `updateWorldMatrix(true, true)` 仍会触发 dirty callback、instanced buffer 同步和 editable-batch materialize,相机矩阵继续独立更新。 |
|
|
99
101
|
| `OffscreenCanvas` + `setEditableBatching` | Offscreen 移走主线程解析/合并/渲染提交,editable batching 减少 draw submission;Three.js 对象必须留在 Worker,业务对象操作通过 structured-clone command 调用。 |
|
|
100
102
|
|
package/docs/release.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
3. VitePress 文档
|
|
8
8
|
4. `/examples/` 在线示例
|
|
9
9
|
|
|
10
|
-
npm 发布使用 Trusted Publishing/OIDC,不保存 `NPM_TOKEN`,日常发布不再要求输入 OTP。docs 和 examples 使用同一个 Vercel production deployment;`scripts/build-vercel-docs.mjs` 会在文档构建完成后复制 `examples
|
|
10
|
+
npm 发布使用 Trusted Publishing/OIDC,不保存 `NPM_TOKEN`,日常发布不再要求输入 OTP。docs 和 examples 使用同一个 Vercel production deployment;`scripts/build-vercel-docs.mjs` 会在文档构建完成后复制 `examples/`,将发布中的 `u-space` 版本写入部署产物的 import map,并用独立 Vite 构建将 Offscreen 示例转换为浏览器可直接执行的主线程 JavaScript、module Worker 和 WASM 资源。
|
|
11
11
|
|
|
12
12
|
## 一次性配置
|
|
13
13
|
|
|
@@ -67,11 +67,11 @@ pnpm release:all patch --no-wait
|
|
|
67
67
|
|
|
68
68
|
工作流按以下顺序执行:
|
|
69
69
|
|
|
70
|
-
1. 递增 `u-space` 和 `u-space-mcp` 版本,同步 examples/docs
|
|
70
|
+
1. 递增 `u-space` 和 `u-space-mcp` 版本,同步 examples/docs 中的当前版本引用;将更新日志的“未发布”内容归档到新的 `X.Y.Z` 版本标题,并创建新的空“未发布”区。
|
|
71
71
|
2. 执行完整测试、库构建、MCP 文档索引构建和 VitePress 构建。
|
|
72
72
|
3. 将版本元数据提交并推送到 `main`。
|
|
73
73
|
4. 通过 npm OIDC 发布两个包;精确版本已经存在时自动跳过。
|
|
74
|
-
5. 构建并部署 docs 和 examples 到 Vercel production
|
|
74
|
+
5. 构建并部署 docs 和 examples 到 Vercel production;Offscreen TypeScript 入口会通过 `examples/offscreen/vite.config.ts` 单独打包,不会以原始 `.ts` 作为线上运行入口。
|
|
75
75
|
6. 推送 `vX.Y.Z` 和 `u-space-mcp-vX.Y.Z` 标签。
|
|
76
76
|
|
|
77
77
|
`release-all` concurrency group 会阻止两次发布并发运行。
|
|
@@ -86,6 +86,8 @@ pnpm release:all current
|
|
|
86
86
|
|
|
87
87
|
工作流会跳过 registry 中已经存在的精确版本,只重试尚未完成的 npm 包、Vercel 部署和标签。
|
|
88
88
|
|
|
89
|
+
`current` 不会再次修改更新日志,因此重试不会生成重复的版本标题。
|
|
90
|
+
|
|
89
91
|
本地旧命令 `pnpm release`、`pnpm publish:mcp` 和 `pnpm docs:deploy` 继续保留,但它们不使用 GitHub OIDC,可能请求 npm OTP 或本机 Vercel 登录。
|
|
90
92
|
|
|
91
93
|
## 参考
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "u-space",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"types": "./dist/src/worker/runtime.d.ts",
|
|
21
21
|
"import": "./dist/worker/runtime.js"
|
|
22
22
|
},
|
|
23
|
+
"./worker/model-decoder": {
|
|
24
|
+
"types": "./dist/src/worker/model-decoder.d.ts",
|
|
25
|
+
"import": "./dist/worker/model-decoder.js"
|
|
26
|
+
},
|
|
23
27
|
"./plugins/*": "./dist/plugins/*/index.js"
|
|
24
28
|
},
|
|
25
29
|
"typesVersions": {
|
|
@@ -30,6 +34,9 @@
|
|
|
30
34
|
"worker/runtime": [
|
|
31
35
|
"./dist/src/worker/runtime.d.ts"
|
|
32
36
|
],
|
|
37
|
+
"worker/model-decoder": [
|
|
38
|
+
"./dist/src/worker/model-decoder.d.ts"
|
|
39
|
+
],
|
|
33
40
|
"plugins/*": [
|
|
34
41
|
"./dist/plugins/*/index.d.ts"
|
|
35
42
|
]
|
|
@@ -42,6 +49,7 @@
|
|
|
42
49
|
"build:plugins": "cross-env BUILD_TARGET=plugins vite build --mode development",
|
|
43
50
|
"build": "cross-env BUILD_TARGET=all vite build --mode production && tsc",
|
|
44
51
|
"example:offscreen": "vite --config examples/offscreen/vite.config.ts",
|
|
52
|
+
"build:example:offscreen": "vite build --config examples/offscreen/vite.config.ts",
|
|
45
53
|
"docs:dev": "vitepress dev docs",
|
|
46
54
|
"docs:build": "vitepress build docs",
|
|
47
55
|
"docs:preview": "vitepress preview docs",
|