@nimbus2d/core 0.0.1

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.
Files changed (85) hide show
  1. package/dist/index.mjs +18433 -0
  2. package/package.json +39 -0
  3. package/src/base/EventEmitter.js +187 -0
  4. package/src/base/Subsystem.js +183 -0
  5. package/src/base/index.js +6 -0
  6. package/src/core/Application/AppState.js +27 -0
  7. package/src/core/Application/Application.js +480 -0
  8. package/src/core/Application/DefaultConfig.js +63 -0
  9. package/src/core/Application/index.js +7 -0
  10. package/src/core/AssetManager/AssetManager.js +711 -0
  11. package/src/core/AssetManager/AssetTypes.js +108 -0
  12. package/src/core/AssetManager/adapters/IResourceAdapter.js +50 -0
  13. package/src/core/AssetManager/adapters/PixiAdapter.js +90 -0
  14. package/src/core/AssetManager/core/RefCounter.js +167 -0
  15. package/src/core/AssetManager/core/ResourceCache.js +281 -0
  16. package/src/core/AssetManager/core/ResourceEntry.js +191 -0
  17. package/src/core/AssetManager/core/ResourceEventBus.js +127 -0
  18. package/src/core/AssetManager/handlers/IResourceHandler.js +45 -0
  19. package/src/core/AssetManager/index.js +26 -0
  20. package/src/core/AssetManager/plugins/IResourcePlugin.js +56 -0
  21. package/src/core/Camera/Camera.js +534 -0
  22. package/src/core/Camera/CameraTypes.js +59 -0
  23. package/src/core/Camera/index.js +13 -0
  24. package/src/core/ConfigSystem/ConfigLayer.js +230 -0
  25. package/src/core/ConfigSystem/ConfigLayerType.js +31 -0
  26. package/src/core/ConfigSystem/ConfigMerger.js +50 -0
  27. package/src/core/ConfigSystem/ConfigPath.js +96 -0
  28. package/src/core/ConfigSystem/ConfigSystem.js +378 -0
  29. package/src/core/ConfigSystem/ConfigTypes.js +29 -0
  30. package/src/core/ConfigSystem/ConfigWatcher.js +84 -0
  31. package/src/core/ConfigSystem/index.js +19 -0
  32. package/src/core/EventBus/EventBus.js +797 -0
  33. package/src/core/EventBus/Interceptor.js +26 -0
  34. package/src/core/EventBus/PerformanceStats.js +105 -0
  35. package/src/core/EventBus/index.js +7 -0
  36. package/src/core/Lifecycle/Lifecycle.js +265 -0
  37. package/src/core/Lifecycle/LifecycleState.js +31 -0
  38. package/src/core/Lifecycle/index.js +6 -0
  39. package/src/core/Logger/ConsoleHandler.js +55 -0
  40. package/src/core/Logger/LogHandler.js +34 -0
  41. package/src/core/Logger/LogLevel.js +38 -0
  42. package/src/core/Logger/Logger.js +234 -0
  43. package/src/core/Logger/index.js +8 -0
  44. package/src/core/PluginSystem/Plugin.js +156 -0
  45. package/src/core/PluginSystem/PluginEntry.js +102 -0
  46. package/src/core/PluginSystem/PluginState.js +30 -0
  47. package/src/core/PluginSystem/PluginSystem.js +530 -0
  48. package/src/core/PluginSystem/index.js +8 -0
  49. package/src/core/PoolManager/DefaultConfig.js +19 -0
  50. package/src/core/PoolManager/ObjectPool.js +326 -0
  51. package/src/core/PoolManager/PoolManager.js +253 -0
  52. package/src/core/PoolManager/PoolTypes.js +92 -0
  53. package/src/core/PoolManager/index.js +15 -0
  54. package/src/core/SceneManager/FadeTransition.js +64 -0
  55. package/src/core/SceneManager/MaskTransition.js +234 -0
  56. package/src/core/SceneManager/Scene.js +221 -0
  57. package/src/core/SceneManager/SceneManager.js +658 -0
  58. package/src/core/SceneManager/SceneState.js +29 -0
  59. package/src/core/SceneManager/SlideTransition.js +113 -0
  60. package/src/core/SceneManager/Transition.js +102 -0
  61. package/src/core/SceneManager/ZoomTransition.js +119 -0
  62. package/src/core/SceneManager/index.js +12 -0
  63. package/src/core/SpriteGPULayer/SpriteGPULayer.js +321 -0
  64. package/src/core/SpriteGPULayer/SpriteGPULayerTypes.js +49 -0
  65. package/src/core/SpriteGPULayer/index.js +11 -0
  66. package/src/core/Timeline/Clip.js +101 -0
  67. package/src/core/Timeline/DefaultConfig.js +41 -0
  68. package/src/core/Timeline/Easing.js +176 -0
  69. package/src/core/Timeline/Timeline.js +458 -0
  70. package/src/core/Timeline/TimelineTypes.js +89 -0
  71. package/src/core/Timeline/Track.js +202 -0
  72. package/src/core/Timeline/index.js +22 -0
  73. package/src/errors/ConfigError.js +47 -0
  74. package/src/errors/LifecycleError.js +58 -0
  75. package/src/errors/NimbusError.js +43 -0
  76. package/src/errors/PluginError.js +138 -0
  77. package/src/errors/ResourceError.js +166 -0
  78. package/src/errors/SceneError.js +124 -0
  79. package/src/errors/SubsystemError.js +68 -0
  80. package/src/errors/index.js +53 -0
  81. package/src/index.js +86 -0
  82. package/src/types/index.js +141 -0
  83. package/src/utils/MemoryChecker.js +374 -0
  84. package/src/utils/Validator.js +60 -0
  85. package/src/utils/index.js +84 -0
