soonspacejs 2.15.4 → 2.15.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soonspacejs",
3
- "version": "2.15.4",
3
+ "version": "2.15.6",
4
4
  "homepage": "https://www.xwbuilders.com/soonspacejs/",
5
5
  "description": "soonspacejs 2.x",
6
6
  "module": "./dist/index.esm.js",
@@ -0,0 +1,80 @@
1
+ import { EventDispatcher, Object3D } from 'three';
2
+ import { Tween } from 'three/examples/jsm/libs/tween.module.js';
3
+ import { default as animation } from './index';
4
+ import { IClipAnimation, IClipAnimationFrame, IClipAnimationPlayerEventMap, IClipTransform, IClipTweenSource } from '../Interface';
5
+ /**
6
+ * 剪辑动画播放器
7
+ *
8
+ * @remarks
9
+ * SDK 内部实现。业务侧推荐使用 {@link SoonSpace.playClipAnimation} 等高层方法,
10
+ * 不需要直接构造该类。
11
+ *
12
+ * 行为:
13
+ * - 接收一组关键帧({@link IClipAnimationFrame}),按数组顺序串行播放
14
+ * - 每段为一次 `ssp.animation()` 补间,覆盖目标的 position / rotation / scale
15
+ * - 通过 `update` / `start` 事件暴露每帧的 tween 数据,便于上层做 UI 同步
16
+ *
17
+ * 生命周期:
18
+ * - {@link initTransform} —— 记录初始姿态(首次 `play` 前自动调用)
19
+ * - {@link play} —— 顺序播放所有 frame,被 {@link stop} 中断时优雅退出
20
+ * - {@link reset} —— 把目标 transform 还原到 `initTransform` 时的快照
21
+ * - {@link dispose} —— `stop + reset + 移除初始姿态标记`
22
+ */
23
+ export declare class ClipAnimationPlayer extends EventDispatcher<IClipAnimationPlayerEventMap> {
24
+ /** SoonSpace 实例 —— 仅用 `animation()` 调度补间 + `render()` 触发重绘 */
25
+ readonly ssp: {
26
+ animation: typeof animation;
27
+ render: () => void;
28
+ };
29
+ /** 被动画的目标对象(每帧的 position / rotation / scale 会写到这里) */
30
+ readonly target: Object3D;
31
+ /** 当前 in-flight 的 tween 集合,{@link stop} 时统一打断 */
32
+ readonly tweenSet: Set<Tween<IClipTweenSource>>;
33
+ /** 是否仍有 tween 在执行 */
34
+ get isPlaying(): boolean;
35
+ constructor(
36
+ /** SoonSpace 实例 —— 仅用 `animation()` 调度补间 + `render()` 触发重绘 */
37
+ ssp: {
38
+ animation: typeof animation;
39
+ render: () => void;
40
+ },
41
+ /** 被动画的目标对象(每帧的 position / rotation / scale 会写到这里) */
42
+ target: Object3D);
43
+ /**
44
+ * 把当前 target.position / rotation / scale 作为初始快照记录到 target 上的 Symbol 槽
45
+ *
46
+ * @remarks
47
+ * 通常无需手动调用 —— {@link play} 会在首次执行前惰性调用一次。
48
+ * 多次调用不会覆盖(除非显式传入 `defaultTransform`)。
49
+ *
50
+ * @param defaultTransform - 显式指定初始姿态(覆盖目标当前 transform 的快照)
51
+ */
52
+ initTransform(defaultTransform?: IClipTransform): IClipTransform;
53
+ /** 取出 {@link initTransform} 记录的初始姿态;未记录时返回 `undefined` */
54
+ getInitialTransform(): IClipTransform | undefined;
55
+ /**
56
+ * 按数组顺序播放关键帧
57
+ *
58
+ * @remarks
59
+ * - 首次调用时会通过 {@link initTransform} 记录初始姿态
60
+ * - 第 0 帧的"起点"为初始姿态;后续帧的"起点"为前一帧的 target 值
61
+ * - 被 {@link stop} 打断时立即结束剩余帧的播放并 resolve
62
+ *
63
+ * @param frames - 关键帧数组(**调用方需自行排序**;高层方法 `playClipAnimation` 会按 `index` 排序后再传入)
64
+ */
65
+ play(frames: IClipAnimationFrame[]): Promise<void>;
66
+ /** 停止所有 in-flight tween;{@link play} 会随之 resolve */
67
+ stop(): void;
68
+ /**
69
+ * 把 target 还原到 {@link initTransform} 时的初始姿态并触发一次重绘
70
+ *
71
+ * @remarks 未调用过 {@link initTransform} 时(无快照)此方法为 no-op
72
+ */
73
+ reset(): void;
74
+ /**
75
+ * 一站式清理:{@link stop} → {@link reset} → 移除 target 上的初始姿态 Symbol 槽
76
+ * @remarks 释放后再次 {@link play} 会重新捕获当前 target 状态作为新的初始姿态
77
+ */
78
+ dispose(): void;
79
+ }
80
+ export type { IClipAnimation, IClipAnimationFrame, IClipTransform, IClipTweenSource, IClipAnimationPlayerEventMap, };
@@ -1,3 +1,6 @@
1
+ import { Tween } from 'three/examples/jsm/libs/tween.module.js';
2
+ import { Vector3, Euler } from 'three';
3
+ import { IVector3 } from './base';
1
4
  type AnimationModeType = 'Linear.None' | 'Quadratic.In' | 'Quadratic.Out' | 'Quadratic.InOut' | 'Cubic.In' | 'Cubic.Out' | 'Cubic.InOut' | 'Quartic.In' | 'Quartic.Out' | 'Quartic.InOut' | 'Quintic.In' | 'Quintic.Out' | 'Quintic.InOut' | 'Sinusoidal.In' | 'Sinusoidal.Out' | 'Sinusoidal.InOut' | 'Exponential.In' | 'Exponential.Out' | 'Exponential.InOut' | 'Circular.In' | 'Circular.Out' | 'Circular.InOut' | 'Elastic.In' | 'Elastic.Out' | 'Elastic.InOut' | 'Back.In' | 'Back.Out' | 'Back.InOut' | 'Bounce.In' | 'Bounce.Out' | 'Bounce.InOut';
