etro 0.8.0 → 0.8.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.
Files changed (95) hide show
  1. package/.github/workflows/nodejs.yml +3 -1
  2. package/CHANGELOG.md +9 -1
  3. package/CODE_OF_CONDUCT.md +5 -5
  4. package/CONTRIBUTING.md +22 -72
  5. package/README.md +1 -1
  6. package/dist/effect/base.d.ts +14 -1
  7. package/dist/etro-cjs.js +156 -213
  8. package/dist/etro-iife.js +156 -213
  9. package/dist/layer/base.d.ts +13 -0
  10. package/eslint.conf.js +2 -1
  11. package/eslint.test-conf.js +1 -0
  12. package/examples/application/readme-screenshot.html +4 -8
  13. package/examples/application/video-player.html +3 -4
  14. package/examples/introduction/effects.html +23 -4
  15. package/karma.conf.js +4 -2
  16. package/package.json +4 -1
  17. package/scripts/gen-effect-samples.html +0 -3
  18. package/src/effect/base.ts +29 -10
  19. package/src/effect/gaussian-blur.ts +10 -10
  20. package/src/effect/pixelate.ts +1 -2
  21. package/src/effect/shader.ts +18 -22
  22. package/src/effect/stack.ts +5 -2
  23. package/src/effect/transform.ts +13 -14
  24. package/src/event.ts +8 -14
  25. package/src/layer/audio-source.ts +16 -14
  26. package/src/layer/audio.ts +1 -2
  27. package/src/layer/base.ts +26 -7
  28. package/src/layer/visual.ts +5 -6
  29. package/src/movie.ts +41 -49
  30. package/src/util.ts +50 -57
  31. package/docs/effect.js.html +0 -1215
  32. package/docs/event.js.html +0 -145
  33. package/docs/index.html +0 -81
  34. package/docs/index.js.html +0 -92
  35. package/docs/layer.js.html +0 -888
  36. package/docs/module-effect-GaussianBlurComponent.html +0 -345
  37. package/docs/module-effect.Brightness.html +0 -339
  38. package/docs/module-effect.Channels.html +0 -319
  39. package/docs/module-effect.ChromaKey.html +0 -611
  40. package/docs/module-effect.Contrast.html +0 -339
  41. package/docs/module-effect.EllipticalMask.html +0 -200
  42. package/docs/module-effect.GaussianBlur.html +0 -202
  43. package/docs/module-effect.GaussianBlurHorizontal.html +0 -242
  44. package/docs/module-effect.GaussianBlurVertical.html +0 -242
  45. package/docs/module-effect.Pixelate.html +0 -330
  46. package/docs/module-effect.Shader.html +0 -1227
  47. package/docs/module-effect.Stack.html +0 -406
  48. package/docs/module-effect.Transform.Matrix.html +0 -193
  49. package/docs/module-effect.Transform.html +0 -1174
  50. package/docs/module-effect.html +0 -148
  51. package/docs/module-event.html +0 -473
  52. package/docs/module-index.html +0 -186
  53. package/docs/module-layer-Media.html +0 -1116
  54. package/docs/module-layer-MediaMixin.html +0 -164
  55. package/docs/module-layer.Audio.html +0 -1188
  56. package/docs/module-layer.Base.html +0 -629
  57. package/docs/module-layer.Image.html +0 -1421
  58. package/docs/module-layer.Text.html +0 -1731
  59. package/docs/module-layer.Video.html +0 -1938
  60. package/docs/module-layer.Visual.html +0 -1698
  61. package/docs/module-layer.html +0 -137
  62. package/docs/module-movie.html +0 -3118
  63. package/docs/module-util.Color.html +0 -702
  64. package/docs/module-util.Font.html +0 -395
  65. package/docs/module-util.html +0 -845
  66. package/docs/movie.js.html +0 -689
  67. package/docs/scripts/collapse.js +0 -20
  68. package/docs/scripts/linenumber.js +0 -25
  69. package/docs/scripts/nav.js +0 -12
  70. package/docs/scripts/polyfill.js +0 -4
  71. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
  72. package/docs/scripts/prettify/lang-css.js +0 -2
  73. package/docs/scripts/prettify/prettify.js +0 -28
  74. package/docs/scripts/search.js +0 -83
  75. package/docs/styles/jsdoc.css +0 -671
  76. package/docs/styles/prettify.css +0 -79
  77. package/docs/util.js.html +0 -503
  78. package/spec/assets/effect/gaussian-blur-horizontal.png +0 -0
  79. package/spec/assets/effect/gaussian-blur-vertical.png +0 -0
  80. package/spec/assets/effect/grayscale.png +0 -0
  81. package/spec/assets/effect/original.png +0 -0
  82. package/spec/assets/effect/pixelate.png +0 -0
  83. package/spec/assets/effect/transform/multiply.png +0 -0
  84. package/spec/assets/effect/transform/rotate.png +0 -0
  85. package/spec/assets/effect/transform/scale-fraction.png +0 -0
  86. package/spec/assets/effect/transform/scale.png +0 -0
  87. package/spec/assets/effect/transform/translate-fraction.png +0 -0
  88. package/spec/assets/effect/transform/translate.png +0 -0
  89. package/spec/assets/layer/audio.wav +0 -0
  90. package/spec/assets/layer/image.jpg +0 -0
  91. package/spec/effect.spec.js +0 -421
  92. package/spec/event.spec.js +0 -39
  93. package/spec/layer.spec.js +0 -307
  94. package/spec/movie.spec.js +0 -346
  95. package/spec/util.spec.js +0 -294