@@ -0,0 +1,458 @@
1
+ // ============================================================================
2
+ // Nimbus2D - Timeline 时间线主类
3
+ // ----------------------------------------------------------------------------
4
+ // 职责:
5
+ // 1. 管理多条 Track,编排时间线动画
6
+ // 2. 提供播放控制(play/pause/stop/seek)
7
+ // 3. 支持循环(loop/loopCount)、反向播放(autoReverse)、自动销毁(autoDestroy)
8
+ // 4. 通过 EventBus 广播时间线事件(play/pause/stop/seek/loop/complete/destroy)
9
+ // 5. 每帧 update 推进所有 Track 的当前时间
10
+ //
11
+ // 设计决策:
12
+ // - 不继承任何类:Timeline 是独立的编排器
13
+ // - EventBus 注入:通过公开方法 setEventBus 注入(不放在构造函数)
14
+ // 避免 Timeline 构造时强制依赖 EventBus,符合依赖注入最佳实践
15
+ // - 事件发射 try-catch:避免事件总线异常影响主流程
16
+ // - 销毁幂等:通过 _isDestroyed 标志避免重复销毁导致崩溃
17
+ // - autoReverse + loop 计数:正向到终点 + 反向到起点 = 1 次完整循环
18
+ // 符合用户直觉(设置 loopCount=2 看到 2 次往返动画)
19
+ // - autoReverse + 非 loop:正向到终点 → 反向到起点 → 完成
20
+ // - duration 自动计算:addTrack/removeTrack 后重新计算总时长
21
+ // - currentTime 范围约束:[0, duration],避免越界
22
+ // - 单 Track 异常隔离:try-catch 包裹 track.evaluate,避免影响其他 Track
23
+ //
24
+ // 四期新增(任务 1.6/4.4):Timeline 动画引擎主类
25
+ // ============================================================================
26
+
27
+ import { Track } from './Track.js'
28
+ import { TimelineEventType, TimelineState, TimelineError } from './TimelineTypes.js'
29
+
30
+ class Timeline {
31
+ /**
32
+ * 创建 Timeline 实例
33
+ * @param {Object} [options={}] - 配置
34
+ * @param {boolean} [options.loop=false] - 是否循环
35
+ * @param {number} [options.loopCount=Infinity] - 循环次数(Infinity 表示无限)
36
+ * @param {boolean} [options.autoReverse=false] - 反向播放(到达终点后反向回到起点)
37
+ * @param {boolean} [options.autoDestroy=false] - 完成后自动销毁
38
+ */
39
+ constructor(options = {}) {
40
+ /** @type {Track[]} 轨道列表 */
41
+ this._tracks = []
42
+
43
+ /** @type {boolean} 是否播放中(含暂停状态) */
44
+ this._isPlaying = false
45
+
46
+ /** @type {boolean} 是否暂停 */
47
+ this._isPaused = false
48
+
49
+ /** @type {number} 当前时间(秒) */
50
+ this._currentTime = 0
51
+
52
+ /** @type {number} 总时长(秒,自动计算) */
53
+ this._duration = 0
54
+
55
+ /** @type {boolean} 是否循环 */
56
+ this._loop = options.loop ?? false
57
+
58
+ /** @type {number} 循环次数上限(必须为正数,否则降级到 Infinity) */
59
+ this._loopCount = (typeof options.loopCount === 'number' && options.loopCount > 0)
60
+ ? options.loopCount
61
+ : Infinity
62
+
63
+ /** @type {number} 当前已完成循环次数 */
64
+ this._currentLoop = 0
65
+
66
+ /** @type {boolean} 是否反向播放 */
67
+ this._autoReverse = options.autoReverse ?? false
68
+
69
+ /** @type {boolean} 完成后自动销毁 */
70
+ this._autoDestroy = options.autoDestroy ?? false
71
+
72
+ /** @type {number} 播放方向(1=正向,-1=反向) */
73
+ this._direction = 1
74
+
75
+ /** @type {EventBus|null} 事件总线(通过 setEventBus 注入) */
76
+ this._eventBus = null
77
+
78
+ /** @type {boolean} 是否已销毁 */
79
+ this._isDestroyed = false
80
+
81
+ /** @type {string} 当前状态(TimelineState 枚举值) */
82
+ this._state = TimelineState.IDLE
83
+ }
84
+
85
+ // --------------------------------------------------------------------------
86
+ // 轨道管理
87
+ // --------------------------------------------------------------------------
88
+
89
+ /**
90
+ * 添加轨道
91
+ * @param {Track} track - 属性轨道
92
+ * @returns {Timeline} this(链式)
93
+ * @throws {TimelineError} track 不是 Track 实例
94
+ */
95
+ addTrack(track) {
96
+ if (this._isDestroyed) return this
97
+ if (!(track instanceof Track)) {
98
+ throw new TimelineError('addTrack 参数必须是 Track 实例', 'TIMELINE_INVALID_TRACK')
99
+ }
100
+ this._tracks.push(track)
101
+ this._recalculateDuration()
102
+ return this
103
+ }
104
+
105
+ /**
106
+ * 移除轨道
107
+ * @param {Track} track - 属性轨道
108
+ * @returns {boolean} 是否移除成功
109
+ */
110
+ removeTrack(track) {
111
+ if (this._isDestroyed) return false
112
+ const index = this._tracks.indexOf(track)
113
+ if (index === -1) return false
114
+ this._tracks.splice(index, 1)
115
+ this._recalculateDuration()
116
+ return true
117
+ }
118
+
119
+ /**
120
+ * 清空所有轨道(不销毁 Track 实例,由调用方负责)
121
+ */
122
+ clearTracks() {
123
+ if (this._isDestroyed) return
124
+ this._tracks.length = 0
125
+ this._recalculateDuration()
126
+ }
127
+
128
+ /**
129
+ * 获取轨道数量
130
+ * @returns {number}
131
+ */
132
+ get trackCount() {
133
+ return this._tracks.length
134
+ }
135
+
136
+ // --------------------------------------------------------------------------
137
+ // 播放控制
138
+ // --------------------------------------------------------------------------
139
+
140
+ /**
141
+ * 开始播放
142
+ * 若已暂停则恢复播放;若已完成则从头开始播放
143
+ * @returns {Timeline} this(链式)
144
+ */
145
+ play() {
146
+ if (this._isDestroyed) return this
147
+ // 已在播放中(非暂停):无操作
148
+ if (this._isPlaying && !this._isPaused) return this
149
+
150
+ // 从完成状态恢复:重置循环计数、方向、时间
151
+ if (this._state === TimelineState.COMPLETED) {
152
+ this._currentTime = 0
153
+ this._currentLoop = 0
154
+ this._direction = 1
155
+ }
156
+
157
+ this._isPlaying = true
158
+ this._isPaused = false
159
+ this._state = TimelineState.PLAYING
160
+ this._emit(TimelineEventType.PLAY, { timeline: this })
161
+ return this
162
+ }
163
+
164
+ /**
165
+ * 暂停播放
166
+ * @returns {Timeline} this(链式)
167
+ */
168
+ pause() {
169
+ if (this._isDestroyed) return this
170
+ // 未播放或已暂停:无操作
171
+ if (!this._isPlaying || this._isPaused) return this
172
+
173
+ this._isPaused = true
174
+ this._state = TimelineState.PAUSED
175
+ this._emit(TimelineEventType.PAUSE, { timeline: this })
176
+ return this
177
+ }
178
+
179
+ /**
180
+ * 停止播放并重置时间
181
+ * @returns {Timeline} this(链式)
182
+ */
183
+ stop() {
184
+ if (this._isDestroyed) return this
185
+ const wasPlaying = this._isPlaying
186
+
187
+ this._isPlaying = false
188
+ this._isPaused = false
189
+ this._currentTime = 0
190
+ this._currentLoop = 0
191
+ this._direction = 1
192
+ this._state = TimelineState.IDLE
193
+
194
+ // 仅在实际播放中触发 stop 事件
195
+ if (wasPlaying) {
196
+ this._emit(TimelineEventType.STOP, { timeline: this })
197
+ }
198
+ return this
199
+ }
200
+
201
+ /**
202
+ * 跳转到指定时间
203
+ * @param {number} time - 目标时间(秒)
204
+ * @returns {Timeline} this(链式)
205
+ */
206
+ seek(time) {
207
+ if (this._isDestroyed) return this
208
+ // 校验 time 是否为有效数字(防御 NaN/Infinity)
209
+ if (typeof time !== 'number' || Number.isNaN(time)) {
210
+ return this
211
+ }
212
+ // 范围约束 [0, duration]
213
+ const clampedTime = time < 0 ? 0 : time > this._duration ? this._duration : time
214
+ this._currentTime = clampedTime
215
+ this._evaluate()
216
+ this._emit(TimelineEventType.SEEK, { timeline: this, time: clampedTime })
217
+ return this
218
+ }
219
+
220
+ // --------------------------------------------------------------------------
221
+ // 状态查询
222
+ // --------------------------------------------------------------------------
223
+
224
+ /** @type {boolean} 是否播放中(不含暂停) */
225
+ get isPlaying() { return this._isPlaying && !this._isPaused }
226
+
227
+ /** @type {boolean} 是否暂停 */
228
+ get isPaused() { return this._isPaused }
229
+
230
+ /** @type {number} 总时长(秒) */
231
+ get duration() { return this._duration }
232
+
233
+ /** @type {number} 当前时间(秒) */
234
+ get currentTime() { return this._currentTime }
235
+
236
+ /** @type {number} 当前进度 [0,1] */
237
+ get progress() { return this._duration > 0 ? this._currentTime / this._duration : 0 }
238
+
239
+ /** @type {string} 当前状态(TimelineState 枚举值) */
240
+ get state() { return this._state }
241
+
242
+ /** @type {boolean} 是否已销毁 */
243
+ get isDestroyed() { return this._isDestroyed }
244
+
245
+ /** @type {number} 当前已完成循环次数 */
246
+ get currentLoop() { return this._currentLoop }
247
+
248
+ // --------------------------------------------------------------------------
249
+ // 帧更新
250
+ // --------------------------------------------------------------------------
251
+
252
+ /**
253
+ * 每帧更新(由外部主循环调用,如 Application.update 或 Scene.update)
254
+ * @param {number} delta - 帧间隔(秒)
255
+ */
256
+ update(delta) {
257
+ // 已销毁、未播放、已暂停:不推进
258
+ if (this._isDestroyed || !this._isPlaying || this._isPaused) return
259
+ // 校验 delta 是否为有效数字(防御 NaN/非数字输入导致 _currentTime 污染)
260
+ if (typeof delta !== 'number' || Number.isNaN(delta)) return
261
+
262
+ // 推进当前时间
263
+ this._currentTime += delta * this._direction
264
+
265
+ // === 边界处理 ===
266
+ if (this._direction > 0 && this._currentTime >= this._duration) {
267
+ // 正向到达终点
268
+ if (!this._handleForwardEnd()) return
269
+ } else if (this._direction < 0 && this._currentTime <= 0) {
270
+ // 反向到达起点
271
+ if (!this._handleBackwardEnd()) return
272
+ }
273
+
274
+ // 评估所有轨道
275
+ this._evaluate()
276
+ }
277
+
278
+ /**
279
+ * 处理正向到达终点
280
+ * @returns {boolean} true=继续播放,false=已结束(不再 evaluate)
281
+ * @private
282
+ */
283
+ _handleForwardEnd() {
284
+ this._currentTime = this._duration
285
+
286
+ // autoReverse 模式:切换为反向继续播放
287
+ if (this._autoReverse) {
288
+ this._direction = -1
289
+ // autoReverse 模式下:正向到终点不算一次完整循环
290
+ // 反向到起点后才算一次完整循环(在 _handleBackwardEnd 中计数)
291
+ // 若不循环:反向到起点后完成
292
+ // 若循环:反向到起点后计数 + 检查 loopCount
293
+ return true
294
+ }
295
+
296
+ // 非 autoReverse:循环检查
297
+ if (this._loop) {
298
+ this._currentLoop++
299
+ if (this._currentLoop >= this._loopCount) {
300
+ this._complete()
301
+ return false
302
+ }
303
+ // 重置时间到起点,继续下一轮循环
304
+ this._currentTime = 0
305
+ this._emit(TimelineEventType.LOOP, { timeline: this, loopCount: this._currentLoop })
306
+ return true
307
+ }
308
+
309
+ // 不循环:完成
310
+ this._complete()
311
+ return false
312
+ }
313
+
314
+ /**
315
+ * 处理反向到达起点(仅在 autoReverse 模式下触发)
316
+ * @returns {boolean} true=继续播放,false=已结束
317
+ * @private
318
+ */
319
+ _handleBackwardEnd() {
320
+ this._currentTime = 0
321
+
322
+ // autoReverse 模式:一次完整循环(正向+反向)完成
323
+ if (this._autoReverse) {
324
+ if (this._loop) {
325
+ // 计数 +1(正向+反向算一次循环)
326
+ this._currentLoop++
327
+ if (this._currentLoop >= this._loopCount) {
328
+ this._complete()
329
+ return false
330
+ }
331
+ // 切换为正向,继续下一轮循环
332
+ this._direction = 1
333
+ this._emit(TimelineEventType.LOOP, { timeline: this, loopCount: this._currentLoop })
334
+ return true
335
+ }
336
+ // autoReverse 但不循环:反向到起点后完成
337
+ this._complete()
338
+ return false
339
+ }
340
+
341
+ // 非 autoReverse 不会反向到达起点(_direction 应该是 1)
342
+ // 防御性处理:直接完成
343
+ this._complete()
344
+ return false
345
+ }
346
+
347
+ /**
348
+ * 评估所有轨道(带异常隔离)
349
+ * @private
350
+ */
351
+ _evaluate() {
352
+ for (const track of this._tracks) {
353
+ try {
354
+ track.evaluate(this._currentTime)
355
+ } catch (e) {
356
+ // 单个 Track 异常不影响其他 Track
357
+ }
358
+ }
359
+ }
360
+
361
+ /**
362
+ * 完成播放
363
+ * @private
364
+ */
365
+ _complete() {
366
+ // 设置到终点并应用最后一帧(确保最终状态正确)
367
+ this._currentTime = this._direction > 0 ? this._duration : 0
368
+ this._evaluate()
369
+ this._isPlaying = false
370
+ this._isPaused = false
371
+ this._direction = 1
372
+ this._state = TimelineState.COMPLETED
373
+ this._emit(TimelineEventType.COMPLETE, { timeline: this })
374
+ // 自动销毁
375
+ if (this._autoDestroy) {
376
+ this.destroy()
377
+ }
378
+ }
379
+
380
+ /**
381
+ * 重新计算总时长(所有 Track 中最晚的 endTime)
382
+ * @private
383
+ */
384
+ _recalculateDuration() {
385
+ let max = 0
386
+ for (const track of this._tracks) {
387
+ const end = track.endTime
388
+ if (end > max) max = end
389
+ }
390
+ this._duration = max
391
+ // 若 currentTime 超出新 duration,约束到新 duration
392
+ if (this._currentTime > this._duration) {
393
+ this._currentTime = this._duration
394
+ }
395
+ }
396
+
397
+ // --------------------------------------------------------------------------
398
+ // EventBus
399
+ // --------------------------------------------------------------------------
400
+
401
+ /**
402
+ * 注入 EventBus(公开方法,由 Scene 或用户调用)
403
+ * @param {EventBus|null} eventBus - 事件总线,传 null 可断开
404
+ * @returns {Timeline} this(链式)
405
+ */
406
+ setEventBus(eventBus) {
407
+ if (this._isDestroyed) return this
408
+ this._eventBus = eventBus
409
+ return this
410
+ }
411
+
412
+ /**
413
+ * 发射事件(带异常捕获)
414
+ * @param {string} type - 事件类型
415
+ * @param {Object} data - 事件数据
416
+ * @private
417
+ */
418
+ _emit(type, data) {
419
+ if (!this._eventBus) return
420
+ try {
421
+ this._eventBus.emit(type, data)
422
+ } catch (e) {
423
+ // 事件总线异常忽略,避免影响主流程
424
+ }
425
+ }
426
+
427
+ // --------------------------------------------------------------------------
428
+ // 销毁
429
+ // --------------------------------------------------------------------------
430
+
431
+ /**
432
+ * 销毁时间线(幂等,可重复调用)
433
+ * 停止播放 + 销毁所有 Track + 清空引用 + 发射 destroy 事件
434
+ */
435
+ destroy() {
436
+ if (this._isDestroyed) return
437
+ this._isDestroyed = true
438
+ this._isPlaying = false
439
+ this._isPaused = false
440
+ this._state = TimelineState.DESTROYED
441
+
442
+ // 销毁所有 Track(带异常隔离)
443
+ for (const track of this._tracks) {
444
+ try {
445
+ track.destroy()
446
+ } catch (e) {
447
+ // 单个 Track 销毁异常忽略
448
+ }
449
+ }
450
+ this._tracks.length = 0
451
+
452
+ // 发射销毁事件(在 eventBus 被置 null 之前)
453
+ this._emit(TimelineEventType.DESTROY, { timeline: this })
454
+ this._eventBus = null
455
+ }
456
+ }
457
+
458
+ export { Timeline }
@@ -0,0 +1,89 @@
1
+ // ============================================================================
2
+ // Nimbus2D - Timeline 类型定义
3
+ // ----------------------------------------------------------------------------
4
+ // 职责:
5
+ // 1. 定义 Timeline 相关的事件类型枚举(TimelineEventType)
6
+ // 2. 定义 Timeline 状态枚举(TimelineState)
7
+ // 3. 定义 Timeline 错误类(TimelineError)
8
+ //
9
+ // 设计决策:
10
+ // - 事件类型使用 Object.freeze 冻结,防止运行时被篡改
11
+ // - 状态枚举使用 Object.freeze 冻结
12
+ // - 错误类继承 NimbusError,附加 module='Timeline' 字段
13
+ // - 与 Camera/SceneManager 的类型定义风格保持一致
14
+ //
15
+ // 四期新增(任务 1.6):Timeline 动画引擎的类型定义
16
+ // ============================================================================
17
+
18
+ import { NimbusError } from '../../errors/NimbusError.js'
19
+
20
+ // ----------------------------------------------------------------------------
21
+ // 事件类型枚举
22
+ // ----------------------------------------------------------------------------
23
+
24
+ /**
25
+ * Timeline 事件类型
26
+ * @enum {string}
27
+ * @readonly
28
+ */
29
+ const TimelineEventType = Object.freeze({
30
+ /** 播放开始(play 调用) */
31
+ PLAY: 'timeline:play',
32
+ /** 暂停(pause 调用) */
33
+ PAUSE: 'timeline:pause',
34
+ /** 停止(stop 调用,currentTime 重置为 0) */
35
+ STOP: 'timeline:stop',
36
+ /** 跳转(seek 调用) */
37
+ SEEK: 'timeline:seek',
38
+ /** 循环(每次循环开始) */
39
+ LOOP: 'timeline:loop',
40
+ /** 完成(非循环模式到达终点,或循环次数到达) */
41
+ COMPLETE: 'timeline:complete',
42
+ /** 销毁(destroy 调用) */
43
+ DESTROY: 'timeline:destroy'
44
+ })
45
+
46
+ // ----------------------------------------------------------------------------
47
+ // 状态枚举
48
+ // ----------------------------------------------------------------------------
49
+
50
+ /**
51
+ * Timeline 状态
52
+ * @enum {string}
53
+ * @readonly
54
+ */
55
+ const TimelineState = Object.freeze({
56
+ /** 已创建(未播放) */
57
+ IDLE: 'idle',
58
+ /** 播放中 */
59
+ PLAYING: 'playing',
60
+ /** 暂停中 */
61
+ PAUSED: 'paused',
62
+ /** 已完成 */
63
+ COMPLETED: 'completed',
64
+ /** 已销毁 */
65
+ DESTROYED: 'destroyed'
66
+ })
67
+
68
+ // ----------------------------------------------------------------------------
69
+ // 错误类
70
+ // ----------------------------------------------------------------------------
71
+
72
+ /**
73
+ * Timeline 错误基类
74
+ * 所有 Timeline 错误构造函数设置 module='Timeline'
75
+ * @extends NimbusError
76
+ */
77
+ class TimelineError extends NimbusError {
78
+ /**
79
+ * 构造函数
80
+ * @param {string} message - 错误消息
81
+ * @param {string} [code='TIMELINE_ERROR'] - 错误码
82
+ * @param {Error|null} [cause=null] - 原始错误
83
+ */
84
+ constructor(message, code = 'TIMELINE_ERROR', cause = null) {
85
+ super(message, code, 'Timeline', cause)
86
+ }
87
+ }
88
+
89
+ export { TimelineEventType, TimelineState, TimelineError }