2
5
  type AnimationModeValueType = (amount: number) => number;
3
6
  interface AnimationOptions {
@@ -7,4 +10,95 @@ interface AnimationOptions {
7
10
  mode?: AnimationModeType;
8
11
  yoyo?: boolean;
9
12
  }
10
- export { AnimationModeType, AnimationModeValueType, AnimationOptions, };
13
+ /**
14
+ * 剪辑动画 —— 单个关键帧
15
+ *
16
+ * @remarks
17
+ * 字段与 bimeditor `IAnimationKeyframe` 协议对齐,可直接将服务端数据传入
18
+ * `ssp.playClipAnimation` 而不需要任何字段映射。
19
+ *
20
+ * - `position` / `scale` 单位为模型世界单位
21
+ * - `rotation` 为欧拉角,**单位:弧度**(与 three.js `Euler` 一致)
22
+ * - `repeat = -1` 解释为 `Infinity`
23
+ */
24
+ interface IClipAnimationFrame {
25
+ /** 关键帧业务 ID(SDK 内部不使用) */
26
+ id?: string;
27
+ /** 目标 position */
28
+ position: IVector3;
29
+ /** 目标 rotation(欧拉角,弧度) */
30
+ rotation: IVector3;
31
+ /** 目标 scale */
32
+ scale: IVector3;
33
+ /** 缓动曲线名称 */
34
+ easing: AnimationModeType;
35
+ /** 持续时间(毫秒),默认 `1000` */
36
+ duration?: number;
37
+ /** 起始延迟(毫秒),默认 `0` */
38
+ delay?: number;
39
+ /** 重复次数;`-1` 视为无限循环;默认 `0`(不重复) */
40
+ repeat?: number;
41
+ /** 是否往返播放,默认 `false` */
42
+ yoyo?: boolean;
43
+ /** 帧排序索引;SDK 在播放前会按此字段升序排序 */
44
+ index?: number;
45
+ /** 业务保留字段(与 SDK 内部行为无关) */
46
+ mode?: string;
47
+ }
48
+ /**
49
+ * 剪辑动画
50
+ *
51
+ * @remarks
52
+ * 字段与 bimeditor `IAnimationClip` 协议对齐。`refId` 是目标对象的标识,
53
+ * SDK 在 `model` 子树内按 `sid → uuid → userData.key` 顺序查找命中节点。
54
+ */
55
+ interface IClipAnimation {
56
+ /** 剪辑业务 ID(SDK 内部不使用) */
57
+ id?: string;
58
+ /** 剪辑名称(SDK 内部不使用) */
59
+ name?: string;
60
+ /** 目标对象的 sid / uuid / userData.key */
61
+ refId: string;
62
+ /** 关键帧列表(按 {@link IClipAnimationFrame.index} 升序播放) */
63
+ keyframes: IClipAnimationFrame[];
64
+ }
65
+ /**
66
+ * 剪辑动画 —— 初始 / 中间 transform 快照
67
+ * @internal 由 `ClipAnimationPlayer.initTransform` 记录,供 `reset` 还原使用
68
+ */
69
+ interface IClipTransform {
70
+ position: Vector3 | IVector3;
71
+ rotation: Euler | IVector3;
72
+ scale: Vector3 | IVector3;
73
+ }
74
+ /**
75
+ * 剪辑动画 —— tween 内部使用的扁平 9 通道数据
76
+ * @internal 把 position / rotation / scale 拍平成 tween 能补间的标量集合
77
+ */
78
+ interface IClipTweenSource {
79
+ x: number;
80
+ y: number;
81
+ z: number;
82
+ rotationX: number;
83
+ rotationY: number;
84
+ rotationZ: number;
85
+ scaleX: number;
86
+ scaleY: number;
87
+ scaleZ: number;
88
+ }
89
+ /**
90
+ * 剪辑动画 —— 播放器事件
91
+ *
92
+ * - `update`:每帧 tween 更新时触发,`source` 为当前帧的 9 通道值
93
+ * - `start` :每段 tween 开始时触发
94
+ */
95
+ interface IClipAnimationPlayerEventMap {
96
+ update: {
97
+ source: IClipTweenSource;
98
+ tween: Tween<IClipTweenSource>;
99
+ };
100
+ start: {
101
+ tween: Tween<IClipTweenSource>;
102
+ };
103
+ }
104
+ export { AnimationModeType, AnimationModeValueType, AnimationOptions, IClipAnimationFrame, IClipAnimation, IClipTransform, IClipTweenSource, IClipAnimationPlayerEventMap, };
package/types/index.d.ts CHANGED
@@ -2,12 +2,12 @@ import { Object3D, Vector3, Euler, Box3, AnimationClip, Light, Texture, Mesh, Sk
2
2
  import { default as Animation } from './Animation';
3
3
  import { PathAnimation, PathAnimationOptions } from './Animation/path-animation';
4
4
  import { CreatePathAnimationOptions, CreatePathAnimationActionForCameraOptions, CreateBonePathAnimationOptions, AnimationPath } from './Animation/createPathAnimation';
5
+ import { IClipAnimation, BaseObjectInfo, ViewportOptions, SceneGlobalEvents, PluginsConstructor, IColor, Position, Rotation, OffsetPoint, ModelAnimationFindFunc, TopologyNodeInfo, FlyToViewpoint, FlyToOptions, FlyToObjOptions, SurroundOptions, LabelOptions, EdgeSelectOptions, StrokeSelectOptions, OpacitySelectOptions, HighlightSelectOptions, EmissiveSelectOptions, FogOptions, UserDataPropertyFindFunc, AmbientLightOptions, DirectionalLightOptions, HemisphereLightOptions, SpotLightOptions, PointLightOptions, CloneModelInfo, ClonePoiInfo, ShortestPathInfo, ShortestPathByMultipleStartPoints, ShortestPathByMultipleEndPoints, TopologyInfoForGml, GridHelperOptions, AxesHelperOptions, BoxHelperOptions, PlaneHelperOptions, GroundHelperOptions, DirectionalLightHelperOptions, HemisphereLightHelperOptions, SpotLightHelperOptions, PointLightHelperOptions, SignalsState, ControlsOptions, RectAreaLightOptions, RectAreaLightHelperOptions, SkyOptions, IColorSpace, ToneMappingOptions, SSAOOptions, BloomOptions, IVector3, EnvironmentOptions, PluginsConstructorWithOptions, TopologyPassableInfo, CameraViewpointData, CameraViewpointDataLegacy, CameraType } from './Interface';
5
6
  import { BaseObject3D, Model, ModelInfo, Poi, PoiInfo, PoiNode, PoiNodeInfo, Topology, TopologyInfo, Group, GroupInfo, Canvas3D, Canvas3DInfo, PluginObject, PluginObjectInfo, DecalInfo, Decal, DecalGeometryInfo, PoiMeshInfo, PolygonPoiMeshInfo } from './Library';
6
7
  import { ObjectsCache } from './Cache';
7
8
  import { default as Viewport } from './Viewport';
8
9
  import { default as Controls } from './Controls';
9
10
  import { default as Manager } from './Manager';
10
- import { BaseObjectInfo, ViewportOptions, SceneGlobalEvents, PluginsConstructor, IColor, Position, Rotation, OffsetPoint, ModelAnimationFindFunc, TopologyNodeInfo, FlyToViewpoint, FlyToOptions, FlyToObjOptions, SurroundOptions, LabelOptions, EdgeSelectOptions, StrokeSelectOptions, OpacitySelectOptions, HighlightSelectOptions, EmissiveSelectOptions, FogOptions, UserDataPropertyFindFunc, AmbientLightOptions, DirectionalLightOptions, HemisphereLightOptions, SpotLightOptions, PointLightOptions, CloneModelInfo, ClonePoiInfo, ShortestPathInfo, ShortestPathByMultipleStartPoints, ShortestPathByMultipleEndPoints, TopologyInfoForGml, GridHelperOptions, AxesHelperOptions, BoxHelperOptions, PlaneHelperOptions, GroundHelperOptions, DirectionalLightHelperOptions, HemisphereLightHelperOptions, SpotLightHelperOptions, PointLightHelperOptions, SignalsState, ControlsOptions, RectAreaLightOptions, RectAreaLightHelperOptions, SkyOptions, IColorSpace, ToneMappingOptions, SSAOOptions, BloomOptions, IVector3, EnvironmentOptions, PluginsConstructorWithOptions, TopologyPassableInfo, CameraViewpointData, CameraViewpointDataLegacy, CameraType } from './Interface';
11
11
  import { BoxSpace, FindObjectsNearPosition, FindNearbyObjects, SetTextureOptions } from './tools';
12
12
  import { ModelsBoundsTreeOptions } from './Viewport/Bvh';
13
13
  import { AnimationOperate, CreateChainSkeletalModelOptions, CreateCurveAnimationClipForBonesOptions } from '@three3d/animation';
@@ -1284,6 +1284,139 @@ declare class SoonSpace {
1284
1284
  skeletalModel: any;
1285
1285
  skeleton: any;
1286
1286
  };
1287
+ /**
1288
+ * 在指定模型上播放剪辑动画
1289
+ *
1290
+ * @description
1291
+ * 在 `model` 子树内按 `clip.refId` 查找目标对象(依次匹配子节点的
1292
+ * `sid` / `uuid` / `userData.key`),将 `clip.keyframes` 作为
1293
+ * position / rotation / scale 的补间序列应用到目标。
1294
+ *
1295
+ * - 同一 `model` + `refId` 多次播放会复用内部 player,{@link resetClipAnimation}
1296
+ * 能精确还原到首次播放前的姿态
1297
+ * - 数组形式按数组顺序串行播放;中途调用 {@link stopClipAnimation}(model) /
1298
+ * {@link resetClipAnimation}(model) / {@link disposeClipAnimation}(model)
1299
+ * 会打断剩余序列
1300
+ *
1301
+ * @param model - 模型作用域:`Object3D` 实例或其顶层 id 字符串
1302
+ * @param data - 单个剪辑或剪辑数组({@link IClipAnimation})
1303
+ * @returns 模型 / 目标找不到时立即 resolve;否则在动画完成、被 stop 或被打断时 resolve
1304
+ *
1305
+ * @example
1306
+ * ```ts
1307
+ * await ssp.playClipAnimation(model, clip) // 单 clip
1308
+ * await ssp.playClipAnimation(model, clips) // 数组顺序播放
1309
+ * ```
1310
+ */
1311
+ playClipAnimation(model: Object3D | string, data: IClipAnimation | IClipAnimation[]): Promise<void>;
1312
+ /**
1313
+ * 停止指定模型上的剪辑动画
1314
+ *
1315
+ * @description
1316
+ * - 不传 `data`:停止该模型上**所有**已播放过的 target,并打断进行中的串行序列
1317
+ * - 传 `data`:仅停止 `data` 对应的 target,**不**打断同模型上的串行序列
1318
+ *
1319
+ * @param model - 模型作用域:`Object3D` 实例或其顶层 id 字符串
1320
+ * @param data - 单个剪辑或剪辑数组;省略则作用于整个模型
1321
+ *
1322
+ * @example
1323
+ * ```ts
1324
+ * ssp.stopClipAnimation(model) // 停该模型上全部
1325
+ * ssp.stopClipAnimation(model, clip) // 只停指定 clip
1326
+ * ssp.stopClipAnimation(model, clips) // 只停一组 clip
1327
+ * ```
1328
+ */
1329
+ stopClipAnimation(model: Object3D | string, data?: IClipAnimation | IClipAnimation[]): void;
1330
+ /**
1331
+ * 复位指定模型上的剪辑动画到首次播放前的姿态(停止 + 还原 transform)
1332
+ *
1333
+ * @description
1334
+ * - 不传 `data`:复位该模型上**所有**已播放过的 target,并打断进行中的串行序列
1335
+ * - 传 `data`:仅复位 `data` 对应的 target,**不**打断同模型上的串行序列
1336
+ *
1337
+ * 还原的姿态来自该 target 首次 `playClipAnimation` 之前的状态,由 SDK 内部记录。
1338
+ *
1339
+ * @param model - 模型作用域:`Object3D` 实例或其顶层 id 字符串
1340
+ * @param data - 单个剪辑或剪辑数组;省略则作用于整个模型
1341
+ *
1342
+ * @example
1343
+ * ```ts
1344
+ * ssp.resetClipAnimation(model) // 复位该模型上全部
1345
+ * ssp.resetClipAnimation(model, clip) // 只复位指定 clip
1346
+ * ```
1347
+ */
1348
+ resetClipAnimation(model: Object3D | string, data?: IClipAnimation | IClipAnimation[]): void;
1349
+ /**
1350
+ * 释放指定模型在剪辑动画系统中的所有缓存与正在进行的播放
1351
+ *
1352
+ * @description
1353
+ * 应在模型从场景移除前调用,否则缓存里会残留指向已脱离场景的 target 的 player。
1354
+ * 内部会:
1355
+ * 1. 打断该模型上进行中的串行序列
1356
+ * 2. 对每个缓存 player 调用 dispose(停止 tween + 移除 initTransform 标记)
1357
+ * 3. 清空 `model -> targets` / target -> player 的索引
1358
+ *
1359
+ * @param model - 模型作用域:`Object3D` 实例或其顶层 id 字符串
1360
+ *
1361
+ * @example
1362
+ * ```ts
1363
+ * ssp.disposeClipAnimation(model)
1364
+ * ssp.removeObject(model)
1365
+ * ```
1366
+ */
1367
+ disposeClipAnimation(model: Object3D | string): void;
1368
+ /**
1369
+ * 剪辑动画 —— player 缓存
1370
+ * @internal key = target.uuid(three.js 自动分配,全局唯一),value = 该 target 的 player
1371
+ */
1372
+ private _clipPlayerCache;
1373
+ /**
1374
+ * 剪辑动画 —— 每个模型上播放过的 target 索引
1375
+ * @internal key = model.uuid,value = 在该模型子树内播放过的所有 target.uuid
1376
+ *
1377
+ * 用于按模型范围实现 {@link stopClipAnimation} / {@link resetClipAnimation} / {@link disposeClipAnimation}
1378
+ * 的 O(targets) 操作,避免遍历全局 player 缓存。
1379
+ */
1380
+ private _modelClipTargets;
1381
+ /**
1382
+ * 剪辑动画 —— 数组串行播放的 abort 注册表
1383
+ * @internal key = model.uuid,value = 当前在该模型上 in-flight 的 aborter 集合
1384
+ *
1385
+ * 每个 in-flight 的 {@link playClipAnimation} 调用注册一个 aborter,stop / reset / dispose
1386
+ * 不传 data 时调用 {@link _abortInFlight} 触发它,使 for 循环在下一次迭代前 bail。
1387
+ */
1388
+ private _modelInFlight;
1389
+ /**
1390
+ * 触发指定模型上所有 in-flight 串行播放的 aborter
1391
+ * @internal
1392
+ */
1393
+ private _abortInFlight;
1394
+ /**
1395
+ * 把传入的 model 参数解析为 Object3D
1396
+ * @internal 字符串走 {@link getObjectById},Object3D 直接返回
1397
+ */
1398
+ private _resolveClipModel;
1399
+ /**
1400
+ * 取出(或惰性创建)某个 (model, refId) 对应的 player
1401
+ * @internal
1402
+ *
1403
+ * - 缓存命中:复用,确保 `getInitialTransform()` 仍指向首次播放前的姿态
1404
+ * - target 已替换(uuid 偶发复用):dispose 旧的,重建
1405
+ * - 新建时立刻 `initTransform()` 记录初始姿态,并登记到 `_modelClipTargets`
1406
+ */
1407
+ private _getOrCreateClipPlayer;
1408
+ /**
1409
+ * 在 model 子树(含 model 自身)内定位剪辑动画目标
1410
+ * @internal
1411
+ *
1412
+ * 命中条件(按短路顺序):`node.sid === id` → `node.uuid === id` → `node.userData.key === id`
1413
+ *
1414
+ * - `sid` —— SBM 子 mesh 的常见情形
1415
+ * - `uuid` —— three.js 自动分配的全局唯一 id
1416
+ * - `userData.key` —— 与 bimeditor `getMeshByUserDataUuid` 行为对齐,
1417
+ * 用于组件编辑器写入 userData 的情形
1418
+ */
1419
+ private _findClipTarget;
1287
1420
  /**
1288
1421
  * 创建骨骼沿曲线路径运动的动画
1289
1422
  * @param model