package/dist/etro-cjs.js CHANGED
@@ -52,14 +52,11 @@ var TypeId = /** @class */ (function () {
52
52
  this._parts = id.split('.');
53
53
  }
54
54
  TypeId.prototype.contains = function (other) {
55
- if (other._parts.length > this._parts.length) {
55
+ if (other._parts.length > this._parts.length)
56
56
  return false;
57
- }
58
- for (var i = 0; i < other._parts.length; i++) {
59
- if (other._parts[i] !== this._parts[i]) {
57
+ for (var i = 0; i < other._parts.length; i++)
58
+ if (other._parts[i] !== this._parts[i])
60
59
  return false;
61
- }
62
- }
63
60
  return true;
64
61
  };
65
62
  TypeId.prototype.toString = function () {
@@ -76,9 +73,8 @@ var TypeId = /** @class */ (function () {
76
73
  * @param listener
77
74
  */
78
75
  function subscribe(target, type, listener) {
79
- if (!listeners.has(target)) {
76
+ if (!listeners.has(target))
80
77
  listeners.set(target, []);
81
- }
82
78
  listeners.get(target).push({ type: new TypeId(type), listener: listener });
83
79
  }
84
80
  /**
@@ -92,9 +88,8 @@ function subscribe(target, type, listener) {
92
88
  function unsubscribe(target, listener) {
93
89
  // Make sure `listener` has been added with `subscribe`.
94
90
  if (!listeners.has(target) ||
95
- !listeners.get(target).map(function (pair) { return pair.listener; }).includes(listener)) {
91
+ !listeners.get(target).map(function (pair) { return pair.listener; }).includes(listener))
96
92
  throw new Error('No matching event listener to remove');
97
- }
98
93
  var removed = listeners.get(target)
99
94
  .filter(function (pair) { return pair.listener !== listener; });
100
95
  listeners.set(target, removed);
@@ -111,17 +106,15 @@ function publish(target, type, event) {
111
106
  event.target = target; // could be a proxy
112
107
  event.type = type;
113
108
  var t = new TypeId(type);
114
- if (!listeners.has(target)) {
109
+ if (!listeners.has(target))
115
110
  // No event fired
116
111
  return null;
117
- }
118
112
  // Call event listeners for this event.
119
113
  var listenersForType = [];
120
114
  for (var i = 0; i < listeners.get(target).length; i++) {
121
115
  var item = listeners.get(target)[i];
122
- if (t.contains(item.type)) {
116
+ if (t.contains(item.type))
123
117
  listenersForType.push(item.listener);
124
- }
125
118
  }
126
119
  for (var i = 0; i < listenersForType.length; i++) {
127
120
  var listener = listenersForType[i];
@@ -149,9 +142,8 @@ var event = /*#__PURE__*/Object.freeze({
149
142
  function getPropertyDescriptor(obj, name) {
150
143
  do {
151
144
  var propDesc = Object.getOwnPropertyDescriptor(obj, name);
152
- if (propDesc) {
145
+ if (propDesc)
153
146
  return propDesc;
154
- }
155
147
  obj = Object.getPrototypeOf(obj);
156
148
  } while (obj);
157
149
  return undefined;
@@ -166,35 +158,30 @@ function getPropertyDescriptor(obj, name) {
166
158
  function applyOptions(options, destObj) {
167
159
  var defaultOptions = destObj.getDefaultOptions();
168
160
  // Validate; make sure `keys` doesn't have any extraneous items
169
- for (var option in options) {
161
+ for (var option in options)
170
162
  // eslint-disable-next-line no-prototype-builtins
171
- if (!defaultOptions.hasOwnProperty(option)) {
163
+ if (!defaultOptions.hasOwnProperty(option))
172
164
  throw new Error("Invalid option: '" + option + "'");
173
- }
174
- }
175
165
  // Merge options and defaultOptions
176
166
  options = __assign(__assign({}, defaultOptions), options);
177
167
  // Copy options
178
168
  for (var option in options) {
179
169
  var propDesc = getPropertyDescriptor(destObj, option);
180
170
  // Update the property as long as the property has not been set (unless if it has a setter)
181
- if (!propDesc || propDesc.set) {
171
+ if (!propDesc || propDesc.set)
182
172
  destObj[option] = options[option];
183
- }
184
173
  }
185
174
  }
186
175
  // This must be cleared at the start of each frame
187
176
  var valCache = new WeakMap();
188
177
  function cacheValue(element, path, value) {
189
178
  // Initiate movie cache
190
- if (!valCache.has(element.movie)) {
179
+ if (!valCache.has(element.movie))
191
180
  valCache.set(element.movie, new WeakMap());
192
- }
193
181
  var movieCache = valCache.get(element.movie);
194
182
  // Iniitate element cache
195
- if (!movieCache.has(element)) {
183
+ if (!movieCache.has(element))
196
184
  movieCache.set(element, {});
197
- }
198
185
  var elementCache = movieCache.get(element);
199
186
  // Cache the value
200
187
  elementCache[path] = value;
@@ -234,16 +221,13 @@ var KeyFrame = /** @class */ (function () {
234
221
  return this;
235
222
  };
236
223
  KeyFrame.prototype.evaluate = function (time) {
237
- if (this.value.length === 0) {
224
+ if (this.value.length === 0)
238
225
  throw new Error('Empty keyframe');
239
- }
240
- if (time === undefined) {
226
+ if (time === undefined)
241
227
  throw new Error('|time| is undefined or null');
242
- }
243
228
  var firstTime = this.value[0][0];
244
- if (time < firstTime) {
229
+ if (time < firstTime)
245
230
  throw new Error('No keyframe point before |time|');
246
- }
247
231
  // I think reduce are slow to do per-frame (or more)?
248
232
  for (var i = 0; i < this.value.length; i++) {
249
233
  var startTime = this.value[i][0];
@@ -252,7 +236,7 @@ var KeyFrame = /** @class */ (function () {
252
236
  if (i + 1 < this.value.length) {
253
237
  var endTime = this.value[i + 1][0];
254
238
  var endValue = this.value[i + 1][1];
255
- if (startTime <= time && time < endTime) {
239
+ if (startTime <= time && time < endTime)
256
240
  // No need for endValue if it is flat interpolation
257
241
  // TODO: support custom interpolation for 'other' types?
258
242
  if (!(typeof startValue === 'number' || typeof endValue === 'object')) {
@@ -268,7 +252,6 @@ var KeyFrame = /** @class */ (function () {
268
252
  endValue, // eslint-disable-line @typescript-eslint/ban-types
269
253
  percentProgress, this.interpolationKeys);
270
254
  }
271
- }
272
255
  }
273
256
  else {
274
257
  // Repeat last value forever
@@ -294,28 +277,23 @@ var KeyFrame = /** @class */ (function () {
294
277
  // TODO: Is this function efficient?
295
278
  // TODO: Update doc @params to allow for keyframes
296
279
  function val(element, path, time) {
297
- if (hasCachedValue(element, path)) {
280
+ if (hasCachedValue(element, path))
298
281
  return getCachedValue(element, path);
299
- }
300
282
  // Get property of element at path
301
283
  var pathParts = path.split('.');
302
284
  var property = element[pathParts.shift()];
303
- while (pathParts.length > 0) {
285
+ while (pathParts.length > 0)
304
286
  property = property[pathParts.shift()];
305
- }
306
287
  // Property filter function
307
288
  var process = element.propertyFilters[path];
308
289
  var value;
309
- if (property instanceof KeyFrame) {
290
+ if (property instanceof KeyFrame)
310
291
  value = property.evaluate(time);
311
- }
312
- else if (typeof property === 'function') {
292
+ else if (typeof property === 'function')
313
293
  value = property(element, time); // TODO? add more args
314
- }
315
- else {
294
+ else
316
295
  // Simple value
317
296
  value = property;
318
- }
319
297
  return cacheValue(element, path, process ? process.call(element, value) : value);
320
298
  }
321
299
  /* export function floorInterp(x1, x2, t, objectKeys) {
@@ -326,18 +304,15 @@ function val(element, path, time) {
326
304
  }, Object.create(Object.getPrototypeOf(x1)));
327
305
  } */
328
306
  function linearInterp(x1, x2, t, objectKeys) {
329
- if (typeof x1 !== typeof x2) {
307
+ if (typeof x1 !== typeof x2)
330
308
  throw new Error('Type mismatch');
331
- }
332
- if (typeof x1 !== 'number' && typeof x1 !== 'object') {
309
+ if (typeof x1 !== 'number' && typeof x1 !== 'object')
333
310
  // Flat interpolation (floor)
334
311
  return x1;
335
- }
336
312
  if (typeof x1 === 'object') { // to work with objects (including arrays)
337
313
  // TODO: make this code DRY
338
- if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2)) {
314
+ if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
339
315
  throw new Error('Prototype mismatch');
340
- }
341
316
  // Preserve prototype of objects
342
317
  var int = Object.create(Object.getPrototypeOf(x1));
343
318
  // Take the intersection of properties
@@ -345,9 +320,8 @@ function linearInterp(x1, x2, t, objectKeys) {
345
320
  for (var i = 0; i < keys.length; i++) {
346
321
  var key = keys[i];
347
322
  // eslint-disable-next-line no-prototype-builtins
348
- if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key)) {
323
+ if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
349
324
  continue;
350
- }
351
325
  int[key] = linearInterp(x1[key], x2[key], t);
352
326
  }
353
327
  return int;
@@ -355,17 +329,14 @@ function linearInterp(x1, x2, t, objectKeys) {
355
329
  return (1 - t) * x1 + t * x2;
356
330
  }
357
331
  function cosineInterp(x1, x2, t, objectKeys) {
358
- if (typeof x1 !== typeof x2) {
332
+ if (typeof x1 !== typeof x2)
359
333
  throw new Error('Type mismatch');
360
- }
361
- if (typeof x1 !== 'number' && typeof x1 !== 'object') {
334
+ if (typeof x1 !== 'number' && typeof x1 !== 'object')
362
335
  // Flat interpolation (floor)
363
336
  return x1;
364
- }
365
337
  if (typeof x1 === 'object' && typeof x2 === 'object') { // to work with objects (including arrays)
366
- if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2)) {
338
+ if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
367
339
  throw new Error('Prototype mismatch');
368
- }
369
340
  // Preserve prototype of objects
370
341
  var int = Object.create(Object.getPrototypeOf(x1));
371
342
  // Take the intersection of properties
@@ -373,9 +344,8 @@ function cosineInterp(x1, x2, t, objectKeys) {
373
344
  for (var i = 0; i < keys.length; i++) {
374
345
  var key = keys[i];
375
346
  // eslint-disable-next-line no-prototype-builtins
376
- if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key)) {
347
+ if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
377
348
  continue;
378
- }
379
349
  int[key] = cosineInterp(x1[key], x2[key], t);
380
350
  }
381
351
  return int;
@@ -505,12 +475,10 @@ function mapPixels(mapper, canvas, ctx, x, y, width, height, flush) {
505
475
  width = width || canvas.width;
506
476
  height = height || canvas.height;
507
477
  var frame = ctx.getImageData(x, y, width, height);
508
- for (var i = 0, l = frame.data.length; i < l; i += 4) {
478
+ for (var i = 0, l = frame.data.length; i < l; i += 4)
509
479
  mapper(frame.data, i);
510
- }
511
- if (flush) {
480
+ if (flush)
512
481
  ctx.putImageData(frame, x, y);
513
- }
514
482
  }
515
483
  /**
516
484
  * <p>Emits "change" event when public properties updated, recursively.
@@ -527,17 +495,17 @@ function watchPublic(target) {
527
495
  // Public API property updated, emit 'modify' event.
528
496
  publish(proxy, target.type + ".change.modify", { property: getPath(receiver, prop), newValue: val });
529
497
  };
530
- var check = function (prop) { return !(prop.startsWith('_') || target.publicExcludes.includes(prop)); };
498
+ var canWatch = function (receiver, prop) { return !prop.startsWith('_') &&
499
+ (target.publicExcludes === undefined || !target.publicExcludes.includes(prop)); };
531
500
  // The path to each child property (each is a unique proxy)
532
501
  var paths = new WeakMap();
533
502
  var handler = {
534
503
  set: function (obj, prop, val, receiver) {
535
504
  // Recurse
536
- if (typeof val === 'object' && val !== null && !paths.has(val) && check(prop)) {
505
+ if (typeof val === 'object' && val !== null && !paths.has(val) && canWatch(receiver, prop)) {
537
506
  val = new Proxy(val, handler);
538
507
  paths.set(val, getPath(receiver, prop));
539
508
  }
540
- var was = prop in obj;
541
509
  // Set property or attribute
542
510
  // Search prototype chain for the closest setter
543
511
  var objProto = obj;
@@ -549,15 +517,12 @@ function watchPublic(target) {
549
517
  break;
550
518
  }
551
519
  }
552
- if (!objProto) {
520
+ if (!objProto)
553
521
  // Couldn't find setter; set value on instance
554
522
  obj[prop] = val;
555
- }
556
- // Check if it already existed and if it's a valid property to watch, if
557
- // on root object.
558
- if (obj !== target || (was && check(prop))) {
523
+ // Check if the property isn't blacklisted in publicExcludes.
524
+ if (canWatch(receiver, prop))
559
525
  callback(prop, val, receiver);
560
- }
561
526
  return true;
562
527
  }
563
528
  };
@@ -597,23 +562,20 @@ function AudioSourceMixin(superclass) {
597
562
  applyOptions(options, _this);
598
563
  var load = function () {
599
564
  // TODO: && ?
600
- if ((options.duration || (_this.source.duration - _this.sourceStartTime)) < 0) {
565
+ if ((options.duration || (_this.source.duration - _this.sourceStartTime)) < 0)
601
566
  throw new Error('Invalid options.duration or options.sourceStartTime');
602
- }
603
567
  _this._unstretchedDuration = options.duration || (_this.source.duration - _this.sourceStartTime);
604
568
  _this.duration = _this._unstretchedDuration / (_this.playbackRate);
605
569
  // onload will use `this`, and can't bind itself because it's before
606
570
  // super()
607
571
  onload && onload.bind(_this)(_this.source, options);
608
572
  };
609
- if (_this.source.readyState >= 2) {
573
+ if (_this.source.readyState >= 2)
610
574
  // this frame's data is available now
611
575
  load();
612
- }
613
- else {
576
+ else
614
577
  // when this frame's data is available
615
578
  _this.source.addEventListener('loadedmetadata', load);
616
- }
617
579
  _this.source.addEventListener('durationchange', function () {
618
580
  _this.duration = options.duration || (_this.source.duration - _this.sourceStartTime);
619
581
  });
@@ -623,11 +585,9 @@ function AudioSourceMixin(superclass) {
623
585
  var _this = this;
624
586
  _super.prototype.attach.call(this, movie);
625
587
  subscribe(movie, 'movie.seek', function () {
626
- var time = movie.currentTime;
627
- if (time < _this.startTime || time >= _this.startTime + _this.duration) {
588
+ if (_this.currentTime < 0 || _this.currentTime >= _this.duration)
628
589
  return;
629
- }
630
- _this.source.currentTime = time - _this.startTime;
590
+ _this.source.currentTime = _this.currentTime + _this.sourceStartTime;
631
591
  });
632
592
  // TODO: on unattach?
633
593
  subscribe(movie, 'movie.audiodestinationupdate', function (event) {
@@ -639,7 +599,7 @@ function AudioSourceMixin(superclass) {
639
599
  }
640
600
  });
641
601
  // connect to audiocontext
642
- this._audioNode = movie.actx.createMediaElementSource(this.source);
602
+ this._audioNode = this.audioNode || movie.actx.createMediaElementSource(this.source);
643
603
  // Spy on connect and disconnect to remember if it connected to
644
604
  // actx.destination (for Movie#record).
645
605
  var oldConnect = this._audioNode.connect.bind(this.audioNode);
@@ -650,14 +610,16 @@ function AudioSourceMixin(superclass) {
650
610
  var oldDisconnect = this._audioNode.disconnect.bind(this.audioNode);
651
611
  this._audioNode.disconnect = function (destination, output, input) {
652
612
  if (_this._connectedToDestination &&
653
- destination === movie.actx.destination) {
613
+ destination === movie.actx.destination)
654
614
  _this._connectedToDestination = false;
655
- }
656
615
  return oldDisconnect(destination, output, input);
657
616
  };
658
617
  // Connect to actx.destination by default (can be rewired by user)
659
618
  this.audioNode.connect(movie.actx.destination);
660
619
  };
620
+ MixedAudioSource.prototype.detach = function () {
621
+ this.audioNode.disconnect(this.movie.actx.destination);
622
+ };
661
623
  MixedAudioSource.prototype.start = function () {
662
624
  this.source.currentTime = this.currentTime + this.sourceStartTime;
663
625
  this.source.play();
@@ -689,9 +651,8 @@ function AudioSourceMixin(superclass) {
689
651
  },
690
652
  set: function (value) {
691
653
  this._playbackRate = value;
692
- if (this._unstretchedDuration !== undefined) {
654
+ if (this._unstretchedDuration !== undefined)
693
655
  this.duration = this._unstretchedDuration / value;
694
- }
695
656
  },
696
657
  enumerable: false,
697
658
  configurable: true
@@ -771,20 +732,36 @@ var Base = /** @class */ (function () {
771
732
  });
772
733
  return newThis;
773
734
  }
774
- Base.prototype.attach = function (movie) {
735
+ /**
736
+ * Attaches this layer to `movie` if not already attached.
737
+ * @ignore
738
+ */
739
+ Base.prototype.tryAttach = function (movie) {
740
+ if (this._occurrenceCount === 0)
741
+ this.attach(movie);
775
742
  this._occurrenceCount++;
743
+ };
744
+ Base.prototype.attach = function (movie) {
776
745
  this._movie = movie;
777
746
  };
778
- Base.prototype.detach = function () {
779
- if (this.movie === null) {
747
+ /**
748
+ * Dettaches this layer from its movie if the number of times `tryDetach` has
749
+ * been called (including this call) equals the number of times `tryAttach`
750
+ * has been called.
751
+ *
752
+ * @ignore
753
+ */
754
+ Base.prototype.tryDetach = function () {
755
+ if (this.movie === null)
780
756
  throw new Error('No movie to detach from');
781
- }
782
757
  this._occurrenceCount--;
783
758
  // If this layer occurs in another place in a `layers` array, do not unset
784
759
  // _movie. (For calling `unshift` on the `layers` proxy)
785
- if (this._occurrenceCount === 0) {
786
- this._movie = null;
787
- }
760
+ if (this._occurrenceCount === 0)
761
+ this.detach();
762
+ };
763
+ Base.prototype.detach = function () {
764
+ this._movie = null;
788
765
  };
789
766
  /**
790
767
  * Called when the layer is activated
@@ -873,9 +850,8 @@ var Audio = /** @class */ (function (_super) {
873
850
  */
874
851
  function Audio(options) {
875
852
  var _this = _super.call(this, options) || this;
876
- if (_this.duration === undefined) {
853
+ if (_this.duration === undefined)
877
854
  _this.duration = (_this).source.duration - _this.sourceStartTime;
878
- }
879
855
  return _this;
880
856
  }
881
857
  Audio.prototype.getDefaultOptions = function () {
@@ -913,9 +889,8 @@ var Visual = /** @class */ (function (_super) {
913
889
  set: function (target, property, value) {
914
890
  if (!isNaN(Number(property))) {
915
891
  // The property is a number (index)
916
- if (target[property]) {
892
+ if (target[property])
917
893
  target[property].detach();
918
- }
919
894
  value.attach(_this);
920
895
  }
921
896
  target[property] = value;
@@ -958,18 +933,16 @@ var Visual = /** @class */ (function (_super) {
958
933
  Visual.prototype.endRender = function () {
959
934
  var w = val(this, 'width', this.currentTime) || val(this.movie, 'width', this.movie.currentTime);
960
935
  var h = val(this, 'height', this.currentTime) || val(this.movie, 'height', this.movie.currentTime);
961
- if (w * h > 0) {
936
+ if (w * h > 0)
962
937
  this._applyEffects();
963
- }
964
938
  // else InvalidStateError for drawing zero-area image in some effects, right?
965
939
  };
966
940
  Visual.prototype._applyEffects = function () {
967
941
  for (var i = 0; i < this.effects.length; i++) {
968
942
  var effect = this.effects[i];
969
- if (effect.enabled) {
943
+ if (effect.enabled)
970
944
  // Pass relative time
971
945
  effect.apply(this, this.movie.currentTime - this.startTime);
972
- }
973
946
  }
974
947
  };
975
948
  /**
@@ -1213,28 +1186,43 @@ var Base$1 = /** @class */ (function () {
1213
1186
  newThis._target = null;
1214
1187
  // Propogate up to target
1215
1188
  subscribe(newThis, 'effect.change.modify', function (event) {
1216
- if (!newThis._target) {
1189
+ if (!newThis._target)
1217
1190
  return;
1218
- }
1219
1191
  var type = newThis._target.type + ".change.effect.modify";
1220
1192
  publish(newThis._target, type, __assign(__assign({}, event), { target: newThis._target, source: newThis, type: type }));
1221
1193
  });
1222
1194
  return newThis;
1223
1195
  }
1224
- Base.prototype.attach = function (target) {
1196
+ /**
1197
+ * Attaches this effect to `target` if not already attached.
1198
+ * @ignore
1199
+ */
1200
+ Base.prototype.tryAttach = function (target) {
1201
+ if (this._occurrenceCount === 0)
1202
+ this.attach(target);
1225
1203
  this._occurrenceCount++;
1226
- this._target = target;
1227
1204
  };
1228
- Base.prototype.detach = function () {
1229
- if (this._target === null) {
1205
+ Base.prototype.attach = function (movie) {
1206
+ this._target = movie;
1207
+ };
1208
+ /**
1209
+ * Dettaches this effect from its target if the number of times `tryDetach`
1210
+ * has been called (including this call) equals the number of times
1211
+ * `tryAttach` has been called.
1212
+ *
1213
+ * @ignore
1214
+ */
1215
+ Base.prototype.tryDetach = function () {
1216
+ if (this._target === null)
1230
1217
  throw new Error('No movie to detach from');
1231
- }
1232
1218
  this._occurrenceCount--;
1233
1219
  // If this effect occurs in another place in the containing array, do not
1234
1220
  // unset _target. (For calling `unshift` on the `layers` proxy)
1235
- if (this._occurrenceCount === 0) {
1236
- this._target = null;
1237
- }
1221
+ if (this._occurrenceCount === 0)
1222
+ this.detach();
1223
+ };
1224
+ Base.prototype.detach = function () {
1225
+ this._target = null;
1238
1226
  };
1239
1227
  // subclasses must implement apply
1240
1228
  /**
@@ -1314,18 +1302,16 @@ var Shader = /** @class */ (function (_super) {
1314
1302
  Shader.prototype._initGl = function () {
1315
1303
  this._canvas = document.createElement('canvas');
1316
1304
  var gl = this._canvas.getContext('webgl');
1317
- if (gl === null) {
1305
+ if (gl === null)
1318
1306
  throw new Error('Unable to initialize WebGL. Your browser or machine may not support it.');
1319
- }
1320
1307
  this._gl = gl;
1321
1308
  return gl;
1322
1309
  };
1323
1310
  Shader.prototype._initTextures = function (userUniforms, userTextures, sourceTextureOptions) {
1324
1311
  var gl = this._gl;
1325
1312
  var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
1326
- if (userTextures.length > maxTextures) {
1313
+ if (userTextures.length > maxTextures)
1327
1314
  console.warn('Too many textures!');
1328
- }
1329
1315
  this._userTextures = {};
1330
1316
  for (var name_1 in userTextures) {
1331
1317
  var userOptions = userTextures[name_1];
@@ -1338,9 +1324,8 @@ var Shader = /** @class */ (function (_super) {
1338
1324
  * textures, without having to define multiple properties in the effect
1339
1325
  * object.
1340
1326
  */
1341
- if (userUniforms[name_1]) {
1327
+ if (userUniforms[name_1])
1342
1328
  throw new Error("Texture - uniform naming conflict: " + name_1 + "!");
1343
- }
1344
1329
  // Add this as a "user uniform".
1345
1330
  userUniforms[name_1] = '1i'; // texture pointer
1346
1331
  }
@@ -1478,13 +1463,11 @@ var Shader = /** @class */ (function (_super) {
1478
1463
  // Set the shader uniforms.
1479
1464
  // Tell the shader we bound the texture to texture unit 0.
1480
1465
  // All base (Shader class) uniforms are optional.
1481
- if (this._uniformLocations.source) {
1466
+ if (this._uniformLocations.source)
1482
1467
  gl.uniform1i(this._uniformLocations.source, 0);
1483
- }
1484
1468
  // All base (Shader class) uniforms are optional.
1485
- if (this._uniformLocations.size) {
1469
+ if (this._uniformLocations.size)
1486
1470
  gl.uniform2iv(this._uniformLocations.size, [target.canvas.width, target.canvas.height]);
1487
- }
1488
1471
  for (var unprefixed in this._userUniforms) {
1489
1472
  var options = this._userUniforms[unprefixed];
1490
1473
  var value = val(this, unprefixed, reltime);
@@ -1535,40 +1518,35 @@ var Shader = /** @class */ (function (_super) {
1535
1518
  var i = 0;
1536
1519
  for (var name_4 in this._userTextures) {
1537
1520
  var testValue = val(this, name_4, reltime);
1538
- if (value === testValue) {
1521
+ if (value === testValue)
1539
1522
  value = Shader.INTERNAL_TEXTURE_UNITS + i; // after the internal texture units
1540
- }
1541
1523
  i++;
1542
1524
  }
1543
1525
  }
1544
1526
  if (outputType === '3fv') {
1545
1527
  // allow 4-component vectors; TODO: why?
1546
- if (Array.isArray(value) && (value.length === 3 || value.length === 4)) {
1528
+ if (Array.isArray(value) && (value.length === 3 || value.length === 4))
1547
1529
  return value;
1548
- }
1549
1530
  // kind of loose so this can be changed if needed
1550
- if (typeof value === 'object') {
1531
+ if (typeof value === 'object')
1551
1532
  return [
1552
1533
  value.r !== undefined ? value.r : def,
1553
1534
  value.g !== undefined ? value.g : def,
1554
1535
  value.b !== undefined ? value.b : def
1555
1536
  ];
1556
- }
1557
1537
  throw new Error("Invalid type: " + outputType + " or value: " + value);
1558
1538
  }
1559
1539
  if (outputType === '4fv') {
1560
- if (Array.isArray(value) && value.length === 4) {
1540
+ if (Array.isArray(value) && value.length === 4)
1561
1541
  return value;
1562
- }
1563
1542
  // kind of loose so this can be changed if needed
1564
- if (typeof value === 'object') {
1543
+ if (typeof value === 'object')
1565
1544
  return [
1566
1545
  value.r !== undefined ? value.r : def,
1567
1546
  value.g !== undefined ? value.g : def,
1568
1547
  value.b !== undefined ? value.b : def,
1569
1548
  value.a !== undefined ? value.a : def
1570
1549
  ];
1571
- }
1572
1550
  throw new Error("Invalid type: " + outputType + " or value: " + value);
1573
1551
  }
1574
1552
  return value;
@@ -1662,9 +1640,8 @@ var Shader = /** @class */ (function (_super) {
1662
1640
  else {
1663
1641
  // No, it's not a power of 2. Turn off mips and set
1664
1642
  // wrapping to clamp to edge
1665
- if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE) {
1643
+ if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE)
1666
1644
  console.warn('Wrap mode is not CLAMP_TO_EDGE for a non-power-of-two texture. Defaulting to CLAMP_TO_EDGE');
1667
- }
1668
1645
  gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1669
1646
  gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1670
1647
  }
@@ -1900,6 +1877,7 @@ var Stack = /** @class */ (function (_super) {
1900
1877
  function Stack(options) {
1901
1878
  var _this = _super.call(this) || this;
1902
1879
  _this._effectsBack = [];
1880
+ // TODO: Throw 'change' events in handlers
1903
1881
  _this.effects = new Proxy(_this._effectsBack, {
1904
1882
  deleteProperty: function (target, property) {
1905
1883
  var value = target[property];
@@ -1910,9 +1888,8 @@ var Stack = /** @class */ (function (_super) {
1910
1888
  set: function (target, property, value) {
1911
1889
  // TODO: make sure type check works
1912
1890
  if (!isNaN(Number(property))) { // if property is a number (index)
1913
- if (target[property]) {
1891
+ if (target[property])
1914
1892
  target[property].detach(); // Detach old effect from movie
1915
- }
1916
1893
  value.attach(this._target); // Attach effect to movie
1917
1894
  }
1918
1895
  target[property] = value;
@@ -1921,6 +1898,7 @@ var Stack = /** @class */ (function (_super) {
1921
1898
  });
1922
1899
  options.effects.forEach(function (effect) { return _this.effects.push(effect); });
1923
1900
  return _this;
1901
+ // TODO: Propogate 'change' events from children up
1924
1902
  }
1925
1903
  Stack.prototype.attach = function (movie) {
1926
1904
  _super.prototype.attach.call(this, movie);
@@ -2001,10 +1979,9 @@ var GaussianBlurComponent = /** @class */ (function (_super) {
2001
1979
  }
2002
1980
  GaussianBlurComponent.prototype.apply = function (target, reltime) {
2003
1981
  var radiusVal = val(this, 'radius', reltime);
2004
- if (radiusVal !== this._radiusCache) {
1982
+ if (radiusVal !== this._radiusCache)
2005
1983
  // Regenerate gaussian distribution canvas.
2006
1984
  this.shape = GaussianBlurComponent._render1DKernel(GaussianBlurComponent._gen1DKernel(radiusVal));
2007
- }
2008
1985
  this._radiusCache = radiusVal;
2009
1986
  _super.prototype.apply.call(this, target, reltime);
2010
1987
  };
@@ -2037,27 +2014,23 @@ var GaussianBlurComponent = /** @class */ (function (_super) {
2037
2014
  var pascal = GaussianBlurComponent._genPascalRow(2 * radius + 1);
2038
2015
  // don't use `reduce` and `map` (overhead?)
2039
2016
  var sum = 0;
2040
- for (var i = 0; i < pascal.length; i++) {
2017
+ for (var i = 0; i < pascal.length; i++)
2041
2018
  sum += pascal[i];
2042
- }
2043
- for (var i = 0; i < pascal.length; i++) {
2019
+ for (var i = 0; i < pascal.length; i++)
2044
2020
  pascal[i] /= sum;
2045
- }
2046
2021
  return pascal;
2047
2022
  };
2048
2023
  GaussianBlurComponent._genPascalRow = function (index) {
2049
- if (index < 0) {
2024
+ if (index < 0)
2050
2025
  throw new Error("Invalid index " + index);
2051
- }
2052
2026
  var currRow = [1];
2053
2027
  for (var i = 1; i < index; i++) {
2054
2028
  var nextRow = [];
2055
2029
  nextRow.length = currRow.length + 1;
2056
2030
  // edges are always 1's
2057
2031
  nextRow[0] = nextRow[nextRow.length - 1] = 1;
2058
- for (var j = 1; j < nextRow.length - 1; j++) {
2032
+ for (var j = 1; j < nextRow.length - 1; j++)
2059
2033
  nextRow[j] = currRow[j - 1] + currRow[j];
2060
- }
2061
2034
  currRow = nextRow;
2062
2035
  }
2063
2036
  return currRow;
@@ -2135,9 +2108,8 @@ var Pixelate = /** @class */ (function (_super) {
2135
2108
  }
2136
2109
  Pixelate.prototype.apply = function (target, reltime) {
2137
2110
  var ps = val(this, 'pixelSize', reltime);
2138
- if (ps % 1 !== 0 || ps < 0) {
2111
+ if (ps % 1 !== 0 || ps < 0)
2139
2112
  throw new Error('Pixel size must be a nonnegative integer');
2140
- }
2141
2113
  _super.prototype.apply.call(this, target, reltime);
2142
2114
  };
2143
2115
  return Pixelate;
@@ -2166,12 +2138,10 @@ var Transform = /** @class */ (function (_super) {
2166
2138
  return _this;
2167
2139
  }
2168
2140
  Transform.prototype.apply = function (target, reltime) {
2169
- if (target.canvas.width !== this._tmpCanvas.width) {
2141
+ if (target.canvas.width !== this._tmpCanvas.width)
2170
2142
  this._tmpCanvas.width = target.canvas.width;
2171
- }
2172
- if (target.canvas.height !== this._tmpCanvas.height) {
2143
+ if (target.canvas.height !== this._tmpCanvas.height)
2173
2144
  this._tmpCanvas.height = target.canvas.height;
2174
- }
2175
2145
  // Use data, since that's the underlying storage
2176
2146
  this._tmpMatrix.data = val(this, 'matrix.data', reltime);
2177
2147
  this._tmpCtx.setTransform(this._tmpMatrix.a, this._tmpMatrix.b, this._tmpMatrix.c, this._tmpMatrix.d, this._tmpMatrix.e, this._tmpMatrix.f);
@@ -2197,9 +2167,8 @@ var Transform = /** @class */ (function (_super) {
2197
2167
  ];
2198
2168
  }
2199
2169
  Matrix.prototype.identity = function () {
2200
- for (var i = 0; i < this.data.length; i++) {
2170
+ for (var i = 0; i < this.data.length; i++)
2201
2171
  this.data[i] = Matrix.IDENTITY.data[i];
2202
- }
2203
2172
  return this;
2204
2173
  };
2205
2174
  /**
@@ -2208,9 +2177,8 @@ var Transform = /** @class */ (function (_super) {
2208
2177
  * @param [val]
2209
2178
  */
2210
2179
  Matrix.prototype.cell = function (x, y, val) {
2211
- if (val !== undefined) {
2180
+ if (val !== undefined)
2212
2181
  this.data[3 * y + x] = val;
2213
- }
2214
2182
  return this.data[3 * y + x];
2215
2183
  };
2216
2184
  Object.defineProperty(Matrix.prototype, "a", {
@@ -2262,19 +2230,16 @@ var Transform = /** @class */ (function (_super) {
2262
2230
  */
2263
2231
  Matrix.prototype.multiply = function (other) {
2264
2232
  // copy to temporary matrix to avoid modifying `this` while reading from it
2265
- for (var x = 0; x < 3; x++) {
2233
+ for (var x = 0; x < 3; x++)
2266
2234
  for (var y = 0; y < 3; y++) {
2267
2235
  var sum = 0;
2268
- for (var i = 0; i < 3; i++) {
2236
+ for (var i = 0; i < 3; i++)
2269
2237
  sum += this.cell(x, i) * other.cell(i, y);
2270
- }
2271
2238
  Matrix._TMP_MATRIX.cell(x, y, sum);
2272
2239
  }
2273
- }
2274
2240
  // copy data from TMP_MATRIX to this
2275
- for (var i = 0; i < Matrix._TMP_MATRIX.data.length; i++) {
2241
+ for (var i = 0; i < Matrix._TMP_MATRIX.data.length; i++)
2276
2242
  this.data[i] = Matrix._TMP_MATRIX.data[i];
2277
- }
2278
2243
  return this;
2279
2244
  };
2280
2245
  /**
@@ -8804,7 +8769,7 @@ var Movie = /** @class */ (function () {
8804
8769
  // Refresh screen when effect is removed, if the movie isn't playing
8805
8770
  // already.
8806
8771
  var value = target[property];
8807
- value.detach();
8772
+ value.tryDetach();
8808
8773
  delete target[property];
8809
8774
  publish(that, 'movie.change.effect.remove', { effect: value });
8810
8775
  return true;
@@ -8816,10 +8781,10 @@ var Movie = /** @class */ (function () {
8816
8781
  publish(that, 'movie.change.effect.remove', {
8817
8782
  effect: target[property]
8818
8783
  });
8819
- target[property].detach();
8784
+ target[property].tryDetach();
8820
8785
  }
8821
8786
  // Attach effect to movie
8822
- value.attach(that);
8787
+ value.tryAttach(that);
8823
8788
  target[property] = value;
8824
8789
  // Refresh screen when effect is set, if the movie isn't playing
8825
8790
  // already.
@@ -8836,12 +8801,11 @@ var Movie = /** @class */ (function () {
8836
8801
  deleteProperty: function (target, property) {
8837
8802
  var oldDuration = this.duration;
8838
8803
  var value = target[property];
8839
- value.detach(that);
8804
+ value.tryDetach(that);
8840
8805
  delete target[property];
8841
8806
  var current = that.currentTime >= value.startTime && that.currentTime < value.startTime + value.duration;
8842
- if (current) {
8807
+ if (current)
8843
8808
  publish(that, 'movie.change.layer.remove', { layer: value });
8844
- }
8845
8809
  publish(that, 'movie.change.duration', { oldDuration: oldDuration });
8846
8810
  return true;
8847
8811
  },
@@ -8853,16 +8817,15 @@ var Movie = /** @class */ (function () {
8853
8817
  publish(that, 'movie.change.layer.remove', {
8854
8818
  layer: target[property]
8855
8819
  });
8856
- target[property].detach();
8820
+ target[property].tryDetach();
8857
8821
  }
8858
8822
  // Attach layer to movie
8859
- value.attach(that);
8823
+ value.tryAttach(that);
8860
8824
  target[property] = value;
8861
8825
  // Refresh screen when a relevant layer is added or removed
8862
8826
  var current = that.currentTime >= value.startTime && that.currentTime < value.startTime + value.duration;
8863
- if (current) {
8827
+ if (current)
8864
8828
  publish(that, 'movie.change.layer.add', { layer: value });
8865
- }
8866
8829
  publish(that, 'movie.change.duration', { oldDuration: oldDuration });
8867
8830
  }
8868
8831
  else {
@@ -8886,14 +8849,12 @@ var Movie = /** @class */ (function () {
8886
8849
  this._lastPlayedOffset = -1;
8887
8850
  // newThis._updateInterval = 0.1; // time in seconds between each "timeupdate" event
8888
8851
  // newThis._lastUpdate = -1;
8889
- if (newThis.autoRefresh) {
8852
+ if (newThis.autoRefresh)
8890
8853
  newThis.refresh(); // render single frame on creation
8891
- }
8892
8854
  // Subscribe to own event "change" (child events propogate up)
8893
8855
  subscribe(newThis, 'movie.change', function () {
8894
- if (newThis.autoRefresh && !newThis.rendering) {
8856
+ if (newThis.autoRefresh && !newThis.rendering)
8895
8857
  newThis.refresh();
8896
- }
8897
8858
  });
8898
8859
  // Subscribe to own event "ended"
8899
8860
  subscribe(newThis, 'movie.recordended', function () {
@@ -8911,16 +8872,14 @@ var Movie = /** @class */ (function () {
8911
8872
  Movie.prototype.play = function () {
8912
8873
  var _this = this;
8913
8874
  return new Promise(function (resolve) {
8914
- if (!_this.paused) {
8875
+ if (!_this.paused)
8915
8876
  throw new Error('Already playing');
8916
- }
8917
8877
  _this._paused = _this._ended = false;
8918
8878
  _this._lastPlayed = performance.now();
8919
8879
  _this._lastPlayedOffset = _this.currentTime;
8920
- if (!_this.renderingFrame) {
8880
+ if (!_this.renderingFrame)
8921
8881
  // Not rendering (and not playing), so play.
8922
8882
  _this._render(true, undefined, resolve);
8923
- }
8924
8883
  // Stop rendering frame if currently doing so, because playing has higher
8925
8884
  // priority. This will effect the next _render call.
8926
8885
  _this._renderingFrame = false;
@@ -8944,12 +8903,10 @@ var Movie = /** @class */ (function () {
8944
8903
  // TODO: improve recording performance to increase frame rate?
8945
8904
  Movie.prototype.record = function (options) {
8946
8905
  var _this = this;
8947
- if (options.video === false && options.audio === false) {
8906
+ if (options.video === false && options.audio === false)
8948
8907
  throw new Error('Both video and audio cannot be disabled');
8949
- }
8950
- if (!this.paused) {
8908
+ if (!this.paused)
8951
8909
  throw new Error('Cannot record movie while already playing or recording');
8952
- }
8953
8910
  return new Promise(function (resolve, reject) {
8954
8911
  var canvasCache = _this.canvas;
8955
8912
  // Record on a temporary canvas context
@@ -8980,9 +8937,8 @@ var Movie = /** @class */ (function () {
8980
8937
  var mediaRecorder = new MediaRecorder(stream, options.mediaRecorderOptions);
8981
8938
  mediaRecorder.ondataavailable = function (event) {
8982
8939
  // if (this._paused) reject(new Error("Recording was interrupted"));
8983
- if (event.data.size > 0) {
8940
+ if (event.data.size > 0)
8984
8941
  recordedChunks.push(event.data);
8985
- }
8986
8942
  };
8987
8943
  // TODO: publish to movie, not layers
8988
8944
  mediaRecorder.onstop = function () {
@@ -9041,17 +8997,15 @@ var Movie = /** @class */ (function () {
9041
8997
  if (!this.rendering) {
9042
8998
  // (!this.paused || this._renderingFrame) is true so it's playing or it's
9043
8999
  // rendering a single frame.
9044
- if (done) {
9000
+ if (done)
9045
9001
  done();
9046
- }
9047
9002
  return;
9048
9003
  }
9049
9004
  this._updateCurrentTime(timestamp);
9050
9005
  var recordingEnd = this.recording ? this._recordEndTime : this.duration;
9051
9006
  var recordingEnded = this.currentTime > recordingEnd;
9052
- if (recordingEnded) {
9007
+ if (recordingEnded)
9053
9008
  publish(this, 'movie.recordended', { movie: this });
9054
- }
9055
9009
  // Bad for performance? (remember, it's calling Array.reduce)
9056
9010
  var end = this.duration;
9057
9011
  var ended = this.currentTime > end;
@@ -9070,9 +9024,8 @@ var Movie = /** @class */ (function () {
9070
9024
  var layer = this.layers[i];
9071
9025
  // A layer that has been deleted before layers.length has been updated
9072
9026
  // (see the layers proxy in the constructor).
9073
- if (!layer) {
9027
+ if (!layer)
9074
9028
  continue;
9075
- }
9076
9029
  layer.stop();
9077
9030
  layer.active = false;
9078
9031
  }
@@ -9080,27 +9033,24 @@ var Movie = /** @class */ (function () {
9080
9033
  }
9081
9034
  // Stop playback or recording if done
9082
9035
  if (recordingEnded || (ended && !this.repeat)) {
9083
- if (done) {
9036
+ if (done)
9084
9037
  done();
9085
- }
9086
9038
  return;
9087
9039
  }
9088
9040
  // Do render
9089
9041
  this._renderBackground(timestamp);
9090
9042
  var frameFullyLoaded = this._renderLayers();
9091
9043
  this._applyEffects();
9092
- if (frameFullyLoaded) {
9044
+ if (frameFullyLoaded)
9093
9045
  publish(this, 'movie.loadeddata', { movie: this });
9094
- }
9095
9046
  // If didn't load in this instant, repeatedly frame-render until frame is
9096
9047
  // loaded.
9097
9048
  // If the expression below is false, don't publish an event, just silently
9098
9049
  // stop render loop.
9099
9050
  if (!repeat || (this._renderingFrame && frameFullyLoaded)) {
9100
9051
  this._renderingFrame = false;
9101
- if (done) {
9052
+ if (done)
9102
9053
  done();
9103
- }
9104
9054
  return;
9105
9055
  }
9106
9056
  window.requestAnimationFrame(function (timestamp) {
@@ -9138,9 +9088,8 @@ var Movie = /** @class */ (function () {
9138
9088
  var layer = this.layers[i];
9139
9089
  // A layer that has been deleted before layers.length has been updated
9140
9090
  // (see the layers proxy in the constructor).
9141
- if (!layer) {
9091
+ if (!layer)
9142
9092
  continue;
9143
- }
9144
9093
  var reltime = this.currentTime - layer.startTime;
9145
9094
  // Cancel operation if layer disabled or outside layer time interval
9146
9095
  if (!val(layer, 'enabled', reltime) ||
@@ -9162,18 +9111,16 @@ var Movie = /** @class */ (function () {
9162
9111
  layer.active = true;
9163
9112
  }
9164
9113
  // if the layer has an input file
9165
- if ('source' in layer) {
9114
+ if ('source' in layer)
9166
9115
  frameFullyLoaded = frameFullyLoaded && layer.source.readyState >= 2;
9167
- }
9168
9116
  layer.render();
9169
9117
  // if the layer has visual component
9170
9118
  if (layer instanceof Visual) {
9171
9119
  var canvas = layer.canvas;
9172
9120
  // layer.canvas.width and layer.canvas.height should already be interpolated
9173
9121
  // if the layer has an area (else InvalidStateError from canvas)
9174
- if (canvas.width * canvas.height > 0) {
9122
+ if (canvas.width * canvas.height > 0)
9175
9123
  this.cctx.drawImage(canvas, val(layer, 'x', reltime), val(layer, 'y', reltime), canvas.width, canvas.height);
9176
- }
9177
9124
  }
9178
9125
  }
9179
9126
  return frameFullyLoaded;
@@ -9183,9 +9130,8 @@ var Movie = /** @class */ (function () {
9183
9130
  var effect = this.effects[i];
9184
9131
  // An effect that has been deleted before effects.length has been updated
9185
9132
  // (see the effectsproxy in the constructor).
9186
- if (!effect) {
9133
+ if (!effect)
9187
9134
  continue;
9188
- }
9189
9135
  effect.apply(this, this.currentTime);
9190
9136
  }
9191
9137
  };
@@ -9204,9 +9150,8 @@ var Movie = /** @class */ (function () {
9204
9150
  * Convienence method
9205
9151
  */
9206
9152
  Movie.prototype._publishToLayers = function (type, event) {
9207
- for (var i = 0; i < this.layers.length; i++) {
9153
+ for (var i = 0; i < this.layers.length; i++)
9208
9154
  publish(this.layers[i], type, event);
9209
- }
9210
9155
  };
9211
9156
  Object.defineProperty(Movie.prototype, "rendering", {
9212
9157
  /**
@@ -9319,13 +9264,11 @@ var Movie = /** @class */ (function () {
9319
9264
  return new Promise(function (resolve, reject) {
9320
9265
  _this._currentTime = time;
9321
9266
  publish(_this, 'movie.seek', {});
9322
- if (refresh) {
9267
+ if (refresh)
9323
9268
  // Pass promise callbacks to `refresh`
9324
9269
  _this.refresh().then(resolve).catch(reject);
9325
- }
9326
- else {
9270
+ else
9327
9271
  resolve();
9328
- }
9329
9272
  });
9330
9273
  };
9331
9274
  Object.defineProperty(Movie.prototype, "canvas", {