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 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
  }