@mentra/sdk 2.1.2 → 2.1.3
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/app/session/events.d.ts +3 -2
- package/dist/app/session/events.d.ts.map +1 -1
- package/dist/app/session/events.js +3 -0
- package/dist/app/session/index.d.ts +8 -1
- package/dist/app/session/index.d.ts.map +1 -1
- package/dist/app/session/index.js +9 -0
- package/dist/app/session/layouts.d.ts +63 -3
- package/dist/app/session/layouts.d.ts.map +1 -1
- package/dist/app/session/layouts.js +101 -7
- package/dist/app/session/modules/camera-managed-extension.d.ts +3 -1
- package/dist/app/session/modules/camera-managed-extension.d.ts.map +1 -1
- package/dist/app/session/modules/camera-managed-extension.js +26 -18
- package/dist/examples/managed-rtmp-streaming-example.js +3 -0
- package/dist/examples/managed-rtmp-streaming-with-restream-example.d.ts +11 -0
- package/dist/examples/managed-rtmp-streaming-with-restream-example.d.ts.map +1 -0
- package/dist/examples/managed-rtmp-streaming-with-restream-example.js +124 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/types/enums.d.ts +3 -1
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/enums.js +2 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/layouts.d.ts +16 -1
- package/dist/types/layouts.d.ts.map +1 -1
- package/dist/types/message-types.d.ts +2 -2
- package/dist/types/message-types.d.ts.map +1 -1
- package/dist/types/message-types.js +3 -3
- package/dist/types/messages/app-to-cloud.d.ts +11 -0
- package/dist/types/messages/app-to-cloud.d.ts.map +1 -1
- package/dist/types/messages/cloud-to-app.d.ts +19 -0
- package/dist/types/messages/cloud-to-app.d.ts.map +1 -1
- package/dist/types/messages/glasses-to-cloud.d.ts +8 -4
- package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -1
- package/dist/types/messages/glasses-to-cloud.js +3 -3
- package/dist/types/models.d.ts +1 -0
- package/dist/types/models.d.ts.map +1 -1
- package/dist/types/models.js +1 -0
- package/dist/types/streams.d.ts +1 -1
- package/dist/types/streams.d.ts.map +1 -1
- package/dist/types/streams.js +2 -2
- package/dist/utils/animation-utils.d.ts +206 -0
- package/dist/utils/animation-utils.d.ts.map +1 -0
- package/dist/utils/animation-utils.js +339 -0
- package/dist/utils/bitmap-utils.d.ts +147 -0
- package/dist/utils/bitmap-utils.d.ts.map +1 -0
- package/dist/utils/bitmap-utils.js +338 -0
- package/package.json +1 -1
@@ -0,0 +1,206 @@
|
|
1
|
+
/**
|
2
|
+
* 🎬 Animation Utilities Module
|
3
|
+
*
|
4
|
+
* Provides helper functions for creating and managing bitmap animations in MentraOS applications.
|
5
|
+
* Includes timing utilities, animation factories, and performance optimization helpers.
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
* ```typescript
|
9
|
+
* import { AnimationUtils } from '@mentra/sdk';
|
10
|
+
*
|
11
|
+
* // Create animation from files
|
12
|
+
* const animation = await AnimationUtils.createBitmapAnimation(
|
13
|
+
* session, './frames', 10, 1750, true
|
14
|
+
* );
|
15
|
+
*
|
16
|
+
* // Simple delay utility
|
17
|
+
* await AnimationUtils.delay(2000);
|
18
|
+
*
|
19
|
+
* // Stop animation
|
20
|
+
* animation.stop();
|
21
|
+
* ```
|
22
|
+
*/
|
23
|
+
import { AppSession } from '../app/session';
|
24
|
+
import { LoadFramesOptions } from './bitmap-utils';
|
25
|
+
/**
|
26
|
+
* Configuration options for bitmap animations
|
27
|
+
*/
|
28
|
+
export interface AnimationConfig {
|
29
|
+
/** Time between frames in milliseconds (default: 1750ms - optimized for MentraOS) */
|
30
|
+
intervalMs?: number;
|
31
|
+
/** Whether to loop the animation continuously (default: false) */
|
32
|
+
repeat?: boolean;
|
33
|
+
/** Validate frames before starting animation (default: true) */
|
34
|
+
validateFrames?: boolean;
|
35
|
+
/** Options for loading frames from files */
|
36
|
+
loadOptions?: LoadFramesOptions;
|
37
|
+
/** Callback fired when animation starts */
|
38
|
+
onStart?: () => void;
|
39
|
+
/** Callback fired when animation stops/completes */
|
40
|
+
onStop?: () => void;
|
41
|
+
/** Callback fired on each frame display */
|
42
|
+
onFrame?: (frameIndex: number, totalFrames: number) => void;
|
43
|
+
/** Callback fired if animation encounters an error */
|
44
|
+
onError?: (error: string) => void;
|
45
|
+
}
|
46
|
+
/**
|
47
|
+
* Animation controller interface
|
48
|
+
*/
|
49
|
+
export interface AnimationController {
|
50
|
+
/** Stop the animation */
|
51
|
+
stop: () => void;
|
52
|
+
/** Check if animation is currently running */
|
53
|
+
isRunning: () => boolean;
|
54
|
+
/** Get current frame index */
|
55
|
+
getCurrentFrame: () => number;
|
56
|
+
/** Get total frame count */
|
57
|
+
getTotalFrames: () => number;
|
58
|
+
}
|
59
|
+
/**
|
60
|
+
* Performance timing information
|
61
|
+
*/
|
62
|
+
export interface TimingInfo {
|
63
|
+
/** Target interval between frames */
|
64
|
+
targetInterval: number;
|
65
|
+
/** Actual measured interval between frames */
|
66
|
+
actualInterval: number;
|
67
|
+
/** Timing drift (difference between target and actual) */
|
68
|
+
drift: number;
|
69
|
+
/** Frame rate (frames per second) */
|
70
|
+
fps: number;
|
71
|
+
}
|
72
|
+
/**
|
73
|
+
* Utility class for creating and managing animations in MentraOS applications
|
74
|
+
*/
|
75
|
+
export declare class AnimationUtils {
|
76
|
+
/**
|
77
|
+
* Simple async delay helper
|
78
|
+
*
|
79
|
+
* @param ms - Milliseconds to delay
|
80
|
+
* @returns Promise that resolves after the specified delay
|
81
|
+
*
|
82
|
+
* @example
|
83
|
+
* ```typescript
|
84
|
+
* console.log('Starting...');
|
85
|
+
* await AnimationUtils.delay(2000);
|
86
|
+
* console.log('2 seconds later!');
|
87
|
+
* ```
|
88
|
+
*/
|
89
|
+
static delay(ms: number): Promise<void>;
|
90
|
+
/**
|
91
|
+
* Create bitmap animation from files with advanced configuration
|
92
|
+
*
|
93
|
+
* @param session - MentraOS app session
|
94
|
+
* @param basePath - Directory containing animation frames
|
95
|
+
* @param frameCount - Number of frames to load
|
96
|
+
* @param config - Animation configuration options
|
97
|
+
* @returns Promise resolving to animation controller
|
98
|
+
*
|
99
|
+
* @example
|
100
|
+
* ```typescript
|
101
|
+
* // Simple animation
|
102
|
+
* const animation = await AnimationUtils.createBitmapAnimation(
|
103
|
+
* session, './animations', 10
|
104
|
+
* );
|
105
|
+
*
|
106
|
+
* // Advanced configuration
|
107
|
+
* const advancedAnimation = await AnimationUtils.createBitmapAnimation(
|
108
|
+
* session, './sprites', 8, {
|
109
|
+
* intervalMs: 1000,
|
110
|
+
* repeat: true,
|
111
|
+
* loadOptions: { filePattern: 'sprite_{i}.bmp', startFrame: 0 },
|
112
|
+
* onFrame: (frame, total) => console.log(`Frame ${frame}/${total}`),
|
113
|
+
* onError: (error) => console.error('Animation error:', error)
|
114
|
+
* }
|
115
|
+
* );
|
116
|
+
* ```
|
117
|
+
*/
|
118
|
+
static createBitmapAnimation(session: AppSession, basePath: string, frameCount: number, config?: AnimationConfig): Promise<AnimationController>;
|
119
|
+
/**
|
120
|
+
* Create bitmap animation from pre-loaded frame data
|
121
|
+
*
|
122
|
+
* @param session - MentraOS app session
|
123
|
+
* @param frames - Array of hex-encoded bitmap data
|
124
|
+
* @param config - Animation configuration options
|
125
|
+
* @returns Animation controller
|
126
|
+
*
|
127
|
+
* @example
|
128
|
+
* ```typescript
|
129
|
+
* const frames = ['424d461a...', '424d461b...', '424d461c...'];
|
130
|
+
* const animation = AnimationUtils.createBitmapAnimationFromFrames(
|
131
|
+
* session, frames, { intervalMs: 1500, repeat: true }
|
132
|
+
* );
|
133
|
+
* ```
|
134
|
+
*/
|
135
|
+
static createBitmapAnimationFromFrames(session: AppSession, frames: string[], config?: Omit<AnimationConfig, 'loadOptions' | 'validateFrames'>): AnimationController;
|
136
|
+
/**
|
137
|
+
* Create a sequence of bitmap displays with custom timing
|
138
|
+
*
|
139
|
+
* @param session - MentraOS app session
|
140
|
+
* @param sequence - Array of frame data with individual timing
|
141
|
+
* @returns Promise that resolves when sequence completes
|
142
|
+
*
|
143
|
+
* @example
|
144
|
+
* ```typescript
|
145
|
+
* await AnimationUtils.createBitmapSequence(session, [
|
146
|
+
* { frame: frame1Hex, duration: 1000 },
|
147
|
+
* { frame: frame2Hex, duration: 500 },
|
148
|
+
* { frame: frame3Hex, duration: 2000 }
|
149
|
+
* ]);
|
150
|
+
* ```
|
151
|
+
*/
|
152
|
+
static createBitmapSequence(session: AppSession, sequence: Array<{
|
153
|
+
frame: string;
|
154
|
+
duration: number;
|
155
|
+
}>): Promise<void>;
|
156
|
+
/**
|
157
|
+
* Measure animation timing performance
|
158
|
+
*
|
159
|
+
* @param targetInterval - Expected interval between frames in ms
|
160
|
+
* @param measureDuration - How long to measure in ms (default: 10 seconds)
|
161
|
+
* @returns Promise resolving to timing performance data
|
162
|
+
*
|
163
|
+
* @example
|
164
|
+
* ```typescript
|
165
|
+
* const timing = await AnimationUtils.measureTiming(1750, 10000);
|
166
|
+
* console.log(`Target: ${timing.targetInterval}ms, Actual: ${timing.actualInterval}ms`);
|
167
|
+
* console.log(`Drift: ${timing.drift}ms, FPS: ${timing.fps.toFixed(1)}`);
|
168
|
+
* ```
|
169
|
+
*/
|
170
|
+
static measureTiming(targetInterval: number, measureDuration?: number): Promise<TimingInfo>;
|
171
|
+
/**
|
172
|
+
* Create optimized animation settings for different hardware
|
173
|
+
*
|
174
|
+
* @param deviceType - Target device type
|
175
|
+
* @returns Recommended animation configuration
|
176
|
+
*
|
177
|
+
* @example
|
178
|
+
* ```typescript
|
179
|
+
* const config = AnimationUtils.getOptimizedConfig('even-realities-g1');
|
180
|
+
* const animation = await AnimationUtils.createBitmapAnimation(
|
181
|
+
* session, './frames', 10, config
|
182
|
+
* );
|
183
|
+
* ```
|
184
|
+
*/
|
185
|
+
static getOptimizedConfig(deviceType: 'even-realities-g1' | 'generic'): AnimationConfig;
|
186
|
+
/**
|
187
|
+
* Preload and cache animation frames for better performance
|
188
|
+
*
|
189
|
+
* @param basePath - Directory containing frames
|
190
|
+
* @param frameCount - Number of frames to preload
|
191
|
+
* @param options - Loading options
|
192
|
+
* @returns Promise resolving to cached frame data
|
193
|
+
*
|
194
|
+
* @example
|
195
|
+
* ```typescript
|
196
|
+
* // Preload frames
|
197
|
+
* const cachedFrames = await AnimationUtils.preloadFrames('./animations', 10);
|
198
|
+
*
|
199
|
+
* // Use cached frames multiple times
|
200
|
+
* const animation1 = AnimationUtils.createBitmapAnimationFromFrames(session, cachedFrames);
|
201
|
+
* const animation2 = AnimationUtils.createBitmapAnimationFromFrames(session, cachedFrames);
|
202
|
+
* ```
|
203
|
+
*/
|
204
|
+
static preloadFrames(basePath: string, frameCount: number, options?: LoadFramesOptions): Promise<string[]>;
|
205
|
+
}
|
206
|
+
//# sourceMappingURL=animation-utils.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"animation-utils.d.ts","sourceRoot":"","sources":["../../src/utils/animation-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAe,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,sDAAsD;IACtD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,yBAAyB;IACzB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,8BAA8B;IAC9B,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B,4BAA4B;IAC5B,cAAc,EAAE,MAAM,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,qCAAqC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,qBAAa,cAAc;IAEvB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;WACU,qBAAqB,CAC9B,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,eAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC;IAgD/B;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,+BAA+B,CAClC,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,EAAE,EAChB,MAAM,GAAE,IAAI,CAAC,eAAe,EAAE,aAAa,GAAG,gBAAgB,CAAM,GACrE,mBAAmB;IAyFtB;;;;;;;;;;;;;;;OAeG;WACU,oBAAoB,CAC7B,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC;IAuBhB;;;;;;;;;;;;;OAaG;WACU,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,eAAe,GAAE,MAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA0CxG;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,mBAAmB,GAAG,SAAS,GAAG,eAAe;IA2BvF;;;;;;;;;;;;;;;;;OAiBG;WACU,aAAa,CACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,iBAAsB,GAChC,OAAO,CAAC,MAAM,EAAE,CAAC;CAYvB"}
|
@@ -0,0 +1,339 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* 🎬 Animation Utilities Module
|
4
|
+
*
|
5
|
+
* Provides helper functions for creating and managing bitmap animations in MentraOS applications.
|
6
|
+
* Includes timing utilities, animation factories, and performance optimization helpers.
|
7
|
+
*
|
8
|
+
* @example
|
9
|
+
* ```typescript
|
10
|
+
* import { AnimationUtils } from '@mentra/sdk';
|
11
|
+
*
|
12
|
+
* // Create animation from files
|
13
|
+
* const animation = await AnimationUtils.createBitmapAnimation(
|
14
|
+
* session, './frames', 10, 1750, true
|
15
|
+
* );
|
16
|
+
*
|
17
|
+
* // Simple delay utility
|
18
|
+
* await AnimationUtils.delay(2000);
|
19
|
+
*
|
20
|
+
* // Stop animation
|
21
|
+
* animation.stop();
|
22
|
+
* ```
|
23
|
+
*/
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
25
|
+
exports.AnimationUtils = void 0;
|
26
|
+
const bitmap_utils_1 = require("./bitmap-utils");
|
27
|
+
/**
|
28
|
+
* Utility class for creating and managing animations in MentraOS applications
|
29
|
+
*/
|
30
|
+
class AnimationUtils {
|
31
|
+
/**
|
32
|
+
* Simple async delay helper
|
33
|
+
*
|
34
|
+
* @param ms - Milliseconds to delay
|
35
|
+
* @returns Promise that resolves after the specified delay
|
36
|
+
*
|
37
|
+
* @example
|
38
|
+
* ```typescript
|
39
|
+
* console.log('Starting...');
|
40
|
+
* await AnimationUtils.delay(2000);
|
41
|
+
* console.log('2 seconds later!');
|
42
|
+
* ```
|
43
|
+
*/
|
44
|
+
static delay(ms) {
|
45
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
46
|
+
}
|
47
|
+
/**
|
48
|
+
* Create bitmap animation from files with advanced configuration
|
49
|
+
*
|
50
|
+
* @param session - MentraOS app session
|
51
|
+
* @param basePath - Directory containing animation frames
|
52
|
+
* @param frameCount - Number of frames to load
|
53
|
+
* @param config - Animation configuration options
|
54
|
+
* @returns Promise resolving to animation controller
|
55
|
+
*
|
56
|
+
* @example
|
57
|
+
* ```typescript
|
58
|
+
* // Simple animation
|
59
|
+
* const animation = await AnimationUtils.createBitmapAnimation(
|
60
|
+
* session, './animations', 10
|
61
|
+
* );
|
62
|
+
*
|
63
|
+
* // Advanced configuration
|
64
|
+
* const advancedAnimation = await AnimationUtils.createBitmapAnimation(
|
65
|
+
* session, './sprites', 8, {
|
66
|
+
* intervalMs: 1000,
|
67
|
+
* repeat: true,
|
68
|
+
* loadOptions: { filePattern: 'sprite_{i}.bmp', startFrame: 0 },
|
69
|
+
* onFrame: (frame, total) => console.log(`Frame ${frame}/${total}`),
|
70
|
+
* onError: (error) => console.error('Animation error:', error)
|
71
|
+
* }
|
72
|
+
* );
|
73
|
+
* ```
|
74
|
+
*/
|
75
|
+
static async createBitmapAnimation(session, basePath, frameCount, config = {}) {
|
76
|
+
const { intervalMs = 1750, // Optimized for MentraOS hardware
|
77
|
+
repeat = false, validateFrames = true, loadOptions = {}, onStart, onStop, onFrame, onError } = config;
|
78
|
+
try {
|
79
|
+
console.log(`🎬 Loading ${frameCount} animation frames from ${basePath}...`);
|
80
|
+
// Load frames with validation
|
81
|
+
const frames = await bitmap_utils_1.BitmapUtils.loadBmpFrames(basePath, frameCount, {
|
82
|
+
validateFrames,
|
83
|
+
...loadOptions
|
84
|
+
});
|
85
|
+
if (frames.length === 0) {
|
86
|
+
throw new Error('No frames loaded for animation');
|
87
|
+
}
|
88
|
+
console.log(`📚 Animation ready: ${frames.length} frames at ${intervalMs}ms intervals`);
|
89
|
+
// Create enhanced animation with the loaded frames
|
90
|
+
return this.createBitmapAnimationFromFrames(session, frames, {
|
91
|
+
intervalMs,
|
92
|
+
repeat,
|
93
|
+
onStart,
|
94
|
+
onStop,
|
95
|
+
onFrame,
|
96
|
+
onError
|
97
|
+
});
|
98
|
+
}
|
99
|
+
catch (error) {
|
100
|
+
const errorMsg = `Failed to create animation: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
101
|
+
console.error(`❌ ${errorMsg}`);
|
102
|
+
if (onError) {
|
103
|
+
onError(errorMsg);
|
104
|
+
}
|
105
|
+
throw new Error(errorMsg);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
/**
|
109
|
+
* Create bitmap animation from pre-loaded frame data
|
110
|
+
*
|
111
|
+
* @param session - MentraOS app session
|
112
|
+
* @param frames - Array of hex-encoded bitmap data
|
113
|
+
* @param config - Animation configuration options
|
114
|
+
* @returns Animation controller
|
115
|
+
*
|
116
|
+
* @example
|
117
|
+
* ```typescript
|
118
|
+
* const frames = ['424d461a...', '424d461b...', '424d461c...'];
|
119
|
+
* const animation = AnimationUtils.createBitmapAnimationFromFrames(
|
120
|
+
* session, frames, { intervalMs: 1500, repeat: true }
|
121
|
+
* );
|
122
|
+
* ```
|
123
|
+
*/
|
124
|
+
static createBitmapAnimationFromFrames(session, frames, config = {}) {
|
125
|
+
const { intervalMs = 1750, repeat = false, onStart, onStop, onFrame, onError } = config;
|
126
|
+
let isRunning = false;
|
127
|
+
let currentFrame = 0;
|
128
|
+
let animationController = null;
|
129
|
+
const controller = {
|
130
|
+
stop: () => {
|
131
|
+
if (animationController) {
|
132
|
+
animationController.stop();
|
133
|
+
animationController = null;
|
134
|
+
}
|
135
|
+
isRunning = false;
|
136
|
+
if (onStop) {
|
137
|
+
onStop();
|
138
|
+
}
|
139
|
+
console.log('🛑 Animation stopped');
|
140
|
+
},
|
141
|
+
isRunning: () => isRunning,
|
142
|
+
getCurrentFrame: () => currentFrame,
|
143
|
+
getTotalFrames: () => frames.length
|
144
|
+
};
|
145
|
+
try {
|
146
|
+
// Start the animation using the session's built-in method
|
147
|
+
animationController = session.layouts.showBitmapAnimation(frames, intervalMs, repeat);
|
148
|
+
isRunning = true;
|
149
|
+
if (onStart) {
|
150
|
+
onStart();
|
151
|
+
}
|
152
|
+
console.log(`🎬 Animation started: ${frames.length} frames at ${intervalMs}ms${repeat ? ' (repeating)' : ''}`);
|
153
|
+
// If we have frame callbacks, we need to track timing manually
|
154
|
+
// This is a limitation of the current SDK - we can't hook into individual frame displays
|
155
|
+
if (onFrame) {
|
156
|
+
let frameTracker = 0;
|
157
|
+
// Call onFrame for the first frame immediately
|
158
|
+
onFrame(frameTracker, frames.length);
|
159
|
+
const frameInterval = setInterval(() => {
|
160
|
+
if (!isRunning) {
|
161
|
+
clearInterval(frameInterval);
|
162
|
+
return;
|
163
|
+
}
|
164
|
+
frameTracker = (frameTracker + 1) % frames.length;
|
165
|
+
onFrame(frameTracker, frames.length);
|
166
|
+
// If not repeating and we've shown all frames, stop tracking
|
167
|
+
if (!repeat && frameTracker === frames.length - 1) {
|
168
|
+
clearInterval(frameInterval);
|
169
|
+
}
|
170
|
+
}, intervalMs);
|
171
|
+
// Override stop to also clear frame tracking
|
172
|
+
const originalStop = controller.stop;
|
173
|
+
controller.stop = () => {
|
174
|
+
clearInterval(frameInterval);
|
175
|
+
originalStop();
|
176
|
+
};
|
177
|
+
}
|
178
|
+
}
|
179
|
+
catch (error) {
|
180
|
+
const errorMsg = `Failed to start animation: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
181
|
+
console.error(`❌ ${errorMsg}`);
|
182
|
+
if (onError) {
|
183
|
+
onError(errorMsg);
|
184
|
+
}
|
185
|
+
throw new Error(errorMsg);
|
186
|
+
}
|
187
|
+
return controller;
|
188
|
+
}
|
189
|
+
/**
|
190
|
+
* Create a sequence of bitmap displays with custom timing
|
191
|
+
*
|
192
|
+
* @param session - MentraOS app session
|
193
|
+
* @param sequence - Array of frame data with individual timing
|
194
|
+
* @returns Promise that resolves when sequence completes
|
195
|
+
*
|
196
|
+
* @example
|
197
|
+
* ```typescript
|
198
|
+
* await AnimationUtils.createBitmapSequence(session, [
|
199
|
+
* { frame: frame1Hex, duration: 1000 },
|
200
|
+
* { frame: frame2Hex, duration: 500 },
|
201
|
+
* { frame: frame3Hex, duration: 2000 }
|
202
|
+
* ]);
|
203
|
+
* ```
|
204
|
+
*/
|
205
|
+
static async createBitmapSequence(session, sequence) {
|
206
|
+
console.log(`🎭 Starting bitmap sequence: ${sequence.length} frames with custom timing`);
|
207
|
+
for (let i = 0; i < sequence.length; i++) {
|
208
|
+
const { frame, duration } = sequence[i];
|
209
|
+
try {
|
210
|
+
console.log(`📽️ Sequence frame ${i + 1}/${sequence.length} (${duration}ms)`);
|
211
|
+
session.layouts.showBitmapView(frame);
|
212
|
+
if (i < sequence.length - 1) { // Don't delay after the last frame
|
213
|
+
await this.delay(duration);
|
214
|
+
}
|
215
|
+
}
|
216
|
+
catch (error) {
|
217
|
+
console.error(`❌ Error in sequence frame ${i + 1}:`, error);
|
218
|
+
throw error;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
console.log('✅ Bitmap sequence completed');
|
222
|
+
}
|
223
|
+
/**
|
224
|
+
* Measure animation timing performance
|
225
|
+
*
|
226
|
+
* @param targetInterval - Expected interval between frames in ms
|
227
|
+
* @param measureDuration - How long to measure in ms (default: 10 seconds)
|
228
|
+
* @returns Promise resolving to timing performance data
|
229
|
+
*
|
230
|
+
* @example
|
231
|
+
* ```typescript
|
232
|
+
* const timing = await AnimationUtils.measureTiming(1750, 10000);
|
233
|
+
* console.log(`Target: ${timing.targetInterval}ms, Actual: ${timing.actualInterval}ms`);
|
234
|
+
* console.log(`Drift: ${timing.drift}ms, FPS: ${timing.fps.toFixed(1)}`);
|
235
|
+
* ```
|
236
|
+
*/
|
237
|
+
static async measureTiming(targetInterval, measureDuration = 10000) {
|
238
|
+
return new Promise((resolve) => {
|
239
|
+
const timestamps = [];
|
240
|
+
let startTime = Date.now();
|
241
|
+
const measureInterval = setInterval(() => {
|
242
|
+
timestamps.push(Date.now());
|
243
|
+
}, targetInterval);
|
244
|
+
setTimeout(() => {
|
245
|
+
clearInterval(measureInterval);
|
246
|
+
if (timestamps.length < 2) {
|
247
|
+
resolve({
|
248
|
+
targetInterval,
|
249
|
+
actualInterval: targetInterval,
|
250
|
+
drift: 0,
|
251
|
+
fps: 1000 / targetInterval
|
252
|
+
});
|
253
|
+
return;
|
254
|
+
}
|
255
|
+
// Calculate actual interval
|
256
|
+
const intervals = [];
|
257
|
+
for (let i = 1; i < timestamps.length; i++) {
|
258
|
+
intervals.push(timestamps[i] - timestamps[i - 1]);
|
259
|
+
}
|
260
|
+
const actualInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length;
|
261
|
+
const drift = actualInterval - targetInterval;
|
262
|
+
const fps = 1000 / actualInterval;
|
263
|
+
resolve({
|
264
|
+
targetInterval,
|
265
|
+
actualInterval,
|
266
|
+
drift,
|
267
|
+
fps
|
268
|
+
});
|
269
|
+
}, measureDuration);
|
270
|
+
});
|
271
|
+
}
|
272
|
+
/**
|
273
|
+
* Create optimized animation settings for different hardware
|
274
|
+
*
|
275
|
+
* @param deviceType - Target device type
|
276
|
+
* @returns Recommended animation configuration
|
277
|
+
*
|
278
|
+
* @example
|
279
|
+
* ```typescript
|
280
|
+
* const config = AnimationUtils.getOptimizedConfig('even-realities-g1');
|
281
|
+
* const animation = await AnimationUtils.createBitmapAnimation(
|
282
|
+
* session, './frames', 10, config
|
283
|
+
* );
|
284
|
+
* ```
|
285
|
+
*/
|
286
|
+
static getOptimizedConfig(deviceType) {
|
287
|
+
switch (deviceType) {
|
288
|
+
case 'even-realities-g1':
|
289
|
+
return {
|
290
|
+
intervalMs: 1650, // Tested optimal timing for Even Realities G1
|
291
|
+
repeat: false,
|
292
|
+
validateFrames: true,
|
293
|
+
loadOptions: {
|
294
|
+
validateFrames: true,
|
295
|
+
skipMissingFrames: false
|
296
|
+
}
|
297
|
+
};
|
298
|
+
case 'generic':
|
299
|
+
default:
|
300
|
+
return {
|
301
|
+
intervalMs: 1000,
|
302
|
+
repeat: false,
|
303
|
+
validateFrames: true,
|
304
|
+
loadOptions: {
|
305
|
+
validateFrames: true,
|
306
|
+
skipMissingFrames: false
|
307
|
+
}
|
308
|
+
};
|
309
|
+
}
|
310
|
+
}
|
311
|
+
/**
|
312
|
+
* Preload and cache animation frames for better performance
|
313
|
+
*
|
314
|
+
* @param basePath - Directory containing frames
|
315
|
+
* @param frameCount - Number of frames to preload
|
316
|
+
* @param options - Loading options
|
317
|
+
* @returns Promise resolving to cached frame data
|
318
|
+
*
|
319
|
+
* @example
|
320
|
+
* ```typescript
|
321
|
+
* // Preload frames
|
322
|
+
* const cachedFrames = await AnimationUtils.preloadFrames('./animations', 10);
|
323
|
+
*
|
324
|
+
* // Use cached frames multiple times
|
325
|
+
* const animation1 = AnimationUtils.createBitmapAnimationFromFrames(session, cachedFrames);
|
326
|
+
* const animation2 = AnimationUtils.createBitmapAnimationFromFrames(session, cachedFrames);
|
327
|
+
* ```
|
328
|
+
*/
|
329
|
+
static async preloadFrames(basePath, frameCount, options = {}) {
|
330
|
+
console.log(`📦 Preloading ${frameCount} frames from ${basePath}...`);
|
331
|
+
const frames = await bitmap_utils_1.BitmapUtils.loadBmpFrames(basePath, frameCount, {
|
332
|
+
validateFrames: true,
|
333
|
+
...options
|
334
|
+
});
|
335
|
+
console.log(`✅ Preloaded ${frames.length} frames (${frames.reduce((total, frame) => total + frame.length, 0)} total characters)`);
|
336
|
+
return frames;
|
337
|
+
}
|
338
|
+
}
|
339
|
+
exports.AnimationUtils = AnimationUtils;
|
@@ -0,0 +1,147 @@
|
|
1
|
+
/**
|
2
|
+
* 🎨 Bitmap Utilities Module
|
3
|
+
*
|
4
|
+
* Provides helper functions for working with bitmap images in MentraOS applications.
|
5
|
+
* Includes file loading, data validation, and format conversion utilities.
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
* ```typescript
|
9
|
+
* import { BitmapUtils } from '@mentra/sdk';
|
10
|
+
*
|
11
|
+
* // Load a single BMP file
|
12
|
+
* const bmpHex = await BitmapUtils.loadBmpAsHex('./my-image.bmp');
|
13
|
+
* session.layouts.showBitmapView(bmpHex);
|
14
|
+
*
|
15
|
+
* // Load multiple animation frames
|
16
|
+
* const frames = await BitmapUtils.loadBmpFrames('./animations', 10);
|
17
|
+
* session.layouts.showBitmapAnimation(frames, 1500, true);
|
18
|
+
* ```
|
19
|
+
*/
|
20
|
+
/**
|
21
|
+
* Validation result for bitmap data
|
22
|
+
*/
|
23
|
+
export interface BitmapValidation {
|
24
|
+
/** Whether the bitmap data is valid */
|
25
|
+
isValid: boolean;
|
26
|
+
/** Total byte count of the bitmap */
|
27
|
+
byteCount: number;
|
28
|
+
/** Number of black (non-FF) pixels found */
|
29
|
+
blackPixels: number;
|
30
|
+
/** Array of validation error messages */
|
31
|
+
errors: string[];
|
32
|
+
/** Additional metadata about the bitmap */
|
33
|
+
metadata?: {
|
34
|
+
/** Expected bitmap dimensions (if detectable) */
|
35
|
+
dimensions?: {
|
36
|
+
width: number;
|
37
|
+
height: number;
|
38
|
+
};
|
39
|
+
/** Bitmap file format info */
|
40
|
+
format?: string;
|
41
|
+
};
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Options for loading bitmap frames
|
45
|
+
*/
|
46
|
+
export interface LoadFramesOptions {
|
47
|
+
/** File name pattern (default: 'animation_10_frame_{i}.bmp') */
|
48
|
+
filePattern?: string;
|
49
|
+
/** Starting frame number (default: 1) */
|
50
|
+
startFrame?: number;
|
51
|
+
/** Validate each frame during loading (default: true) */
|
52
|
+
validateFrames?: boolean;
|
53
|
+
/** Continue loading if a frame is missing (default: false) */
|
54
|
+
skipMissingFrames?: boolean;
|
55
|
+
}
|
56
|
+
/**
|
57
|
+
* Utility class for working with bitmap images in MentraOS applications
|
58
|
+
*/
|
59
|
+
export declare class BitmapUtils {
|
60
|
+
/**
|
61
|
+
* Load a BMP file as hex string from filesystem
|
62
|
+
*
|
63
|
+
* @param filePath - Path to the BMP file
|
64
|
+
* @returns Promise resolving to hex-encoded bitmap data
|
65
|
+
* @throws Error if file cannot be read or is not a valid BMP
|
66
|
+
*
|
67
|
+
* @example
|
68
|
+
* ```typescript
|
69
|
+
* const bmpHex = await BitmapUtils.loadBmpAsHex('./assets/icon.bmp');
|
70
|
+
* session.layouts.showBitmapView(bmpHex);
|
71
|
+
* ```
|
72
|
+
*/
|
73
|
+
static loadBmpAsHex(filePath: string): Promise<string>;
|
74
|
+
/**
|
75
|
+
* Load multiple BMP frames as hex array for animations
|
76
|
+
*
|
77
|
+
* @param basePath - Directory containing the frame files
|
78
|
+
* @param frameCount - Number of frames to load
|
79
|
+
* @param options - Loading options and configuration
|
80
|
+
* @returns Promise resolving to array of hex-encoded bitmap data
|
81
|
+
*
|
82
|
+
* @example
|
83
|
+
* ```typescript
|
84
|
+
* // Load 10 frames with default pattern
|
85
|
+
* const frames = await BitmapUtils.loadBmpFrames('./animations', 10);
|
86
|
+
*
|
87
|
+
* // Load with custom pattern
|
88
|
+
* const customFrames = await BitmapUtils.loadBmpFrames('./sprites', 8, {
|
89
|
+
* filePattern: 'sprite_{i}.bmp',
|
90
|
+
* startFrame: 0
|
91
|
+
* });
|
92
|
+
* ```
|
93
|
+
*/
|
94
|
+
static loadBmpFrames(basePath: string, frameCount: number, options?: LoadFramesOptions): Promise<string[]>;
|
95
|
+
/**
|
96
|
+
* Validate BMP hex data integrity and extract metadata
|
97
|
+
*
|
98
|
+
* @param hexString - Hex-encoded bitmap data
|
99
|
+
* @returns Validation result with detailed information
|
100
|
+
*
|
101
|
+
* @example
|
102
|
+
* ```typescript
|
103
|
+
* const validation = BitmapUtils.validateBmpHex(bmpHex);
|
104
|
+
* if (!validation.isValid) {
|
105
|
+
* console.error('Invalid bitmap:', validation.errors);
|
106
|
+
* } else {
|
107
|
+
* console.log(`Valid bitmap: ${validation.blackPixels} black pixels`);
|
108
|
+
* }
|
109
|
+
* ```
|
110
|
+
*/
|
111
|
+
static validateBmpHex(hexString: string): BitmapValidation;
|
112
|
+
/**
|
113
|
+
* Convert bitmap data between different formats
|
114
|
+
*
|
115
|
+
* @param data - Input bitmap data
|
116
|
+
* @param fromFormat - Source format ('hex' | 'base64' | 'buffer')
|
117
|
+
* @param toFormat - Target format ('hex' | 'base64' | 'buffer')
|
118
|
+
* @returns Converted bitmap data
|
119
|
+
*
|
120
|
+
* @example
|
121
|
+
* ```typescript
|
122
|
+
* const base64Data = BitmapUtils.convertFormat(hexData, 'hex', 'base64');
|
123
|
+
* const bufferData = BitmapUtils.convertFormat(base64Data, 'base64', 'buffer');
|
124
|
+
* ```
|
125
|
+
*/
|
126
|
+
static convertFormat(data: string | Buffer, fromFormat: 'hex' | 'base64' | 'buffer', toFormat: 'hex' | 'base64' | 'buffer'): string | Buffer;
|
127
|
+
/**
|
128
|
+
* Get bitmap information without full validation
|
129
|
+
*
|
130
|
+
* @param hexString - Hex-encoded bitmap data
|
131
|
+
* @returns Basic bitmap information
|
132
|
+
*
|
133
|
+
* @example
|
134
|
+
* ```typescript
|
135
|
+
* const info = BitmapUtils.getBitmapInfo(bmpHex);
|
136
|
+
* console.log(`Bitmap: ${info.width}x${info.height}, ${info.blackPixels} black pixels`);
|
137
|
+
* ```
|
138
|
+
*/
|
139
|
+
static getBitmapInfo(hexString: string): {
|
140
|
+
byteCount: number;
|
141
|
+
blackPixels: number;
|
142
|
+
width?: number;
|
143
|
+
height?: number;
|
144
|
+
isValidBmp: boolean;
|
145
|
+
};
|
146
|
+
}
|
147
|
+
//# sourceMappingURL=bitmap-utils.d.ts.map
|