lotio 1.1.54 → 1.1.56
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/browser/index.js +154 -2
- package/browser/lotio.js +1 -1
- package/browser/lotio.wasm +0 -0
- package/browser/wasm.js +368 -58
- package/package.json +1 -1
package/browser/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module lotio
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { initLotio, createAnimation, renderFrameToCanvas, renderFrameRGBA, cleanup, registerFont, getVersion } from './wasm.js';
|
|
6
|
+
import { initLotio, createAnimation, renderFrameToCanvas, renderFrameRGBA, cleanup, registerFont, getVersion, setDebugMode } from './wasm.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Animation states
|
|
@@ -75,6 +75,7 @@ export class Lotio extends EventEmitter {
|
|
|
75
75
|
* @param {number} options.textPadding - Text padding factor (0.0-1.0, default: 0.97)
|
|
76
76
|
* @param {string} options.textMeasurementMode - Text measurement mode: 'fast'|'accurate'|'pixel-perfect' (default: 'accurate')
|
|
77
77
|
* @param {string} options.wasmPath - Path to lotio.wasm file (default: './lotio.wasm')
|
|
78
|
+
* @param {boolean} options.debug - Enable debug logging (default: false)
|
|
78
79
|
*/
|
|
79
80
|
constructor(options = {}) {
|
|
80
81
|
super();
|
|
@@ -86,6 +87,7 @@ export class Lotio extends EventEmitter {
|
|
|
86
87
|
this._layerOverrides = options.layerOverrides || null;
|
|
87
88
|
this._textPadding = options.textPadding !== undefined ? options.textPadding : 0.97;
|
|
88
89
|
this._textMeasurementMode = options.textMeasurementMode || 'accurate';
|
|
90
|
+
this._debug = options.debug === true;
|
|
89
91
|
this._state = State.STOPPED;
|
|
90
92
|
this._wasmInitialized = false;
|
|
91
93
|
this._animationInfo = null;
|
|
@@ -96,6 +98,19 @@ export class Lotio extends EventEmitter {
|
|
|
96
98
|
this._startTime = 0;
|
|
97
99
|
this._registeredFonts = new Set();
|
|
98
100
|
|
|
101
|
+
if (this._debug) {
|
|
102
|
+
console.log('[Lotio] Constructor called with options:', {
|
|
103
|
+
wasmPath: this._wasmPath,
|
|
104
|
+
fps: this._fps,
|
|
105
|
+
hasAnimation: !!this._animation,
|
|
106
|
+
hasLayerOverrides: !!this._layerOverrides,
|
|
107
|
+
textPadding: this._textPadding,
|
|
108
|
+
textMeasurementMode: this._textMeasurementMode,
|
|
109
|
+
fontsCount: this._fonts.length,
|
|
110
|
+
debug: this._debug
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
99
114
|
// Auto-initialize if animation is provided
|
|
100
115
|
if (this._animation) {
|
|
101
116
|
this._init().catch(error => {
|
|
@@ -111,14 +126,34 @@ export class Lotio extends EventEmitter {
|
|
|
111
126
|
*/
|
|
112
127
|
async _init() {
|
|
113
128
|
if (this._wasmInitialized) {
|
|
129
|
+
if (this._debug) {
|
|
130
|
+
console.log('[Lotio] WASM already initialized, skipping');
|
|
131
|
+
}
|
|
114
132
|
return;
|
|
115
133
|
}
|
|
116
134
|
|
|
135
|
+
let initStartTime;
|
|
136
|
+
if (this._debug) {
|
|
137
|
+
console.log('[Lotio] Initializing WASM module from:', this._wasmPath);
|
|
138
|
+
initStartTime = performance.now();
|
|
139
|
+
setDebugMode(true);
|
|
140
|
+
} else {
|
|
141
|
+
setDebugMode(false);
|
|
142
|
+
}
|
|
143
|
+
|
|
117
144
|
try {
|
|
118
145
|
await initLotio(this._wasmPath);
|
|
119
146
|
this._wasmInitialized = true;
|
|
120
147
|
|
|
148
|
+
if (this._debug) {
|
|
149
|
+
const initEndTime = performance.now();
|
|
150
|
+
console.log(`[Lotio] WASM module initialized successfully in ${initStartTime ? (initEndTime - initStartTime).toFixed(2) : '?'}ms`);
|
|
151
|
+
}
|
|
152
|
+
|
|
121
153
|
// Register fonts
|
|
154
|
+
if (this._debug && this._fonts.length > 0) {
|
|
155
|
+
console.log(`[Lotio] Registering ${this._fonts.length} font(s)...`);
|
|
156
|
+
}
|
|
122
157
|
for (const font of this._fonts) {
|
|
123
158
|
await this._registerFont(font.name, font.data);
|
|
124
159
|
}
|
|
@@ -128,8 +163,14 @@ export class Lotio extends EventEmitter {
|
|
|
128
163
|
await this._loadAnimation();
|
|
129
164
|
} else {
|
|
130
165
|
this._setState(State.LOADED);
|
|
166
|
+
if (this._debug) {
|
|
167
|
+
console.log('[Lotio] No animation provided, state set to LOADED');
|
|
168
|
+
}
|
|
131
169
|
}
|
|
132
170
|
} catch (error) {
|
|
171
|
+
if (this._debug) {
|
|
172
|
+
console.error('[Lotio] Failed to initialize WASM:', error);
|
|
173
|
+
}
|
|
133
174
|
this._setState(State.ERROR);
|
|
134
175
|
this.emit('error', error, this);
|
|
135
176
|
throw error;
|
|
@@ -142,6 +183,9 @@ export class Lotio extends EventEmitter {
|
|
|
142
183
|
*/
|
|
143
184
|
async _registerFont(name, data) {
|
|
144
185
|
if (this._registeredFonts.has(name)) {
|
|
186
|
+
if (this._debug) {
|
|
187
|
+
console.log(`[Lotio] Font "${name}" already registered, skipping`);
|
|
188
|
+
}
|
|
145
189
|
return;
|
|
146
190
|
}
|
|
147
191
|
|
|
@@ -149,8 +193,16 @@ export class Lotio extends EventEmitter {
|
|
|
149
193
|
await this._init();
|
|
150
194
|
}
|
|
151
195
|
|
|
196
|
+
if (this._debug) {
|
|
197
|
+
console.log(`[Lotio] Registering font "${name}" (${data.length} bytes)`);
|
|
198
|
+
}
|
|
199
|
+
|
|
152
200
|
registerFont(name, data);
|
|
153
201
|
this._registeredFonts.add(name);
|
|
202
|
+
|
|
203
|
+
if (this._debug) {
|
|
204
|
+
console.log(`[Lotio] Font "${name}" registered successfully`);
|
|
205
|
+
}
|
|
154
206
|
}
|
|
155
207
|
|
|
156
208
|
/**
|
|
@@ -162,6 +214,12 @@ export class Lotio extends EventEmitter {
|
|
|
162
214
|
await this._init();
|
|
163
215
|
}
|
|
164
216
|
|
|
217
|
+
let loadStartTime;
|
|
218
|
+
if (this._debug) {
|
|
219
|
+
console.log('[Lotio] Loading animation...');
|
|
220
|
+
loadStartTime = performance.now();
|
|
221
|
+
}
|
|
222
|
+
|
|
165
223
|
try {
|
|
166
224
|
const animationJson = typeof this._animation === 'string'
|
|
167
225
|
? this._animation
|
|
@@ -173,6 +231,15 @@ export class Lotio extends EventEmitter {
|
|
|
173
231
|
: JSON.stringify(this._layerOverrides))
|
|
174
232
|
: null;
|
|
175
233
|
|
|
234
|
+
if (this._debug) {
|
|
235
|
+
const animSize = animationJson.length;
|
|
236
|
+
console.log(`[Lotio] Animation JSON size: ${animSize} bytes`);
|
|
237
|
+
if (layerOverridesJson) {
|
|
238
|
+
console.log(`[Lotio] Layer overrides JSON size: ${layerOverridesJson.length} bytes`);
|
|
239
|
+
}
|
|
240
|
+
console.log(`[Lotio] Text padding: ${this._textPadding}, measurement mode: ${this._textMeasurementMode}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
176
243
|
this._animationInfo = createAnimation(
|
|
177
244
|
JSON.parse(animationJson),
|
|
178
245
|
layerOverridesJson ? JSON.parse(layerOverridesJson) : null,
|
|
@@ -180,11 +247,25 @@ export class Lotio extends EventEmitter {
|
|
|
180
247
|
this._textMeasurementMode
|
|
181
248
|
);
|
|
182
249
|
|
|
250
|
+
if (this._debug) {
|
|
251
|
+
const loadEndTime = performance.now();
|
|
252
|
+
console.log(`[Lotio] Animation loaded successfully in ${loadStartTime ? (loadEndTime - loadStartTime).toFixed(2) : '?'}ms`);
|
|
253
|
+
console.log('[Lotio] Animation info:', {
|
|
254
|
+
width: this._animationInfo.width,
|
|
255
|
+
height: this._animationInfo.height,
|
|
256
|
+
duration: this._animationInfo.duration,
|
|
257
|
+
fps: this._animationInfo.fps
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
183
261
|
this._currentTime = 0;
|
|
184
262
|
this._currentFrame = 0;
|
|
185
263
|
this._setState(State.LOADED);
|
|
186
264
|
this.emit('loaded', this);
|
|
187
265
|
} catch (error) {
|
|
266
|
+
if (this._debug) {
|
|
267
|
+
console.error('[Lotio] Failed to load animation:', error);
|
|
268
|
+
}
|
|
188
269
|
this._setState(State.ERROR);
|
|
189
270
|
this.emit('error', error, this);
|
|
190
271
|
throw error;
|
|
@@ -200,6 +281,9 @@ export class Lotio extends EventEmitter {
|
|
|
200
281
|
this._state = newState;
|
|
201
282
|
|
|
202
283
|
if (oldState !== newState) {
|
|
284
|
+
if (this._debug) {
|
|
285
|
+
console.log(`[Lotio] State changed: ${oldState} -> ${newState}`);
|
|
286
|
+
}
|
|
203
287
|
this.emit('statechange', newState, oldState, this);
|
|
204
288
|
}
|
|
205
289
|
}
|
|
@@ -210,6 +294,9 @@ export class Lotio extends EventEmitter {
|
|
|
210
294
|
*/
|
|
211
295
|
_animate() {
|
|
212
296
|
if (!this._isPlaying || !this._animationInfo) {
|
|
297
|
+
if (this._debug) {
|
|
298
|
+
console.warn('[Lotio] Animation loop called but not playing or no animation info');
|
|
299
|
+
}
|
|
213
300
|
return;
|
|
214
301
|
}
|
|
215
302
|
|
|
@@ -221,8 +308,15 @@ export class Lotio extends EventEmitter {
|
|
|
221
308
|
this._currentTime = (elapsed * speedMultiplier) % this._animationInfo.duration;
|
|
222
309
|
this._currentFrame = Math.floor(this._currentTime * animationFPS);
|
|
223
310
|
|
|
311
|
+
if (this._debug && this._currentFrame % Math.floor(animationFPS) === 0) {
|
|
312
|
+
console.log(`[Lotio] Frame ${this._currentFrame} at time ${this._currentTime.toFixed(3)}s (${(this._currentTime / this._animationInfo.duration * 100).toFixed(1)}%)`);
|
|
313
|
+
}
|
|
314
|
+
|
|
224
315
|
// Check if animation ended
|
|
225
316
|
if (this._currentTime >= this._animationInfo.duration) {
|
|
317
|
+
if (this._debug) {
|
|
318
|
+
console.log('[Lotio] Animation ended');
|
|
319
|
+
}
|
|
226
320
|
this.stop();
|
|
227
321
|
this.emit('end', this);
|
|
228
322
|
return;
|
|
@@ -344,6 +438,9 @@ export class Lotio extends EventEmitter {
|
|
|
344
438
|
throw new Error('Animation not loaded');
|
|
345
439
|
}
|
|
346
440
|
|
|
441
|
+
const oldTime = this._currentTime;
|
|
442
|
+
const oldFrame = this._currentFrame;
|
|
443
|
+
|
|
347
444
|
// Determine if input is frame number or time
|
|
348
445
|
if (frameOrTime < 1) {
|
|
349
446
|
// Likely a time value (0.0 - duration)
|
|
@@ -356,6 +453,10 @@ export class Lotio extends EventEmitter {
|
|
|
356
453
|
this._currentTime = this._currentFrame / animationFPS;
|
|
357
454
|
}
|
|
358
455
|
|
|
456
|
+
if (this._debug && (oldTime !== this._currentTime || oldFrame !== this._currentFrame)) {
|
|
457
|
+
console.log(`[Lotio] Seek: frame ${oldFrame} -> ${this._currentFrame}, time ${oldTime.toFixed(3)}s -> ${this._currentTime.toFixed(3)}s`);
|
|
458
|
+
}
|
|
459
|
+
|
|
359
460
|
if (this._isPlaying) {
|
|
360
461
|
this._startTime = performance.now() - (this._currentTime / (this._fps / (this._animationInfo.fps || 30)) * 1000);
|
|
361
462
|
}
|
|
@@ -370,9 +471,17 @@ export class Lotio extends EventEmitter {
|
|
|
370
471
|
}
|
|
371
472
|
|
|
372
473
|
if (this._isPlaying) {
|
|
474
|
+
if (this._debug) {
|
|
475
|
+
console.log('[Lotio] Already playing, ignoring start() call');
|
|
476
|
+
}
|
|
373
477
|
return this;
|
|
374
478
|
}
|
|
375
479
|
|
|
480
|
+
if (this._debug) {
|
|
481
|
+
console.log('[Lotio] Starting animation...');
|
|
482
|
+
console.log(`[Lotio] Starting from frame ${this._currentFrame}, time ${this._currentTime.toFixed(3)}s`);
|
|
483
|
+
}
|
|
484
|
+
|
|
376
485
|
this._isPlaying = true;
|
|
377
486
|
this._setState(State.PLAYING);
|
|
378
487
|
|
|
@@ -380,6 +489,10 @@ export class Lotio extends EventEmitter {
|
|
|
380
489
|
const speedMultiplier = this._fps / animationFPS;
|
|
381
490
|
this._startTime = performance.now() - (this._currentTime / speedMultiplier * 1000);
|
|
382
491
|
|
|
492
|
+
if (this._debug) {
|
|
493
|
+
console.log(`[Lotio] Animation FPS: ${animationFPS}, Target FPS: ${this._fps}, Speed multiplier: ${speedMultiplier.toFixed(3)}`);
|
|
494
|
+
}
|
|
495
|
+
|
|
383
496
|
this.emit('start', this);
|
|
384
497
|
this._animate();
|
|
385
498
|
|
|
@@ -388,9 +501,16 @@ export class Lotio extends EventEmitter {
|
|
|
388
501
|
|
|
389
502
|
pause() {
|
|
390
503
|
if (!this._isPlaying) {
|
|
504
|
+
if (this._debug) {
|
|
505
|
+
console.log('[Lotio] Not playing, ignoring pause() call');
|
|
506
|
+
}
|
|
391
507
|
return this;
|
|
392
508
|
}
|
|
393
509
|
|
|
510
|
+
if (this._debug) {
|
|
511
|
+
console.log(`[Lotio] Pausing at frame ${this._currentFrame}, time ${this._currentTime.toFixed(3)}s`);
|
|
512
|
+
}
|
|
513
|
+
|
|
394
514
|
this._isPlaying = false;
|
|
395
515
|
this._setState(State.PAUSED);
|
|
396
516
|
|
|
@@ -406,6 +526,10 @@ export class Lotio extends EventEmitter {
|
|
|
406
526
|
stop() {
|
|
407
527
|
const wasPlaying = this._isPlaying;
|
|
408
528
|
|
|
529
|
+
if (this._debug && wasPlaying) {
|
|
530
|
+
console.log(`[Lotio] Stopping animation (was at frame ${this._currentFrame}, time ${this._currentTime.toFixed(3)}s)`);
|
|
531
|
+
}
|
|
532
|
+
|
|
409
533
|
this.pause();
|
|
410
534
|
this.seek(0);
|
|
411
535
|
this._setState(State.STOPPED);
|
|
@@ -421,12 +545,31 @@ export class Lotio extends EventEmitter {
|
|
|
421
545
|
* Render current frame to canvas
|
|
422
546
|
* @param {HTMLCanvasElement} canvas - Canvas element to render to
|
|
423
547
|
* @param {string} bgColor - Background color (default: '#2a2a2a')
|
|
548
|
+
* @param {boolean} emitFrameEvent - Whether to emit 'frame' event (default: false)
|
|
424
549
|
*/
|
|
425
|
-
renderToCanvas(canvas, bgColor = '#2a2a2a') {
|
|
550
|
+
renderToCanvas(canvas, bgColor = '#2a2a2a', emitFrameEvent = false) {
|
|
426
551
|
if (!this._animationInfo) {
|
|
427
552
|
throw new Error('Animation not loaded');
|
|
428
553
|
}
|
|
554
|
+
|
|
555
|
+
let renderStartTime;
|
|
556
|
+
if (this._debug) {
|
|
557
|
+
console.log(`[Lotio] Rendering frame ${this._currentFrame} (time ${this._currentTime.toFixed(3)}s) to canvas`);
|
|
558
|
+
renderStartTime = performance.now();
|
|
559
|
+
}
|
|
560
|
+
|
|
429
561
|
renderFrameToCanvas(canvas, this._currentTime, bgColor);
|
|
562
|
+
|
|
563
|
+
// Optionally emit frame event when rendering directly
|
|
564
|
+
if (emitFrameEvent) {
|
|
565
|
+
this.emit('frame', this._currentFrame, this._currentTime, this);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (this._debug) {
|
|
569
|
+
const renderEndTime = performance.now();
|
|
570
|
+
console.log(`[Lotio] Canvas rendered in ${renderStartTime ? (renderEndTime - renderStartTime).toFixed(2) : '?'}ms`);
|
|
571
|
+
}
|
|
572
|
+
|
|
430
573
|
return this;
|
|
431
574
|
}
|
|
432
575
|
|
|
@@ -434,12 +577,21 @@ export class Lotio extends EventEmitter {
|
|
|
434
577
|
* Cleanup resources
|
|
435
578
|
*/
|
|
436
579
|
destroy() {
|
|
580
|
+
if (this._debug) {
|
|
581
|
+
console.log('[Lotio] Destroying instance...');
|
|
582
|
+
}
|
|
583
|
+
|
|
437
584
|
this.stop();
|
|
438
585
|
cleanup();
|
|
439
586
|
this._wasmInitialized = false;
|
|
440
587
|
this._animationInfo = null;
|
|
441
588
|
this._state = State.STOPPED;
|
|
442
589
|
this.emit('destroy', this);
|
|
590
|
+
|
|
591
|
+
if (this._debug) {
|
|
592
|
+
console.log('[Lotio] Instance destroyed');
|
|
593
|
+
}
|
|
594
|
+
|
|
443
595
|
return this;
|
|
444
596
|
}
|
|
445
597
|
}
|