@umituz/react-native-mascot 1.0.4 → 1.0.7

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 (39) hide show
  1. package/README.md +60 -0
  2. package/package.json +2 -1
  3. package/src/application/services/AnimationStateManager.ts +69 -0
  4. package/src/application/services/AppearanceManagement.ts +40 -0
  5. package/src/application/services/MascotService.ts +42 -33
  6. package/src/application/services/PersonalityManagement.ts +39 -0
  7. package/src/application/services/StateHistory.ts +55 -0
  8. package/src/application/services/StateMachine.ts +154 -0
  9. package/src/application/services/StateTransitions.ts +73 -0
  10. package/src/application.ts +40 -0
  11. package/src/assets/index.ts +14 -19
  12. package/src/core.ts +62 -0
  13. package/src/domain/entities/Mascot.ts +186 -127
  14. package/src/domain/types/AnimationStateTypes.ts +148 -0
  15. package/src/domain/types/MascotTypes.ts +9 -0
  16. package/src/domain/value-objects/AnimationState.ts +126 -0
  17. package/src/index.ts +9 -99
  18. package/src/infrastructure/controllers/AnimationController.ts +26 -122
  19. package/src/infrastructure/controllers/AnimationPlayer.ts +104 -0
  20. package/src/infrastructure/controllers/AnimationTimer.ts +62 -0
  21. package/src/infrastructure/controllers/EventManager.ts +108 -0
  22. package/src/infrastructure/di/Container.ts +73 -10
  23. package/src/infrastructure/managers/AssetManager.ts +134 -63
  24. package/src/infrastructure/managers/MascotBuilder.ts +89 -0
  25. package/src/infrastructure/managers/MascotFactory.ts +24 -176
  26. package/src/infrastructure/managers/MascotTemplates.ts +151 -0
  27. package/src/infrastructure/utils/LRUCache.ts +218 -0
  28. package/src/infrastructure.ts +24 -0
  29. package/src/presentation/components/LottieMascot.tsx +85 -0
  30. package/src/presentation/components/MascotView.tsx +42 -233
  31. package/src/presentation/components/SVGMascot.tsx +61 -0
  32. package/src/presentation/contexts/MascotContext.tsx +2 -3
  33. package/src/presentation/hooks/useMascot.ts +118 -39
  34. package/src/presentation/hooks/useMascotAnimation.ts +9 -15
  35. package/src/presentation/hooks/useMascotState.ts +213 -0
  36. package/src/presentation.ts +37 -0
  37. package/src/types.d.ts +4 -0
  38. package/src/application/index.ts +0 -8
  39. package/src/domain/value-objects/index.ts +0 -9
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Animation State Types
3
+ * State-based animation system inspired by AIStylistMascot implementation
4
+ */
5
+
6
+ /**
7
+ * Predefined animation states with specific behaviors
8
+ */
9
+ export type MascotAnimationState =
10
+ | 'idle' // Calm breathing, default state (loop)
11
+ | 'loading' // Active processing, rotation/swirl (loop)
12
+ | 'success' // Confirmation, scale pulse (non-loop)
13
+ | 'error' // Error acknowledgment, shake (non-loop)
14
+ | 'empty' // Empty state, inviting gesture (loop)
15
+ | 'guide'; // Onboarding assistance (loop)
16
+
17
+ /**
18
+ * State configuration for each animation state
19
+ */
20
+ export interface MascotStateConfig {
21
+ state: MascotAnimationState;
22
+ loop: boolean;
23
+ duration?: number; // in milliseconds
24
+ autoPlay?: boolean;
25
+ speed?: number;
26
+ onComplete?: () => void;
27
+ transitionTo?: MascotAnimationState; // Auto-transition after completion
28
+ }
29
+
30
+ /**
31
+ * State transition rules
32
+ */
33
+ export interface StateTransition {
34
+ from: MascotAnimationState;
35
+ to: MascotAnimationState;
36
+ condition?: 'always' | 'on-success' | 'on-error' | 'on-complete';
37
+ delay?: number; // Delay before transition (ms)
38
+ }
39
+
40
+ /**
41
+ * State history for tracking and debugging
42
+ */
43
+ export interface StateHistoryEntry {
44
+ state: MascotAnimationState;
45
+ timestamp: number;
46
+ duration?: number;
47
+ triggeredBy?: 'user' | 'system' | 'auto-transition';
48
+ }
49
+
50
+ /**
51
+ * Size variants for mascot display
52
+ */
53
+ export type MascotSize = 'small' | 'medium' | 'large' | number;
54
+
55
+ /**
56
+ * Size configuration in pixels
57
+ */
58
+ export interface MascotSizeConfig {
59
+ small: number;
60
+ medium: number;
61
+ large: number;
62
+ }
63
+
64
+ /**
65
+ * Default state configurations
66
+ */
67
+ export const DEFAULT_STATE_CONFIGS: Record<MascotAnimationState, MascotStateConfig> = {
68
+ idle: {
69
+ state: 'idle',
70
+ loop: true,
71
+ duration: 3000,
72
+ autoPlay: true,
73
+ speed: 1,
74
+ },
75
+ loading: {
76
+ state: 'loading',
77
+ loop: true,
78
+ duration: 2000,
79
+ autoPlay: true,
80
+ speed: 1,
81
+ },
82
+ success: {
83
+ state: 'success',
84
+ loop: false,
85
+ duration: 1000,
86
+ autoPlay: true,
87
+ speed: 1,
88
+ transitionTo: 'idle',
89
+ },
90
+ error: {
91
+ state: 'error',
92
+ loop: false,
93
+ duration: 500,
94
+ autoPlay: true,
95
+ speed: 1,
96
+ transitionTo: 'idle',
97
+ },
98
+ empty: {
99
+ state: 'empty',
100
+ loop: true,
101
+ duration: 3000,
102
+ autoPlay: true,
103
+ speed: 1,
104
+ },
105
+ guide: {
106
+ state: 'guide',
107
+ loop: true,
108
+ duration: 2000,
109
+ autoPlay: true,
110
+ speed: 1,
111
+ },
112
+ };
113
+
114
+ /**
115
+ * Default size configurations in pixels
116
+ */
117
+ export const DEFAULT_SIZE_CONFIG: MascotSizeConfig = {
118
+ small: 40,
119
+ medium: 80,
120
+ large: 120,
121
+ };
122
+
123
+ /**
124
+ * State transition mappings
125
+ */
126
+ export const STATE_TRANSITIONS: Record<MascotAnimationState, StateTransition[]> = {
127
+ idle: [
128
+ { from: 'idle', to: 'loading', condition: 'always' },
129
+ { from: 'idle', to: 'empty', condition: 'always' },
130
+ { from: 'idle', to: 'guide', condition: 'always' },
131
+ ],
132
+ loading: [
133
+ { from: 'loading', to: 'success', condition: 'on-success' },
134
+ { from: 'loading', to: 'error', condition: 'on-error' },
135
+ ],
136
+ success: [
137
+ { from: 'success', to: 'idle', condition: 'on-complete', delay: 100 },
138
+ ],
139
+ error: [
140
+ { from: 'error', to: 'idle', condition: 'on-complete', delay: 100 },
141
+ ],
142
+ empty: [
143
+ { from: 'empty', to: 'idle', condition: 'always' },
144
+ ],
145
+ guide: [
146
+ { from: 'guide', to: 'idle', condition: 'on-complete', delay: 200 },
147
+ ],
148
+ };
@@ -73,3 +73,12 @@ export interface MascotInteraction {
73
73
  handler: () => void | Promise<void>;
74
74
  animation?: string;
75
75
  }
