@umituz/react-native-mascot 1.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.
- package/LICENSE +21 -0
- package/README.md +370 -0
- package/package.json +89 -0
- package/skills/SKILL.md +188 -0
- package/src/assets/index.ts +104 -0
- package/src/domain/entities/Mascot.ts +216 -0
- package/src/domain/interfaces/IAnimationController.ts +78 -0
- package/src/domain/interfaces/IAssetManager.ts +51 -0
- package/src/domain/interfaces/IMascotRepository.ts +39 -0
- package/src/domain/types/MascotTypes.ts +75 -0
- package/src/index.ts +99 -0
- package/src/infrastructure/assets/lottie/dance.json +61 -0
- package/src/infrastructure/assets/lottie/error.json +48 -0
- package/src/infrastructure/assets/lottie/idle.json +49 -0
- package/src/infrastructure/assets/lottie/jump.json +48 -0
- package/src/infrastructure/assets/lottie/success.json +46 -0
- package/src/infrastructure/assets/lottie/wave.json +46 -0
- package/src/infrastructure/assets/svg/cartoon-bot.svg +20 -0
- package/src/infrastructure/assets/svg/minimal-cat.svg +19 -0
- package/src/infrastructure/controllers/AnimationController.ts +163 -0
- package/src/infrastructure/managers/AssetManager.ts +159 -0
- package/src/infrastructure/managers/MascotFactory.ts +239 -0
- package/src/infrastructure/repositories/MascotRepository.ts +93 -0
- package/src/presentation/components/MascotView.tsx +296 -0
- package/src/presentation/contexts/MascotContext.tsx +141 -0
- package/src/presentation/hooks/useMascot.ts +224 -0
- package/src/presentation/hooks/useMascotAnimation.ts +168 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Mascot Assets
|
|
3
|
+
* Pre-configured mascots and animations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
7
|
+
import type { MascotConfig, MascotAnimationType } from '../domain/types/MascotTypes';
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
|
+
const idleAnim = require('./lottie/idle.json');
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
12
|
+
const waveAnim = require('./lottie/wave.json');
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
14
|
+
const jumpAnim = require('./lottie/jump.json');
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
16
|
+
const successAnim = require('./lottie/success.json');
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
18
|
+
const errorAnim = require('./lottie/error.json');
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20
|
+
const danceAnim = require('./lottie/dance.json');
|
|
21
|
+
|
|
22
|
+
export const BUILT_IN_MASCOTS: Record<string, MascotConfig> = {
|
|
23
|
+
'happy-robot': {
|
|
24
|
+
id: 'happy-robot',
|
|
25
|
+
name: 'Happy Robot',
|
|
26
|
+
type: 'lottie',
|
|
27
|
+
personality: {
|
|
28
|
+
mood: 'happy',
|
|
29
|
+
energy: 0.8,
|
|
30
|
+
friendliness: 0.9,
|
|
31
|
+
playfulness: 0.7,
|
|
32
|
+
},
|
|
33
|
+
appearance: {
|
|
34
|
+
baseColor: '#4A90E2',
|
|
35
|
+
accentColor: '#50E3C2',
|
|
36
|
+
accessories: [],
|
|
37
|
+
style: 'cartoon',
|
|
38
|
+
scale: 1,
|
|
39
|
+
},
|
|
40
|
+
animations: [
|
|
41
|
+
{
|
|
42
|
+
id: 'idle',
|
|
43
|
+
name: 'Idle',
|
|
44
|
+
type: 'idle' as MascotAnimationType,
|
|
45
|
+
source: idleAnim,
|
|
46
|
+
loop: true,
|
|
47
|
+
autoplay: true,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'wave',
|
|
51
|
+
name: 'Wave',
|
|
52
|
+
type: 'action' as MascotAnimationType,
|
|
53
|
+
source: waveAnim,
|
|
54
|
+
loop: false,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'jump',
|
|
58
|
+
name: 'Jump',
|
|
59
|
+
type: 'action' as MascotAnimationType,
|
|
60
|
+
source: jumpAnim,
|
|
61
|
+
loop: false,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'success',
|
|
65
|
+
name: 'Success',
|
|
66
|
+
type: 'reaction' as MascotAnimationType,
|
|
67
|
+
source: successAnim,
|
|
68
|
+
loop: false,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'error',
|
|
72
|
+
name: 'Error',
|
|
73
|
+
type: 'reaction' as MascotAnimationType,
|
|
74
|
+
source: errorAnim,
|
|
75
|
+
loop: false,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'dance',
|
|
79
|
+
name: 'Dance',
|
|
80
|
+
type: 'action' as MascotAnimationType,
|
|
81
|
+
source: danceAnim,
|
|
82
|
+
loop: true,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
interactive: true,
|
|
86
|
+
touchEnabled: true,
|
|
87
|
+
soundEnabled: false,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Helper function to get built-in mascot
|
|
92
|
+
export function getBuiltInMascot(id: string): MascotConfig | undefined {
|
|
93
|
+
return BUILT_IN_MASCOTS[id];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Helper function to get all built-in mascot IDs
|
|
97
|
+
export function getBuiltInMascotIds(): string[] {
|
|
98
|
+
return Object.keys(BUILT_IN_MASCOTS);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Helper function to check if mascot is built-in
|
|
102
|
+
export function isBuiltInMascot(id: string): boolean {
|
|
103
|
+
return id in BUILT_IN_MASCOTS;
|
|
104
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mascot Entity
|
|
3
|
+
* Core mascot representation following DDD principles
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
MascotConfig,
|
|
8
|
+
MascotPersonality,
|
|
9
|
+
MascotAppearance,
|
|
10
|
+
MascotAnimation,
|
|
11
|
+
MascotState,
|
|
12
|
+
MascotType,
|
|
13
|
+
MascotMood,
|
|
14
|
+
MascotAccessory,
|
|
15
|
+
} from '../types/MascotTypes';
|
|
16
|
+
|
|
17
|
+
export class Mascot {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly type: MascotType;
|
|
21
|
+
private _personality: MascotPersonality;
|
|
22
|
+
private _appearance: MascotAppearance;
|
|
23
|
+
private readonly _animations: Map<string, MascotAnimation>;
|
|
24
|
+
private readonly _config: MascotConfig;
|
|
25
|
+
private _state: MascotState;
|
|
26
|
+
private _interactions: Map<string, () => void | Promise<void>>;
|
|
27
|
+
|
|
28
|
+
constructor(config: MascotConfig) {
|
|
29
|
+
this.id = config.id;
|
|
30
|
+
this.name = config.name;
|
|
31
|
+
this.type = config.type;
|
|
32
|
+
this._personality = config.personality;
|
|
33
|
+
this._appearance = config.appearance;
|
|
34
|
+
this._animations = new Map(
|
|
35
|
+
config.animations.map((anim) => [anim.id, anim])
|
|
36
|
+
);
|
|
37
|
+
this._config = config;
|
|
38
|
+
this._state = {
|
|
39
|
+
currentMood: config.personality.mood,
|
|
40
|
+
currentAnimation: null,
|
|
41
|
+
isAnimating: false,
|
|
42
|
+
isVisible: true,
|
|
43
|
+
};
|
|
44
|
+
this._interactions = new Map();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Getters
|
|
48
|
+
get personality(): MascotPersonality {
|
|
49
|
+
return { ...this._personality };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get appearance(): MascotAppearance {
|
|
53
|
+
return { ...this._appearance };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get state(): MascotState {
|
|
57
|
+
return { ...this._state };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get config(): MascotConfig {
|
|
61
|
+
return { ...this._config };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get animations(): MascotAnimation[] {
|
|
65
|
+
return Array.from(this._animations.values());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get interactive(): boolean {
|
|
69
|
+
return this._config.interactive ?? false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get touchEnabled(): boolean {
|
|
73
|
+
return this._config.touchEnabled ?? true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get soundEnabled(): boolean {
|
|
77
|
+
return this._config.soundEnabled ?? false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Personality Management
|
|
81
|
+
setMood(mood: MascotMood): void {
|
|
82
|
+
this._personality.mood = mood;
|
|
83
|
+
this._state.currentMood = mood;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setEnergy(energy: number): void {
|
|
87
|
+
if (energy < 0 || energy > 1) {
|
|
88
|
+
throw new Error('Energy must be between 0 and 1');
|
|
89
|
+
}
|
|
90
|
+
this._personality.energy = energy;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setFriendliness(friendliness: number): void {
|
|
94
|
+
if (friendliness < 0 || friendliness > 1) {
|
|
95
|
+
throw new Error('Friendliness must be between 0 and 1');
|
|
96
|
+
}
|
|
97
|
+
this._personality.friendliness = friendliness;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setPlayfulness(playfulness: number): void {
|
|
101
|
+
if (playfulness < 0 || playfulness > 1) {
|
|
102
|
+
throw new Error('Playfulness must be between 0 and 1');
|
|
103
|
+
}
|
|
104
|
+
this._personality.playfulness = playfulness;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Appearance Management
|
|
108
|
+
updateAppearance(appearance: Partial<MascotAppearance>): void {
|
|
109
|
+
this._appearance = {
|
|
110
|
+
...this._appearance,
|
|
111
|
+
...appearance,
|
|
112
|
+
accessories: appearance.accessories ?? this._appearance.accessories,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setBaseColor(color: string): void {
|
|
117
|
+
this._appearance.baseColor = color;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
setAccentColor(color: string): void {
|
|
121
|
+
this._appearance.accentColor = color;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
addAccessory(accessory: {
|
|
125
|
+
id: string;
|
|
126
|
+
type: string;
|
|
127
|
+
color?: string;
|
|
128
|
+
position?: { x: number; y: number };
|
|
129
|
+
}): void {
|
|
130
|
+
const newAccessory: MascotAccessory = {
|
|
131
|
+
id: accessory.id,
|
|
132
|
+
type: accessory.type as MascotAccessory['type'],
|
|
133
|
+
color: accessory.color,
|
|
134
|
+
position: accessory.position,
|
|
135
|
+
visible: true,
|
|
136
|
+
};
|
|
137
|
+
this._appearance.accessories = [
|
|
138
|
+
...this._appearance.accessories.filter((a) => a.id !== accessory.id),
|
|
139
|
+
newAccessory,
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
removeAccessory(accessoryId: string): void {
|
|
144
|
+
this._appearance.accessories = this._appearance.accessories.filter(
|
|
145
|
+
(a) => a.id !== accessoryId
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Animation Management
|
|
150
|
+
getAnimation(animationId: string): MascotAnimation | undefined {
|
|
151
|
+
return this._animations.get(animationId);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
getAnimationsByType(type: string): MascotAnimation[] {
|
|
155
|
+
return this.animations.filter((anim) => anim.type === type);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// State Management
|
|
159
|
+
startAnimation(animationId: string): void {
|
|
160
|
+
const animation = this._animations.get(animationId);
|
|
161
|
+
if (!animation) {
|
|
162
|
+
throw new Error(`Animation ${animationId} not found`);
|
|
163
|
+
}
|
|
164
|
+
this._state.currentAnimation = animationId;
|
|
165
|
+
this._state.isAnimating = true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
stopAnimation(): void {
|
|
169
|
+
this._state.isAnimating = false;
|
|
170
|
+
this._state.currentAnimation = null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
setVisible(visible: boolean): void {
|
|
174
|
+
this._state.isVisible = visible;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
setPosition(position: { x: number; y: number }): void {
|
|
178
|
+
this._state.position = position;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Interaction Management
|
|
182
|
+
registerInteraction(
|
|
183
|
+
id: string,
|
|
184
|
+
handler: () => void | Promise<void>
|
|
185
|
+
): void {
|
|
186
|
+
this._interactions.set(id, handler);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
unregisterInteraction(id: string): void {
|
|
190
|
+
this._interactions.delete(id);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async triggerInteraction(id: string): Promise<void> {
|
|
194
|
+
const handler = this._interactions.get(id);
|
|
195
|
+
if (handler) {
|
|
196
|
+
await handler();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Utility Methods
|
|
201
|
+
clone(): Mascot {
|
|
202
|
+
return new Mascot(this._config);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
toJSON(): object {
|
|
206
|
+
return {
|
|
207
|
+
id: this.id,
|
|
208
|
+
name: this.name,
|
|
209
|
+
type: this.type,
|
|
210
|
+
personality: this._personality,
|
|
211
|
+
appearance: this._appearance,
|
|
212
|
+
state: this._state,
|
|
213
|
+
config: this._config,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation Controller Interface
|
|
3
|
+
* Defines contract for animation playback control
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { MascotAnimation } from '../types/MascotTypes';
|
|
7
|
+
|
|
8
|
+
export interface IAnimationController {
|
|
9
|
+
/**
|
|
10
|
+
* Play an animation
|
|
11
|
+
*/
|
|
12
|
+
play(animation: MascotAnimation, options?: AnimationOptions): Promise<void>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Pause current animation
|
|
16
|
+
*/
|
|
17
|
+
pause(): void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Resume paused animation
|
|
21
|
+
*/
|
|
22
|
+
resume(): void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Stop current animation
|
|
26
|
+
*/
|
|
27
|
+
stop(): void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get current animation progress (0-1)
|
|
31
|
+
*/
|
|
32
|
+
getProgress(): number;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Set animation progress (0-1)
|
|
36
|
+
*/
|
|
37
|
+
setProgress(progress: number): void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Set animation speed multiplier
|
|
41
|
+
*/
|
|
42
|
+
setSpeed(speed: number): void;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if currently playing
|
|
46
|
+
*/
|
|
47
|
+
isPlaying(): boolean;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Add event listener
|
|
51
|
+
*/
|
|
52
|
+
on(
|
|
53
|
+
event: AnimationEvent,
|
|
54
|
+
callback: (data?: unknown) => void
|
|
55
|
+
): () => void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Remove event listener
|
|
59
|
+
*/
|
|
60
|
+
off(event: AnimationEvent, callback: (data?: unknown) => void): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type AnimationEvent =
|
|
64
|
+
| 'start'
|
|
65
|
+
| 'finish'
|
|
66
|
+
| 'pause'
|
|
67
|
+
| 'resume'
|
|
68
|
+
| 'progress'
|
|
69
|
+
| 'error';
|
|
70
|
+
|
|
71
|
+
export interface AnimationOptions {
|
|
72
|
+
speed?: number;
|
|
73
|
+
loop?: boolean;
|
|
74
|
+
autoplay?: boolean;
|
|
75
|
+
onStart?: () => void;
|
|
76
|
+
onFinish?: () => void;
|
|
77
|
+
onError?: (error: Error) => void;
|
|
78
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset Manager Interface
|
|
3
|
+
* Defines contract for loading and managing mascot assets
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { MascotAnimation } from '../types/MascotTypes';
|
|
7
|
+
|
|
8
|
+
export interface IAssetManager {
|
|
9
|
+
/**
|
|
10
|
+
* Load a Lottie animation
|
|
11
|
+
*/
|
|
12
|
+
loadLottieAnimation(source: string | object): Promise<MascotAnimation>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Load an SVG asset
|
|
16
|
+
*/
|
|
17
|
+
loadSVGAsset(source: string): Promise<string>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Preload multiple animations
|
|
21
|
+
*/
|
|
22
|
+
preloadAnimations(sources: Array<string | object>): Promise<void>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Clear cached assets
|
|
26
|
+
*/
|
|
27
|
+
clearCache(): void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get asset URL or path
|
|
31
|
+
*/
|
|
32
|
+
getAssetUrl(assetId: string): string | null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if asset is loaded
|
|
36
|
+
*/
|
|
37
|
+
isAssetLoaded(assetId: string): boolean;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get all loaded assets
|
|
41
|
+
*/
|
|
42
|
+
getLoadedAssets(): string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AssetCache {
|
|
46
|
+
[key: string]: {
|
|
47
|
+
data: unknown;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
size: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mascot Repository Interface
|
|
3
|
+
* Defines contract for mascot data persistence and retrieval
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Mascot } from '../entities/Mascot';
|
|
7
|
+
import type { MascotConfig } from '../types/MascotTypes';
|
|
8
|
+
|
|
9
|
+
export interface IMascotRepository {
|
|
10
|
+
/**
|
|
11
|
+
* Save a mascot configuration
|
|
12
|
+
*/
|
|
13
|
+
save(config: MascotConfig): Promise<void>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Load a mascot by ID
|
|
17
|
+
*/
|
|
18
|
+
load(id: string): Promise<Mascot | null>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load all mascots
|
|
22
|
+
*/
|
|
23
|
+
loadAll(): Promise<Mascot[]>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Delete a mascot
|
|
27
|
+
*/
|
|
28
|
+
delete(id: string): Promise<void>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Update mascot configuration
|
|
32
|
+
*/
|
|
33
|
+
update(id: string, config: Partial<MascotConfig>): Promise<void>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if mascot exists
|
|
37
|
+
*/
|
|
38
|
+
exists(id: string): Promise<boolean>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mascot Types
|
|
3
|
+
* Core type definitions for the mascot system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type MascotType = 'lottie' | 'svg' | 'custom';
|
|
7
|
+
|
|
8
|
+
export type MascotStyle = 'minimal' | 'cartoon' | 'realistic' | 'pixel';
|
|
9
|
+
|
|
10
|
+
export type MascotMood = 'happy' | 'sad' | 'excited' | 'thinking' | 'angry' | 'neutral' | 'surprised';
|
|
11
|
+
|
|
12
|
+
export type MascotAnimationType = 'idle' | 'action' | 'reaction' | 'transition';
|
|
13
|
+
|
|
14
|
+
export type AnimationSpeed = 'very-slow' | 'slow' | 'normal' | 'fast' | 'very-fast';
|
|
15
|
+
|
|
16
|
+
export interface MascotAppearance {
|
|
17
|
+
baseColor: string;
|
|
18
|
+
accentColor: string;
|
|
19
|
+
secondaryColor?: string;
|
|
20
|
+
accessories: MascotAccessory[];
|
|
21
|
+
style: MascotStyle;
|
|
22
|
+
scale?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface MascotAccessory {
|
|
26
|
+
id: string;
|
|
27
|
+
type: 'glasses' | 'hat' | 'bow' | 'crown' | 'headphones' | 'mask' | 'custom';
|
|
28
|
+
color?: string;
|
|
29
|
+
position?: { x: number; y: number };
|
|
30
|
+
visible?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface MascotPersonality {
|
|
34
|
+
mood: MascotMood;
|
|
35
|
+
energy: number; // 0-1
|
|
36
|
+
friendliness: number; // 0-1
|
|
37
|
+
playfulness: number; // 0-1
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface MascotAnimation {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
type: MascotAnimationType;
|
|
44
|
+
source: string | object;
|
|
45
|
+
loop: boolean;
|
|
46
|
+
duration?: number;
|
|
47
|
+
speed?: number;
|
|
48
|
+
autoplay?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface MascotConfig {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
type: MascotType;
|
|
55
|
+
personality: MascotPersonality;
|
|
56
|
+
appearance: MascotAppearance;
|
|
57
|
+
animations: MascotAnimation[];
|
|
58
|
+
interactive?: boolean;
|
|
59
|
+
touchEnabled?: boolean;
|
|
60
|
+
soundEnabled?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface MascotState {
|
|
64
|
+
currentMood: MascotMood;
|
|
65
|
+
currentAnimation: string | null;
|
|
66
|
+
isAnimating: boolean;
|
|
67
|
+
isVisible: boolean;
|
|
68
|
+
position?: { x: number; y: number };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface MascotInteraction {
|
|
72
|
+
type: 'tap' | 'longPress' | 'drag' | 'pinch' | 'custom';
|
|
73
|
+
handler: () => void | Promise<void>;
|
|
74
|
+
animation?: string;
|
|
75
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @umituz/react-native-mascot
|
|
3
|
+
*
|
|
4
|
+
* Interactive mascot system for React Native apps
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { MascotMood, AnimationSpeed } from './domain/types/MascotTypes';
|
|
8
|
+
|
|
9
|
+
// Domain - Entities
|
|
10
|
+
export { Mascot } from './domain/entities/Mascot';
|
|
11
|
+
|
|
12
|
+
// Domain - Types
|
|
13
|
+
export type {
|
|
14
|
+
MascotType,
|
|
15
|
+
MascotStyle,
|
|
16
|
+
MascotAnimationType,
|
|
17
|
+
MascotAppearance,
|
|
18
|
+
MascotAccessory,
|
|
19
|
+
MascotPersonality,
|
|
20
|
+
MascotAnimation,
|
|
21
|
+
MascotConfig,
|
|
22
|
+
MascotState,
|
|
23
|
+
MascotInteraction,
|
|
24
|
+
MascotMood,
|
|
25
|
+
AnimationSpeed,
|
|
26
|
+
} from './domain/types/MascotTypes';
|
|
27
|
+
|
|
28
|
+
// Domain - Interfaces
|
|
29
|
+
export type {
|
|
30
|
+
IAnimationController,
|
|
31
|
+
AnimationEvent,
|
|
32
|
+
AnimationOptions,
|
|
33
|
+
} from './domain/interfaces/IAnimationController';
|
|
34
|
+
|
|
35
|
+
export type {
|
|
36
|
+
IAssetManager,
|
|
37
|
+
AssetCache,
|
|
38
|
+
} from './domain/interfaces/IAssetManager';
|
|
39
|
+
|
|
40
|
+
export type {
|
|
41
|
+
IMascotRepository,
|
|
42
|
+
} from './domain/interfaces/IMascotRepository';
|
|
43
|
+
|
|
44
|
+
// Infrastructure - Repositories
|
|
45
|
+
export { MascotRepository } from './infrastructure/repositories/MascotRepository';
|
|
46
|
+
|
|
47
|
+
// Infrastructure - Controllers
|
|
48
|
+
export { AnimationController } from './infrastructure/controllers/AnimationController';
|
|
49
|
+
|
|
50
|
+
// Infrastructure - Managers
|
|
51
|
+
export { AssetManager } from './infrastructure/managers/AssetManager';
|
|
52
|
+
export { MascotFactory, type MascotTemplate } from './infrastructure/managers/MascotFactory';
|
|
53
|
+
|
|
54
|
+
// Presentation - Components
|
|
55
|
+
export { MascotView } from './presentation/components/MascotView';
|
|
56
|
+
export type { MascotViewProps } from './presentation/components/MascotView';
|
|
57
|
+
|
|
58
|
+
// Presentation - Hooks
|
|
59
|
+
export { useMascot } from './presentation/hooks/useMascot';
|
|
60
|
+
export type {
|
|
61
|
+
UseMascotOptions,
|
|
62
|
+
UseMascotReturn,
|
|
63
|
+
} from './presentation/hooks/useMascot';
|
|
64
|
+
|
|
65
|
+
export { useMascotAnimation } from './presentation/hooks/useMascotAnimation';
|
|
66
|
+
export type {
|
|
67
|
+
UseMascotAnimationOptions,
|
|
68
|
+
UseMascotAnimationReturn,
|
|
69
|
+
} from './presentation/hooks/useMascotAnimation';
|
|
70
|
+
|
|
71
|
+
// Presentation - Contexts
|
|
72
|
+
export { MascotProvider, useMascotContext } from './presentation/contexts/MascotContext';
|
|
73
|
+
export type { MascotProviderProps, MascotContextValue } from './presentation/contexts/MascotContext';
|
|
74
|
+
|
|
75
|
+
// Constants
|
|
76
|
+
export const MASCOT_TEMPLATES = [
|
|
77
|
+
'friendly-bot',
|
|
78
|
+
'cute-pet',
|
|
79
|
+
'wise-owl',
|
|
80
|
+
'pixel-hero',
|
|
81
|
+
] as const;
|
|
82
|
+
|
|
83
|
+
export const DEFAULT_MASCOT_MOODS: MascotMood[] = [
|
|
84
|
+
'happy',
|
|
85
|
+
'sad',
|
|
86
|
+
'excited',
|
|
87
|
+
'thinking',
|
|
88
|
+
'angry',
|
|
89
|
+
'neutral',
|
|
90
|
+
'surprised',
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
export const DEFAULT_ANIMATION_SPEEDS: AnimationSpeed[] = [
|
|
94
|
+
'very-slow',
|
|
95
|
+
'slow',
|
|
96
|
+
'normal',
|
|
97
|
+
'fast',
|
|
98
|
+
'very-fast',
|
|
99
|
+
];
|