u-space 0.0.11 → 0.0.13
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/index.cjs +3 -3
- package/dist/index.js +243 -200
- package/dist/plugins/curve-movement/CurveMovementObject.d.ts +1 -1
- package/dist/plugins/curve-movement/index.cjs +1 -1
- package/dist/plugins/curve-movement/index.js +4 -5
- package/dist/plugins/u-manager/Watermarker.d.ts +1 -0
- package/dist/plugins/u-manager/constants.d.ts +1 -0
- package/dist/plugins/u-manager/index.cjs +60 -60
- package/dist/plugins/u-manager/index.d.ts +1 -0
- package/dist/plugins/u-manager/index.js +9032 -8616
- package/dist/plugins/u-manager/loaders/SceneLoader.d.ts +10 -1
- package/dist/plugins/u-manager/semantics/BuildingGroup.d.ts +15 -0
- package/dist/plugins/u-manager/semantics/FloorMesh.d.ts +41 -0
- package/dist/plugins/u-manager/semantics/SemanticLoader.d.ts +8 -0
- package/dist/plugins/u-manager/semantics/SemanticParser.d.ts +5 -0
- package/dist/plugins/u-manager/semantics/index.d.ts +6 -0
- package/dist/plugins/u-manager/semantics/semantic.types.d.ts +87 -0
- package/dist/plugins/u-manager/semantics/types.d.ts +25 -0
- package/dist/plugins/u-manager/types.d.ts +1 -1
- package/dist/src/effects/TSLEffects.d.ts +1 -1
- package/dist/src/loaders/ModelLoaderManager.d.ts +1 -1
- package/dist/src/loaders/TextureLoaderManager.d.ts +1 -1
- package/dist/src/viewers/Viewer.d.ts +1 -1
- package/docs/api-plugin-u-manager.md +109 -1
- package/docs/changelog.md +7 -0
- package/docs/index.md +7 -1
- package/docs/mcp.md +96 -0
- package/package.json +8 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Group, Loader } from 'three/webgpu';
|
|
2
2
|
import { type Viewer } from 'u-space';
|
|
3
|
+
import type { ITreeData } from '../types';
|
|
3
4
|
export interface SceneLoaderOptions {
|
|
4
5
|
}
|
|
5
6
|
export declare class SceneLoader extends Loader<unknown, SceneLoaderOptions> {
|
|
@@ -7,9 +8,17 @@ export declare class SceneLoader extends Loader<unknown, SceneLoaderOptions> {
|
|
|
7
8
|
viewer: Viewer;
|
|
8
9
|
key: string;
|
|
9
10
|
cachedIds: Set<string>;
|
|
11
|
+
protected _resourceData: any;
|
|
12
|
+
protected _treeData: ITreeData[];
|
|
10
13
|
constructor(viewer: Viewer);
|
|
11
14
|
setKey(key: string): this;
|
|
12
|
-
|
|
15
|
+
protected _preareTreeData(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* 加载场景
|
|
18
|
+
* @param options
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
loadAsync(options?: SceneLoaderOptions): Promise<Group>;
|
|
13
22
|
clearCache(): void;
|
|
14
23
|
dispose(): void;
|
|
15
24
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseGroup } from 'u-space';
|
|
2
|
+
import type { FloorMesh } from './FloorMesh';
|
|
3
|
+
export declare class BuildingGroup extends BaseGroup {
|
|
4
|
+
isBuildingGroup: boolean;
|
|
5
|
+
type: string;
|
|
6
|
+
floorMeshes: FloorMesh[];
|
|
7
|
+
constructor();
|
|
8
|
+
addFloor(mesh: FloorMesh): this;
|
|
9
|
+
getFloorAt(index: number): FloorMesh;
|
|
10
|
+
removeFloor(mesh: FloorMesh): this;
|
|
11
|
+
isolateFloor(mesh: FloorMesh | number): this;
|
|
12
|
+
showAllFloors(): this;
|
|
13
|
+
planishFloors(): this;
|
|
14
|
+
unplanishFloors(): this;
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Box3, Matrix4, Sphere, Vector3, Vector4, type Intersection, type Raycaster } from 'three/webgpu';
|
|
2
|
+
import { BaseMesh } from 'u-space';
|
|
3
|
+
import type { SemanticColor, SemanticGeometryEntry } from './types';
|
|
4
|
+
export declare class FloorMesh extends BaseMesh {
|
|
5
|
+
#private;
|
|
6
|
+
isFloorMergedSemanticMesh: boolean;
|
|
7
|
+
type: string;
|
|
8
|
+
boundingBox: Box3 | null;
|
|
9
|
+
boundingSphere: Sphere | null;
|
|
10
|
+
wallsInstances: Map<string, number>;
|
|
11
|
+
columnsInstances: Map<string, number>;
|
|
12
|
+
spacesInstances: Map<string, number>;
|
|
13
|
+
doorsInstances: Map<string, number>;
|
|
14
|
+
windowsInstances: Map<string, number>;
|
|
15
|
+
semanticInstances: Map<string, number>;
|
|
16
|
+
constructor(entries: SemanticGeometryEntry[]);
|
|
17
|
+
planish(): void;
|
|
18
|
+
unplanish(): void;
|
|
19
|
+
get semanticCount(): number;
|
|
20
|
+
get instanceCount(): number;
|
|
21
|
+
getSemanticIndexById(id: string): number | undefined;
|
|
22
|
+
getSemanticIdAt(index: number): string;
|
|
23
|
+
getSemanticKindAt(index: number): import("./types").SemanticKind;
|
|
24
|
+
getSemanticNameAt(index: number): string | undefined;
|
|
25
|
+
setColorAt(index: number, color: SemanticColor): this;
|
|
26
|
+
getColorAt(index: number, target?: Vector4): Vector4;
|
|
27
|
+
setOpacityAt(index: number, opacity: number): this;
|
|
28
|
+
getOpacityAt(index: number): number;
|
|
29
|
+
setVisibleAt(index: number, visible: boolean): this;
|
|
30
|
+
getVisibleAt(index: number): boolean;
|
|
31
|
+
setMatrixAt(index: number, matrix: Matrix4): this;
|
|
32
|
+
setScaleAt(index: number, scale: number | Vector3, y?: number, z?: number): this;
|
|
33
|
+
getMatrixAt(index: number, matrix?: Matrix4): Matrix4;
|
|
34
|
+
getFinalMatrixAt(index: number, matrix?: Matrix4): Matrix4;
|
|
35
|
+
computeBoundingBox(): void;
|
|
36
|
+
computeBoundingSphere(): void;
|
|
37
|
+
getBoundingBoxAt(index: number, target?: Box3, world?: boolean): Box3 | null;
|
|
38
|
+
getBoundingSphereAt(index: number, target?: Sphere, world?: boolean): Sphere | null;
|
|
39
|
+
raycast(raycaster: Raycaster, intersects: Intersection[]): boolean | void;
|
|
40
|
+
dispose(): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Loader } from 'three/webgpu';
|
|
2
|
+
import type { Viewer } from 'u-space';
|
|
3
|
+
import { BuildingGroup } from './BuildingGroup';
|
|
4
|
+
export declare class SemanticLoader extends Loader {
|
|
5
|
+
viewer: Viewer;
|
|
6
|
+
constructor(viewer: Viewer);
|
|
7
|
+
loadAsync(): Promise<BuildingGroup[]>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface Building {
|
|
2
|
+
ID: string;
|
|
3
|
+
Name: string;
|
|
4
|
+
Stories: number[];
|
|
5
|
+
}
|
|
6
|
+
export interface Polygon {
|
|
7
|
+
shape?: number[];
|
|
8
|
+
}
|
|
9
|
+
export interface Door {
|
|
10
|
+
Elevation: number;
|
|
11
|
+
Height: number;
|
|
12
|
+
ID: string;
|
|
13
|
+
Open: boolean;
|
|
14
|
+
Polygon?: Polygon;
|
|
15
|
+
Width: number;
|
|
16
|
+
}
|
|
17
|
+
export interface Column {
|
|
18
|
+
ID: string;
|
|
19
|
+
Elevation: number;
|
|
20
|
+
Height: number;
|
|
21
|
+
Polygon?: Polygon;
|
|
22
|
+
}
|
|
23
|
+
export interface Space {
|
|
24
|
+
CeilingHeight: number;
|
|
25
|
+
GroundHeight: number;
|
|
26
|
+
ID: string;
|
|
27
|
+
Name: string;
|
|
28
|
+
Polygon?: Polygon;
|
|
29
|
+
}
|
|
30
|
+
export interface Staircase {
|
|
31
|
+
Elevation: number;
|
|
32
|
+
ID: string;
|
|
33
|
+
Polyline: number[];
|
|
34
|
+
Spaces: number[];
|
|
35
|
+
}
|
|
36
|
+
export interface Story {
|
|
37
|
+
Columns?: any[];
|
|
38
|
+
Doors?: number[];
|
|
39
|
+
Elevation?: number;
|
|
40
|
+
Facilities?: any[];
|
|
41
|
+
FloorIndex?: any;
|
|
42
|
+
Height?: number;
|
|
43
|
+
ID?: string;
|
|
44
|
+
Name?: string;
|
|
45
|
+
Polygon?: Polygon;
|
|
46
|
+
Spaces?: number[];
|
|
47
|
+
Staircases?: number[];
|
|
48
|
+
Walls?: number[];
|
|
49
|
+
Windows?: number[];
|
|
50
|
+
}
|
|
51
|
+
export interface Wall {
|
|
52
|
+
Doors: any[];
|
|
53
|
+
Elevation: number;
|
|
54
|
+
Height: number;
|
|
55
|
+
ID: string;
|
|
56
|
+
Polygon?: Polygon;
|
|
57
|
+
Spaces: number[];
|
|
58
|
+
SubPolygons?: any;
|
|
59
|
+
VirtualWall: boolean;
|
|
60
|
+
Windows: any[];
|
|
61
|
+
}
|
|
62
|
+
export interface Window {
|
|
63
|
+
Elevation: number;
|
|
64
|
+
Height: number;
|
|
65
|
+
ID: string;
|
|
66
|
+
Open: boolean;
|
|
67
|
+
Polygon?: Polygon;
|
|
68
|
+
Width: number;
|
|
69
|
+
}
|
|
70
|
+
export interface Asset {
|
|
71
|
+
Generator: string;
|
|
72
|
+
GplUUID?: any;
|
|
73
|
+
Unit: string;
|
|
74
|
+
Version: string;
|
|
75
|
+
UBuilder?: any;
|
|
76
|
+
}
|
|
77
|
+
export interface SemanticObject {
|
|
78
|
+
Buildings?: Building[];
|
|
79
|
+
Doors?: Door[];
|
|
80
|
+
Spaces?: Space[];
|
|
81
|
+
Staircases?: Staircase[];
|
|
82
|
+
Stories?: Story[];
|
|
83
|
+
Walls?: Wall[];
|
|
84
|
+
Windows?: Window[];
|
|
85
|
+
Columns?: Column[];
|
|
86
|
+
Asset?: Asset;
|
|
87
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { BufferGeometry, Color, Matrix4, Vector3, Vector4 } from 'three/webgpu';
|
|
2
|
+
export type SemanticKind = 'WALL' | 'COLUMN' | 'SPACE' | 'Doors' | 'Windows';
|
|
3
|
+
export type SemanticColor = Color | Vector3 | Vector4;
|
|
4
|
+
export interface SemanticGeometryEntry {
|
|
5
|
+
id: string;
|
|
6
|
+
kind: SemanticKind;
|
|
7
|
+
name?: string;
|
|
8
|
+
geometry: BufferGeometry;
|
|
9
|
+
color: Vector4;
|
|
10
|
+
}
|
|
11
|
+
export interface SemanticObjectState {
|
|
12
|
+
id: string;
|
|
13
|
+
kind: SemanticKind;
|
|
14
|
+
name?: string;
|
|
15
|
+
index: number;
|
|
16
|
+
baseMatrix: Matrix4;
|
|
17
|
+
matrix: Matrix4;
|
|
18
|
+
finalMatrix: Matrix4;
|
|
19
|
+
geometry: BufferGeometry;
|
|
20
|
+
color: Vector4;
|
|
21
|
+
visible: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface ReadableAttribute {
|
|
24
|
+
getComponent(index: number, component: number): number;
|
|
25
|
+
}
|
|
@@ -28,7 +28,7 @@ export interface ITreeData {
|
|
|
28
28
|
sid: string;
|
|
29
29
|
name: string;
|
|
30
30
|
path: string | null;
|
|
31
|
-
renderType: 'GROUP' | '3D' | 'STUB' | 'POLYGON' | 'CIRCLE' | 'WATER_SURFACE' | 'DECAL' | 'AREA' | 'FLOOR' | 'ROOM' | 'GS';
|
|
31
|
+
renderType: 'GROUP' | '3D' | 'STUB' | 'POLYGON' | 'CIRCLE' | 'WATER_SURFACE' | 'DECAL' | 'AREA' | 'FLOOR' | 'ROOM' | 'DOOR' | 'STAIRCASE' | 'ELEVATOR' | 'VENT' | 'WINDOW' | 'GS';
|
|
32
32
|
deviceCode: string | null;
|
|
33
33
|
matrix: number[];
|
|
34
34
|
familyId: string | null;
|
|
@@ -13,7 +13,7 @@ export interface LoadParameters {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class ModelLoaderManager {
|
|
15
15
|
private static CACHE_NAME;
|
|
16
|
-
static fileLoader: FileLoader
|
|
16
|
+
static fileLoader: FileLoader<string | ArrayBuffer>;
|
|
17
17
|
static dracoLoader: DRACOLoader;
|
|
18
18
|
static ktx2Loader: KTX2Loader;
|
|
19
19
|
static gltfLoader: GLTFLoader;
|
|
@@ -5,7 +5,7 @@ export declare class TextureLoaderManager {
|
|
|
5
5
|
static hdrLoader: HDRLoader;
|
|
6
6
|
static cubeTextureLoader: CubeTextureLoader;
|
|
7
7
|
static setLoadingManager(loadingManager: LoadingManager): void;
|
|
8
|
-
static loadAsyncTexture(url: string): Promise<import("three").Texture<HTMLImageElement>>;
|
|
8
|
+
static loadAsyncTexture(url: string): Promise<import("three").Texture<HTMLImageElement, import("three").TextureEventMap>>;
|
|
9
9
|
static loadAsyncHDR(url: string): Promise<import("three").DataTexture>;
|
|
10
10
|
static loadAsyncCubeTexture(path: string, urls: string[]): Promise<import("three").CubeTexture<unknown>>;
|
|
11
11
|
}
|
|
@@ -72,7 +72,7 @@ declare class Viewer extends EventDispatcher<ViewerEventMap> {
|
|
|
72
72
|
render(frame?: number): Promise<void>;
|
|
73
73
|
private animate;
|
|
74
74
|
private _initRenderer;
|
|
75
|
-
createScene(): Scene
|
|
75
|
+
createScene(): Scene<import("three").Object3DEventMap>;
|
|
76
76
|
createPerspectiveCamera(): PerspectiveCamera;
|
|
77
77
|
createOrthographicCamera(): OrthographicCamera;
|
|
78
78
|
/**
|
|
@@ -1,9 +1,117 @@
|
|
|
1
1
|
# u-manager
|
|
2
2
|
|
|
3
|
-
`u-manager`
|
|
3
|
+
`u-manager` 是一套全面的加载器和解析器,用于从服务器路径流式传输、解密并显示结构化场景数据。支持场景、拓扑、动画、属性、相机视点和楼层语义模型。
|
|
4
4
|
|
|
5
5
|
所有加载器均继承自 Three.js 的 `Loader`,并提供 `setPath(path)` 方法,在调用 `loadAsync()` 前配置基础数据目录。
|
|
6
6
|
|
|
7
|
+
## `SemanticLoader`
|
|
8
|
+
|
|
9
|
+
加载 `db/semantic_model.json` 楼层语义数据,并按建筑返回 `BuildingGroup[]`。每个建筑包含多个 `FloorMesh`,每个楼层把墙、柱、空间等语义对象合并为一个 TSL 材质驱动的网格。
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Vector3, Vector4 } from 'three';
|
|
13
|
+
import { SemanticLoader } from 'u-space/plugins/u-manager';
|
|
14
|
+
|
|
15
|
+
const loader = new SemanticLoader(viewer);
|
|
16
|
+
loader.setPath('./scenes/my-scene');
|
|
17
|
+
|
|
18
|
+
const buildings = await loader.loadAsync(); // BuildingGroup[]
|
|
19
|
+
viewer.scene.add(...buildings);
|
|
20
|
+
|
|
21
|
+
const building = buildings[0];
|
|
22
|
+
const floor = building.getFloorAt(0);
|
|
23
|
+
|
|
24
|
+
building.isolateFloor(floor);
|
|
25
|
+
await viewer.controls.flyToObject(floor);
|
|
26
|
+
|
|
27
|
+
floor.addEventListener('click', ({ event }) => {
|
|
28
|
+
const { target, intersect } = event;
|
|
29
|
+
const index = intersect.semanticIndex;
|
|
30
|
+
|
|
31
|
+
target.setColorAt(index, new Vector4(1, 0, 0, 0.5));
|
|
32
|
+
target.setScaleAt(index, new Vector3(1, 0.1, 1));
|
|
33
|
+
viewer.render();
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `BuildingGroup`
|
|
38
|
+
|
|
39
|
+
`BuildingGroup` 继承自 `BaseGroup`,用于组织一个建筑下的所有楼层。
|
|
40
|
+
|
|
41
|
+
| 属性 / 方法 | 说明 |
|
|
42
|
+
| :---------- | :--- |
|
|
43
|
+
| `floorMeshes` | 当前建筑内的 `FloorMesh[]`。 |
|
|
44
|
+
| `addFloor(floor)` | 添加楼层,并同步加入 group。 |
|
|
45
|
+
| `removeFloor(floor)` | 移除楼层,并同步从 group 移除。 |
|
|
46
|
+
| `getFloorAt(index)` | 按楼层下标获取 `FloorMesh`。 |
|
|
47
|
+
| `isolateFloor(floor \| index)` | 只显示指定楼层,隐藏其他楼层。 |
|
|
48
|
+
| `showAllFloors()` | 显示全部楼层。 |
|
|
49
|
+
| `planishFloors()` | 将所有楼层整体压扁。 |
|
|
50
|
+
| `unplanishFloors()` | 恢复所有楼层整体缩放。 |
|
|
51
|
+
|
|
52
|
+
### `FloorMesh`
|
|
53
|
+
|
|
54
|
+
`FloorMesh` 继承自 `BaseMesh`,表示一个楼层。它不是 `BatchedMesh`,而是把同一楼层内的语义对象合并为一份几何,并通过 TSL + `DataTexture` 在 GPU 侧按 `semanticIndex` 控制颜色、透明度、显示隐藏和实例矩阵。
|
|
55
|
+
|
|
56
|
+
这种结构的目标是让每个楼层通常只占一个主渲染 draw call,同时仍保留实例级控制能力。`xxxAt` 方法全部作用于单个语义实例;没有 `At` 后缀的方法作用于整个楼层 mesh。
|
|
57
|
+
|
|
58
|
+
| 属性 / 方法 | 说明 |
|
|
59
|
+
| :---------- | :--- |
|
|
60
|
+
| `semanticCount` / `instanceCount` | 当前楼层语义实例数量。 |
|
|
61
|
+
| `semanticInstances` | `Map<string, number>`,从语义对象 ID 映射到实例下标。 |
|
|
62
|
+
| `wallsInstances` / `columnsInstances` / `spacesInstances` / `doorsInstances` / `windowsInstances` | 按语义类型维护的 ID 到实例下标映射。 |
|
|
63
|
+
| `getSemanticIndexById(id)` | 根据语义 ID 获取实例下标。 |
|
|
64
|
+
| `getSemanticIdAt(index)` | 获取实例语义 ID。 |
|
|
65
|
+
| `getSemanticKindAt(index)` | 获取实例类型:`'WALL' \| 'COLUMN' \| 'SPACE' \| 'Doors' \| 'Windows'`。 |
|
|
66
|
+
| `getSemanticNameAt(index)` | 获取实例名称;当前 `SPACE` 会从语义数据的 `Name` 写入,其他类型可能为 `undefined`。 |
|
|
67
|
+
| `setColorAt(index, color)` / `getColorAt(index, target?)` | 修改或读取实例颜色,支持 `Color`、`Vector3`、`Vector4`。 |
|
|
68
|
+
| `setOpacityAt(index, opacity)` / `getOpacityAt(index)` | 修改或读取实例透明度。 |
|
|
69
|
+
| `setVisibleAt(index, visible)` / `getVisibleAt(index)` | 修改或读取实例显隐状态。 |
|
|
70
|
+
| `setMatrixAt(index, matrix)` / `getMatrixAt(index, target?)` | 设置或读取实例附加矩阵。 |
|
|
71
|
+
| `setScaleAt(index, scale, y?, z?)` | 修改实例缩放,支持 `number` 或 `Vector3`。 |
|
|
72
|
+
| `getFinalMatrixAt(index, target?)` | 读取实例最终矩阵,包含语义对象原始基点矩阵。 |
|
|
73
|
+
| `getBoundingBoxAt(index, target?, world?)` | 获取实例包围盒;`world = true` 时包含 `FloorMesh.matrixWorld`。 |
|
|
74
|
+
| `getBoundingSphereAt(index, target?, world?)` | 获取实例包围球;`world = true` 时包含 `FloorMesh.matrixWorld`。 |
|
|
75
|
+
| `computeBoundingBox()` / `computeBoundingSphere()` | 计算整个楼层的包围体。 |
|
|
76
|
+
| `planish()` / `unplanish()` | 压扁或恢复整个楼层 mesh。 |
|
|
77
|
+
|
|
78
|
+
### 飞向语义实例
|
|
79
|
+
|
|
80
|
+
点击、射线检测命中 `FloorMesh` 时,`intersect` 上会附加语义字段:`semanticIndex`、`semanticId`、`semanticKind`。可以直接用 `getBoundingBoxAt()` 获取实例的世界包围盒,然后让相机飞向该实例。
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { Box3 } from 'three';
|
|
84
|
+
|
|
85
|
+
const box = new Box3();
|
|
86
|
+
|
|
87
|
+
floor.addEventListener('click', async ({ event }) => {
|
|
88
|
+
const { target, intersect } = event;
|
|
89
|
+
const semanticBox = target.getBoundingBoxAt(intersect.semanticIndex, box, true);
|
|
90
|
+
|
|
91
|
+
if (semanticBox) {
|
|
92
|
+
await viewer.controls.flyToBox(semanticBox, {
|
|
93
|
+
viewpoint: 'rightFrontTop',
|
|
94
|
+
padding: 0.2,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
如果要根据 ID 操作对象,先通过 `getSemanticIndexById(id)` 转为实例下标。
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const index = floor.getSemanticIndexById('SPACE_001');
|
|
104
|
+
|
|
105
|
+
if (index !== undefined) {
|
|
106
|
+
floor.setVisibleAt(index, false);
|
|
107
|
+
viewer.render();
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 楼层压扁
|
|
112
|
+
|
|
113
|
+
`planish()` 会缩放整个 `FloorMesh`,适合展示楼层整体。`setScaleAt()` 只缩放单个语义实例,并保留该语义对象自己的基点矩阵,因此压扁墙、柱、房间时不会被压到世界原点。
|
|
114
|
+
|
|
7
115
|
## `SceneLoader`
|
|
8
116
|
|
|
9
117
|
从服务端场景包加载完整场景树(模型、组、形状、拉伸区域),并自动将所有已加载对象按 `id` 和 `sid` 注册到 `viewer.objectManager`。
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
+
## 0.0.12
|
|
4
|
+
|
|
5
|
+
### 新增
|
|
6
|
+
|
|
7
|
+
- **u-manager semantics** — 新增 `SemanticLoader`、`BuildingGroup`、`FloorMesh` 语义楼层 API,支持楼层隔离、实例级颜色/透明度/显隐/matrix/scale 控制,以及实例包围盒/包围球查询。
|
|
8
|
+
- **u-space MCP** — 内置文档索引同步语义楼层 API,MCP 客户端可检索 `SemanticLoader`、`BuildingGroup` 和 `FloorMesh` 用法。
|
|
9
|
+
|
|
3
10
|
## 0.0.8
|
|
4
11
|
|
|
5
12
|
### 新增
|
package/docs/index.md
CHANGED
|
@@ -52,9 +52,15 @@ features:
|
|
|
52
52
|
| [keyboard-controls](./api-plugin-keyboard-controls) | WASD / 方向键控制相机移动与旋转 |
|
|
53
53
|
| [minimap](./api-plugin-minimap) | 2D 小地图叠加层 |
|
|
54
54
|
| [tiles](./api-plugin-tiles) | ArcGIS 3D 瓦片 / GIS 地球渲染 |
|
|
55
|
-
| [u-manager](./api-plugin-u-manager) |
|
|
55
|
+
| [u-manager](./api-plugin-u-manager) | 场景加载、语义楼层、拓扑、动画、属性、视点管理 |
|
|
56
56
|
| [curve-movement](./api-plugin-curve-movement) | 沿样条曲线移动相机或对象 |
|
|
57
57
|
| [tracking-controls](./api-plugin-tracking-controls) | 相机跟随移动目标 |
|
|
58
58
|
| [atmosphere](./api-plugin-atmosphere) | 天空/大气渲染(开发中) |
|
|
59
59
|
| [object-controls](./api-plugin-object-controls) | 交互式移动、旋转、缩放 3D 对象 |
|
|
60
60
|
| [topology-drawer](./api-plugin-topology-drawer) | 在场景任意表面交互式绘制拓扑路径图 |
|
|
61
|
+
|
|
62
|
+
### MCP
|
|
63
|
+
|
|
64
|
+
| 文档 | 说明 |
|
|
65
|
+
| :--- | :--- |
|
|
66
|
+
| [u-space MCP](./mcp) | 面向 Mastra、Claude Desktop、Cursor 等 MCP 客户端的只读文档检索服务器 |
|
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# u-space MCP
|
|
2
|
+
|
|
3
|
+
`u-space-mcp` 是面向 `u-space` 文档的 Model Context Protocol(MCP)服务器。它把当前文档打包成只读 MCP 工具,方便 Mastra、Claude Desktop、Cursor 等 MCP 客户端在回答 `u-space` API、插件和示例问题时直接检索官方文档,包括 `u-manager` 的 `SemanticLoader`、`BuildingGroup` 和 `FloorMesh` 语义楼层 API。
|
|
4
|
+
|
|
5
|
+
## 安装与启动
|
|
6
|
+
|
|
7
|
+
推荐通过 `npx` 使用已发布的 npm 包:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"uSpace": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "u-space-mcp@latest"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
本地开发文档时,可以通过 `--docs` 指向仓库里的 docs 目录:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"uSpace": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": [
|
|
28
|
+
"-y",
|
|
29
|
+
"u-space-mcp@latest",
|
|
30
|
+
"--docs",
|
|
31
|
+
"/Users/jiangqi/Desktop/xunwei/SoonSpace/u-space/docs"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
也可以使用环境变量:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
U_SPACE_DOCS_PATH=/path/to/u-space/docs npx -y u-space-mcp@latest
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Mastra 接入
|
|
45
|
+
|
|
46
|
+
在 Mastra 中通过 `MCPClient` 使用 stdio 形式接入:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { MCPClient } from '@mastra/mcp';
|
|
50
|
+
|
|
51
|
+
export const uSpaceMcpClient = new MCPClient({
|
|
52
|
+
id: 'u-space-mcp-client',
|
|
53
|
+
servers: {
|
|
54
|
+
uSpace: {
|
|
55
|
+
command: 'npx',
|
|
56
|
+
args: ['-y', 'u-space-mcp@latest'],
|
|
57
|
+
stderr: 'pipe',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
然后把工具挂到 Agent 上:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
export const codingAgent = new Agent({
|
|
67
|
+
// ...
|
|
68
|
+
tools: {
|
|
69
|
+
...(await uSpaceMcpClient.listTools()),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 工具列表
|
|
75
|
+
|
|
76
|
+
`u-space-mcp` 只提供只读工具:
|
|
77
|
+
|
|
78
|
+
| 工具 | 说明 |
|
|
79
|
+
| :--- | :--- |
|
|
80
|
+
| `list_docs` | 列出可用文档页 |
|
|
81
|
+
| `search_docs` | 按关键词、API 名、插件名或概念检索文档 |
|
|
82
|
+
| `get_doc` | 按 path 或 id 读取单篇文档 |
|
|
83
|
+
| `get_api_reference` | 面向 API / 类 / 方法 / 插件的检索 |
|
|
84
|
+
| `find_examples` | 查找示例和用法相关文档 |
|
|
85
|
+
| `get_changelog` | 读取更新日志 |
|
|
86
|
+
|
|
87
|
+
## 包结构
|
|
88
|
+
|
|
89
|
+
源码位于 `packages/u-space-mcp`。构建时会从根目录 `docs/*.md` 生成内置文档索引,并编译成可发布的 npm 包:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pnpm build:mcp
|
|
93
|
+
pnpm publish:mcp
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
发布后的包不依赖本机绝对路径;只有在传入 `--docs` 或设置 `U_SPACE_DOCS_PATH` 时,才会读取本地文档目录。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "u-space",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
"docs:build": "vitepress build docs",
|
|
30
30
|
"docs:preview": "vitepress preview docs",
|
|
31
31
|
"docs:deploy": "pnpm docs:build && vercel --prod",
|
|
32
|
+
"build:mcp": "pnpm --filter u-space-mcp build",
|
|
33
|
+
"publish:mcp": "npm publish ./packages/u-space-mcp --access public",
|
|
32
34
|
"release": "npm version patch && pnpm build && npm publish --access=public"
|
|
33
35
|
},
|
|
34
36
|
"files": [
|
|
@@ -58,10 +60,10 @@
|
|
|
58
60
|
"vitepress": "^1.6.4"
|
|
59
61
|
},
|
|
60
62
|
"peerDependencies": {
|
|
61
|
-
"3d-tiles-renderer": "
|
|
62
|
-
"@takram/three-geospatial": "
|
|
63
|
-
"@types/three": "
|
|
64
|
-
"camera-controls": "
|
|
65
|
-
"three": "
|
|
63
|
+
"3d-tiles-renderer": ">=0.4.27",
|
|
64
|
+
"@takram/three-geospatial": ">=0.9.1",
|
|
65
|
+
"@types/three": ">=0.184.1",
|
|
66
|
+
"camera-controls": ">=3.1.2",
|
|
67
|
+
"three": ">=0.184.0"
|
|
66
68
|
}
|
|
67
69
|
}
|