76
+
77
+ export interface AnimationOptions {
78
+ speed?: number;
79
+ loop?: boolean;
80
+ autoplay?: boolean;
81
+ onStart?: () => void;
82
+ onFinish?: () => void;
83
+ onError?: (error: Error) => void;
84
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Animation State Value Object
3
+ * Encapsulates animation state logic and validation
4
+ */
5
+
6
+ import type {
7
+ MascotAnimationState,
8
+ MascotStateConfig,
9
+ StateTransition,
10
+ } from '../types/AnimationStateTypes';
11
+ import { DEFAULT_STATE_CONFIGS, STATE_TRANSITIONS } from '../types/AnimationStateTypes';
12
+
13
+ export class AnimationState {
14
+ private constructor(
15
+ public readonly value: MascotAnimationState,
16
+ private readonly _config: MascotStateConfig
17
+ ) {}
18
+
19
+ static create(state: MascotAnimationState, config?: Partial<MascotStateConfig>): AnimationState {
20
+ const defaultConfig = DEFAULT_STATE_CONFIGS[state];
21
+ const finalConfig = { ...defaultConfig, ...config, state };
22
+ return new AnimationState(state, finalConfig);
23
+ }
24
+
25
+ /**
26
+ * Check if state should loop
27
+ */
28
+ shouldLoop(): boolean {
29
+ return this._config.loop;
30
+ }
31
+
32
+ /**
33
+ * Get animation duration
34
+ */
35
+ getDuration(): number {
36
+ return this._config.duration || 3000;
37
+ }
38
+
39
+ /**
40
+ * Check if animation should auto-play
41
+ */
42
+ shouldAutoPlay(): boolean {
43
+ return this._config.autoPlay ?? true;
44
+ }
45
+
46
+ /**
47
+ * Get animation speed
48
+ */
49
+ getSpeed(): number {
50
+ return this._config.speed || 1;
51
+ }
52
+
53
+ /**
54
+ * Get next state after completion (for auto-transition)
55
+ */
56
+ getNextState(): MascotAnimationState | null {
57
+ return this._config.transitionTo || null;
58
+ }
59
+
60
+ /**
61
+ * Get available transitions from current state
62
+ */
63
+ getAvailableTransitions(): StateTransition[] {
64
+ return STATE_TRANSITIONS[this.value] || [];
65
+ }
66
+
67
+ /**
68
+ * Check if transition to target state is allowed
69
+ */
70
+ canTransitionTo(targetState: MascotAnimationState): boolean {
71
+ const transitions = this.getAvailableTransitions();
72
+ return transitions.some(t => t.to === targetState);
73
+ }
74
+
75
+ /**
76
+ * Get transition delay to target state
77
+ */
78
+ getTransitionDelay(targetState: MascotAnimationState): number {
79
+ const transitions = this.getAvailableTransitions();
80
+ const transition = transitions.find(t => t.to === targetState);
81
+ return transition?.delay || 0;
82
+ }
83
+
84
+ /**
85
+ * Get completion callback
86
+ */
87
+ getOnComplete(): (() => void) | undefined {
88
+ return this._config.onComplete;
89
+ }
90
+
91
+ /**
92
+ * Check if state is a success state
93
+ */
94
+ isSuccessState(): boolean {
95
+ return this.value === 'success';
96
+ }
97
+
98
+ /**
99
+ * Check if state is an error state
100
+ */
101
+ isErrorState(): boolean {
102
+ return this.value === 'error';
103
+ }
104
+
105
+ /**
106
+ * Check if state is a loading state
107
+ */
108
+ isLoadingState(): boolean {
109
+ return this.value === 'loading';
110
+ }
111
+
112
+ /**
113
+ * Check if state is an idle state
114
+ */
115
+ isIdleState(): boolean {
116
+ return this.value === 'idle';
117
+ }
118
+
119
+ equals(other: AnimationState): boolean {
120
+ return this.value === other.value;
121
+ }
122
+
123
+ toJSON(): MascotStateConfig {
124
+ return { ...this._config };
125
+ }
126
+ }
package/src/index.ts CHANGED
@@ -2,109 +2,18 @@
2
2
  * @umituz/react-native-mascot
3
3
  *
4
4
  * Interactive mascot system for React Native apps with DDD architecture
5
+ * Version: 1.0.6
5
6
  */
6
7
 
7
- import type { MascotMood, AnimationSpeed } from './domain/types/MascotTypes';
8
-
9
- // Domain - Entities
10
- export { Mascot } from './domain/entities/Mascot';
11
-
12
- // Domain - Value Objects
13
- export { Mood, EnergyLevel, FriendlinessLevel, PlayfulnessLevel } from './domain/value-objects';
14
-
15
- // Domain - Types
16
- export type {
17
- MascotType,
18
- MascotStyle,
19
- MascotAnimationType,
20
- MascotAppearance,
21
- MascotAccessory,
22
- MascotPersonality,
23
- MascotAnimation,
24
- MascotConfig,
25
- MascotState,
26
- MascotInteraction,
27
- MascotMood,
28
- AnimationSpeed,
29
- } from './domain/types/MascotTypes';
30
-
31
- // Domain - Interfaces
32
- export type {
33
- IAnimationController,
34
- AnimationEvent,
35
- AnimationOptions,
36
- } from './domain/interfaces/IAnimationController';
37
-
38
- export type {
39
- IAssetManager,
40
- AssetCache,
41
- } from './domain/interfaces/IAssetManager';
42
-
43
- export type {
44
- IMascotRepository,
45
- } from './domain/interfaces/IMascotRepository';
46
-
47
- // Application - Services
48
- export { MascotService } from './application/services/MascotService';
49
- export type { MascotTemplate } from './application/services/MascotService';
50
-
51
- // Application - Errors
52
- export {
53
- MascotError,
54
- MascotNotInitializedError,
55
- AnimationNotFoundError,
56
- InvalidEnergyLevelError,
57
- InvalidFriendlinessLevelError,
58
- InvalidPlayfulnessLevelError,
59
- InvalidMoodTransitionError,
60
- MascotNotFoundError,
61
- TemplateNotFoundError,
62
- } from './application/errors/MascotErrors';
63
-
64
- // Application - DTOs
65
- export type {
66
- MascotDTO,
67
- AnimationStateDTO,
68
- MascotInitOptionsDTO,
69
- AnimationPlaybackOptionsDTO,
70
- MascotUpdateOptionsDTO,
71
- } from './application/dto/MascotDTO';
72
-
73
- // Infrastructure - DI
74
- export { DIContainer } from './infrastructure/di/Container';
75
-
76
- // Infrastructure - Repositories
77
- export { MascotRepository } from './infrastructure/repositories/MascotRepository';
78
-
79
- // Infrastructure - Controllers
80
- export { AnimationController } from './infrastructure/controllers/AnimationController';
81
-
82
- // Infrastructure - Managers
83
- export { AssetManager } from './infrastructure/managers/AssetManager';
84
- export { MascotFactory, type MascotTemplate as FactoryMascotTemplate } from './infrastructure/managers/MascotFactory';
85
-
86
- // Presentation - Components
87
- export { MascotView } from './presentation/components/MascotView';
88
- export type { MascotViewProps } from './presentation/components/MascotView';
89
-
90
- // Presentation - Hooks
91
- export { useMascot } from './presentation/hooks/useMascot';
92
- export type {
93
- UseMascotOptions,
94
- UseMascotReturn,
95
- } from './presentation/hooks/useMascot';
96
-
97
- export { useMascotAnimation } from './presentation/hooks/useMascotAnimation';
98
- export type {
99
- UseMascotAnimationOptions,
100
- UseMascotAnimationReturn,
101
- } from './presentation/hooks/useMascotAnimation';
102
-
103
- // Presentation - Contexts
104
- export { MascotProvider, useMascotContext } from './presentation/contexts/MascotContext';
105
- export type { MascotProviderProps, MascotContextValue } from './presentation/contexts/MascotContext';
8
+ // Re-export all layers
9
+ export * from './core';
10
+ export * from './application';
11
+ export * from './infrastructure';
12
+ export * from './presentation';
106
13
 
107
14
  // Constants
15
+ import type { MascotMood, AnimationSpeed } from './domain/types/MascotTypes';
16
+
108
17
  export const MASCOT_TEMPLATES = [
109
18
  'friendly-bot',
110
19
  'cute-pet',
@@ -132,6 +41,7 @@ export const DEFAULT_ANIMATION_SPEEDS: AnimationSpeed[] = [
132
41
 
133
42
  // Convenience export - get service instance
134
43
  export const getMascotService = () => {
44
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
135
45
  const { DIContainer } = require('./infrastructure/di/Container');
136
46
  return DIContainer.getInstance().getMascotService();
137
47
  };
@@ -1,163 +1,67 @@
1
1
  /**
2
- * Animation Controller Implementation
3
- * Controls Lottie and SVG animations with unified API
2
+ * Animation Controller (Main - 60 lines)
3
+ * Unified animation control interface
4
4
  */
5
5
 
6
- import type {
7
- IAnimationController,
8
- AnimationOptions,
9
- AnimationEvent,
10
- } from '../../domain/interfaces/IAnimationController';
6
+ import type { IAnimationController, AnimationOptions, AnimationEvent } from '../../domain/interfaces/IAnimationController';
11
7
  import type { MascotAnimation } from '../../domain/types/MascotTypes';
8
+ import { AnimationPlayer } from './AnimationPlayer';
9
+ import { EventManager } from './EventManager';
12
10
 
13
11
  export class AnimationController implements IAnimationController {
14
- private _currentAnimation: MascotAnimation | null = null;
15
- private _isPlaying: boolean = false;
16
- private _isPaused: boolean = false;
17
- private _progress: number = 0;
18
- private _speed: number = 1;
19
- private _eventListeners: Map<AnimationEvent, Set<(data?: unknown) => void>>;
12
+ private _player: AnimationPlayer;
13
+ private _events: EventManager;
20
14
 
21
15
  constructor() {
22
- this._eventListeners = new Map();
23
- this._initializeEventListeners();
16
+ this._player = new AnimationPlayer();
17
+ this._events = new EventManager();
24
18
  }
25
19
 
26
- play(
27
- animation: MascotAnimation,
28
- options?: AnimationOptions
29
- ): Promise<void> {
30
- this._currentAnimation = animation;
31
- this._isPlaying = true;
32
- this._isPaused = false;
33
-
34
- if (options?.speed !== undefined) {
35
- this._speed = options.speed;
36
- }
37
-
38
- this._emit('start', { animation: animation.id });
39
-
40
- // Simulate animation completion
41
- // In real implementation, this would be controlled by LottieView
42
- const duration = animation.duration || 2000;
43
- const adjustedDuration = duration / this._speed;
44
-
45
- return new Promise((resolve) => {
46
- setTimeout(() => {
47
- if (this._isPlaying && !this._isPaused) {
48
- this._isPlaying = false;
49
- this._progress = 1;
50
- this._emit('finish', { animation: animation.id });
51
- options?.onFinish?.();
52
- }
53
- resolve();
54
- }, adjustedDuration);
55
-
56
- options?.onStart?.();
57
- });
20
+ play(animation: MascotAnimation, options?: AnimationOptions): Promise<void> {
21
+ return this._player.play(animation, options);
58
22
  }
59
23
 
60
24
  pause(): void {
61
- if (!this._isPlaying || this._isPaused) {
62
- return;
63
- }
64
-
65
- this._isPaused = true;
66
- this._emit('pause');
25
+ this._player.pause();
26
+ this._events.emit('pause');
67
27
  }
68
28
 
69
29
  resume(): void {
70
- if (!this._isPaused) {
71
- return;
72
- }
73
-
74
- this._isPaused = false;
75
- this._emit('resume');
30
+ this._player.resume();
31
+ this._events.emit('resume');
76
32
  }
77
33
 
78
34
  stop(): void {
79
- this._isPlaying = false;
80
- this._isPaused = false;
81
- this._progress = 0;
82
- this._currentAnimation = null;
35
+ this._player.stop();
83
36
  }
84
37
 
85
38
  getProgress(): number {
86
- return this._progress;
39
+ return this._player.progress;
87
40
  }
88
41
 
89
42
  setProgress(progress: number): void {
90
- if (progress < 0 || progress > 1) {
91
- throw new Error('Progress must be between 0 and 1');
92
- }
93
- this._progress = progress;
94
- this._emit('progress', { progress });
43
+ this._player.setProgress(progress);
44
+ this._events.emit('progress', { progress });
95
45
  }
96
46
 
97
47
  setSpeed(speed: number): void {
98
- if (speed <= 0) {
99
- throw new Error('Speed must be greater than 0');
100
- }
101
- this._speed = speed;
48
+ this._player.setSpeed(speed);
102
49
  }
103
50
 
104
51
  isPlaying(): boolean {
105
- return this._isPlaying && !this._isPaused;
52
+ return this._player.isPlaying;
106
53
  }
107
54
 
108
55
  on(event: AnimationEvent, callback: (data?: unknown) => void): () => void {
109
- if (!this._eventListeners.has(event)) {
110
- this._eventListeners.set(event, new Set());
111
- }
112
-
113
- this._eventListeners.get(event)!.add(callback);
114
-
115
- // Return unsubscribe function
116
- return () => {
117
- this.off(event, callback);
118
- };
56
+ return this._events.on(event, callback);
119
57
  }
120
58
 
121
59
  off(event: AnimationEvent, callback: (data?: unknown) => void): void {
122
- const listeners = this._eventListeners.get(event);
123
- if (listeners) {
124
- listeners.delete(callback);
125
- }
126
- }
127
-
128
- // Private Methods
129
- private _initializeEventListeners(): void {
130
- const events: AnimationEvent[] = ['start', 'finish', 'pause', 'resume', 'progress', 'error'];
131
- events.forEach((event) => {
132
- if (!this._eventListeners.has(event)) {
133
- this._eventListeners.set(event, new Set());
134
- }
135
- });
136
- }
137
-
138
- private _emit(event: AnimationEvent, data?: unknown): void {
139
- const listeners = this._eventListeners.get(event);
140
- if (listeners) {
141
- listeners.forEach((callback) => {
142
- try {
143
- callback(data);
144
- } catch (error) {
145
- console.error(`Error in ${event} event listener:`, error);
146
- }
147
- });
148
- }
149
- }
150
-
151
- // Getters
152
- get currentAnimation(): MascotAnimation | null {
153
- return this._currentAnimation;
154
- }
155
-
156
- get speed(): number {
157
- return this._speed;
60
+ this._events.off(event, callback);
158
61
  }
159
62
 
160
- get isPaused(): boolean {
161
- return this._isPaused;
63
+ destroy(): void {
64
+ this._player.destroy();
65
+ this._events.clear();
162
66
  }
163
67
  }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Animation Player (100 lines)
3
+ * Core playback logic for mascot animations
4
+ */
5
+
6
+ import type { MascotAnimation } from '../../domain/types/MascotTypes';
7
+ import type { AnimationOptions } from '../../domain/interfaces/IAnimationController';
8
+ import { AnimationTimer } from './AnimationTimer';
9
+
10
+ export class AnimationPlayer {
11
+ private _currentAnimation: MascotAnimation | null = null;
12
+ private _isPlaying: boolean = false;
13
+ private _isPaused: boolean = false;
14
+ private _progress: number = 0;
15
+ private _speed: number = 1;
16
+ private readonly _timer: AnimationTimer;
17
+
18
+ constructor() {
19
+ this._timer = new AnimationTimer();
20
+ }
21
+
22
+ get currentAnimation(): MascotAnimation | null {
23
+ return this._currentAnimation;
24
+ }
25
+
26
+ get isPlaying(): boolean {
27
+ return this._isPlaying && !this._isPaused;
28
+ }
29
+
30
+ get progress(): number {
31
+ return this._progress;
32
+ }
33
+
34
+ get speed(): number {
35
+ return this._speed;
36
+ }
37
+
38
+ play(animation: MascotAnimation, options?: AnimationOptions): Promise<void> {
39
+ // Stop existing animation
40
+ this.stop();
41
+
42
+ this._currentAnimation = animation;
43
+ this._isPlaying = true;
44
+ this._isPaused = false;
45
+
46
+ if (options?.speed !== undefined) {
47
+ this._speed = options.speed;
48
+ }
49
+
50
+ const duration = animation.duration || 2000;
51
+ const adjustedDuration = duration / this._speed;
52
+
53
+ // Start timer
54
+ this._timer.start(adjustedDuration, () => {
55
+ this._isPlaying = false;
56
+ this._progress = 1;
57
+ options?.onFinish?.();
58
+ });
59
+
60
+ options?.onStart?.();
61
+ return Promise.resolve();
62
+ }
63
+
64
+ pause(): void {
65
+ if (!this._isPlaying || this._isPaused) return;
66
+
67
+ this._isPaused = true;
68
+ this._timer.pause();
69
+ }
70
+
71
+ resume(): void {
72
+ if (!this._isPaused) return;
73
+
74
+ this._isPaused = false;
75
+ this._timer.resume();
76
+ }
77
+
78
+ stop(): void {
79
+ this._isPlaying = false;
80
+ this._isPaused = false;
81
+ this._progress = 0;
82
+ this._currentAnimation = null;
83
+ this._timer.stop();
84
+ }
85
+
86
+ setProgress(progress: number): void {
87
+ if (progress < 0 || progress > 1) {
88
+ throw new Error('Progress must be between 0 and 1');
89
+ }
90
+ this._progress = progress;
91
+ }
92
+
93
+ setSpeed(speed: number): void {
94
+ if (speed <= 0) {
95
+ throw new Error('Speed must be greater than 0');
96
+ }
97
+ this._speed = speed;
98
+ }
99
+
100
+ destroy(): void {
101
+ this.stop();
102
+ this._timer.destroy();
103
+ }
104
+ }