etro 0.8.5 → 0.9.0
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/.github/workflows/nodejs.yml +1 -1
- package/CHANGELOG.md +20 -0
- package/CONTRIBUTING.md +9 -10
- package/README.md +3 -1
- package/dist/effect/base.d.ts +5 -5
- package/dist/effect/visual.d.ts +11 -0
- package/dist/etro-cjs.js +50 -28
- package/dist/etro-iife.js +50 -28
- package/dist/layer/image.d.ts +2 -2
- package/dist/movie.d.ts +10 -1
- package/dist/util.d.ts +2 -0
- package/karma.conf.js +11 -1
- package/package.json +3 -3
- package/private-todo.txt +70 -0
- package/src/effect/base.ts +6 -6
- package/src/effect/visual.ts +16 -1
- package/src/layer/audio-source.ts +4 -1
- package/src/layer/base.ts +1 -1
- package/src/layer/image.ts +3 -3
- package/src/movie.ts +43 -27
- package/src/util.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [0.9.0] - 2022-07-17
|
|
9
|
+
### Changed
|
|
10
|
+
- Methods in the `Base` effect now accept `Base` layers instead of `Visual` layers.
|
|
11
|
+
|
|
12
|
+
### Deprecated
|
|
13
|
+
- `autoRefresh` option ([#130](https://github.com/etro-js/etro/issues/130)).
|
|
14
|
+
- `publicExcludes` ([#130](https://github.com/etro-js/etro/issues/130)).
|
|
15
|
+
- All `change` events ([#130](https://github.com/etro-js/etro/issues/130)).
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Layers no longer trigger infinite loops when their active states change ([#127](https://github.com/etro-js/etro/issues/127)).
|
|
19
|
+
- Add missing `VisualSource` options to `Image` layer ([#128](https://github.com/etro-js/etro/pull/128)).
|
|
20
|
+
- Layers are now stopped when recording ends.
|
|
21
|
+
- `stop()` is no longer called on inactive layers.
|
|
22
|
+
- Movies no longer publish `'movie.ended'` when done recording.
|
|
23
|
+
- `Audio` and `Video` layers not detaching properly.
|
|
24
|
+
- When done playing or recording, movies only reset their time if they're in repeat mode.
|
|
25
|
+
- The `timeupdate` event is no longer fired when `currentTime` remains the same (due to `performance.now()` rounding).
|
|
26
|
+
|
|
8
27
|
## [0.8.5] - 2022-03-06
|
|
9
28
|
### Deprecated
|
|
10
29
|
- `vd.effect.Base` - All visual effects now inherit from `vd.effect.Visual` instead.
|
|
@@ -208,6 +227,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
208
227
|
- Gaussian blur
|
|
209
228
|
- Transform
|
|
210
229
|
|
|
230
|
+
[0.9.0]: https://github.com/etro-js/etro/compare/v0.8.5...v0.9.0
|
|
211
231
|
[0.8.5]: https://github.com/etro-js/etro/compare/v0.8.4...v0.8.5
|
|
212
232
|
[0.8.4]: https://github.com/etro-js/etro/compare/v0.8.3...v0.8.4
|
|
213
233
|
[0.8.3]: https://github.com/etro-js/etro/compare/v0.8.2...v0.8.3
|
package/CONTRIBUTING.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
Thank you for considering contributing to Etro! There are many ways you can contribute to Etro, like creating issues for features or bugs, improving the docs or wiki, or writing the actual code for the library. This page covers how to make changes to the repository files (either code or docs).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[Join our Discord](https://discord.gg/myrBsQ8Cht)
|
|
8
8
|
|
|
9
9
|
## Setting up your local environment
|
|
10
10
|
|
|
11
11
|
#### Step 0: Dependencies
|
|
12
12
|
|
|
13
|
-
- You will need Git, Node, NPM (at least 7.x) and
|
|
13
|
+
- You will need Git, Node, NPM (at least 7.x) and Firefox (for headless unit testing) installed
|
|
14
14
|
|
|
15
15
|
#### Step 1: Fork
|
|
16
16
|
|
|
@@ -27,9 +27,9 @@ Thank you for considering contributing to Etro! There are many ways you can cont
|
|
|
27
27
|
|
|
28
28
|
#### Step 2: Code
|
|
29
29
|
|
|
30
|
-
- Make some changes
|
|
31
|
-
- If you are writing code, the linter uses [StandardJS](https://standardjs.com/rules.html) for style conventions
|
|
32
|
-
- When you're ready to submit
|
|
30
|
+
- Make some changes
|
|
31
|
+
- If you are writing code, the linter uses [StandardJS](https://standardjs.com/rules.html) for style conventions
|
|
32
|
+
- When you're ready to submit, first run
|
|
33
33
|
|
|
34
34
|
```
|
|
35
35
|
npm run lint
|
|
@@ -57,19 +57,18 @@ Thank you for considering contributing to Etro! There are many ways you can cont
|
|
|
57
57
|
|
|
58
58
|
#### Step 3: Push
|
|
59
59
|
|
|
60
|
-
- First, rebase (
|
|
60
|
+
- First, rebase (please avoid merging) to integrate your work with any new changes in the main repository
|
|
61
61
|
|
|
62
62
|
```
|
|
63
63
|
git fetch upstream
|
|
64
64
|
git rebase upstream/master
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
- Push to
|
|
67
|
+
- Push to the fork
|
|
68
68
|
|
|
69
69
|
#### Step 4: Pull request
|
|
70
70
|
|
|
71
|
-
- Open a pull request from
|
|
72
|
-
- In the PR title, include **fixes ###** for bugs and **resolves ###** for feature requests
|
|
71
|
+
- Open a pull request from the branch in your fork to the main repository
|
|
73
72
|
- If you changed any core functionality, make sure you explain your motives for those changes
|
|
74
73
|
|
|
75
74
|
#### Step 5: Feedback
|
|
@@ -80,7 +79,7 @@ Thank you for considering contributing to Etro! There are many ways you can cont
|
|
|
80
79
|
|
|
81
80
|
### Etro Overview
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
Check out [the overview guide](https://etrojs.dev/docs/overview) for usage information
|
|
84
83
|
|
|
85
84
|
### API Structure
|
|
86
85
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/etro)
|
|
4
4
|
[](https://actions-badge.atrox.dev/etro-js/etro/goto)
|
|
5
5
|
|
|
6
|
-
> Etro was previously known as
|
|
6
|
+
> Etro was previously known as Etro, but it had to be renamed to avoid
|
|
7
7
|
> confusion with an existing software product.
|
|
8
8
|
|
|
9
9
|
Etro is a typescript framework for programmatically editing videos. Similar to
|
|
@@ -12,6 +12,8 @@ Etro comes shipped with text, video, audio and image layers, along with a bunch
|
|
|
12
12
|
of GLSL effects. You can also define your own layers and effects with javascript
|
|
13
13
|
and GLSL.
|
|
14
14
|
|
|
15
|
+
[Join our Discord](https://discord.gg/myrBsQ8Cht)
|
|
16
|
+
|
|
15
17
|
## Features
|
|
16
18
|
|
|
17
19
|
- Composite video and audio layers
|
package/dist/effect/base.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Movie } from '../movie';
|
|
2
|
-
import {
|
|
2
|
+
import { Base as BaseLayer } from '../layer/index';
|
|
3
3
|
import BaseObject from '../object';
|
|
4
4
|
/**
|
|
5
5
|
* @deprecated All visual effects now inherit from `Visual` instead
|
|
@@ -21,8 +21,8 @@ export declare class Base implements BaseObject {
|
|
|
21
21
|
* Attaches this effect to `target` if not already attached.
|
|
22
22
|
* @ignore
|
|
23
23
|
*/
|
|
24
|
-
tryAttach(target: Movie |
|
|
25
|
-
attach(movie: Movie |
|
|
24
|
+
tryAttach(target: Movie | BaseLayer): void;
|
|
25
|
+
attach(movie: Movie | BaseLayer): void;
|
|
26
26
|
/**
|
|
27
27
|
* Dettaches this effect from its target if the number of times `tryDetach`
|
|
28
28
|
* has been called (including this call) equals the number of times
|
|
@@ -40,12 +40,12 @@ export declare class Base implements BaseObject {
|
|
|
40
40
|
* (will soon be replaced with an instance getter)
|
|
41
41
|
* @abstract
|
|
42
42
|
*/
|
|
43
|
-
apply(target: Movie |
|
|
43
|
+
apply(target: Movie | BaseLayer, reltime: number): void;
|
|
44
44
|
/**
|
|
45
45
|
* The current time of the target
|
|
46
46
|
*/
|
|
47
47
|
get currentTime(): number;
|
|
48
|
-
get parent(): Movie |
|
|
48
|
+
get parent(): Movie | BaseLayer;
|
|
49
49
|
get movie(): Movie;
|
|
50
50
|
getDefaultOptions(): Record<string, unknown>;
|
|
51
51
|
}
|
package/dist/effect/visual.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import { Movie } from '../movie';
|
|
2
|
+
import { Visual as VisualLayer } from '../layer/index';
|
|
1
3
|
import { Base } from './base';
|
|
2
4
|
/**
|
|
3
5
|
* Modifies the visual contents of a layer.
|
|
4
6
|
*/
|
|
5
7
|
export declare class Visual extends Base {
|
|
8
|
+
/**
|
|
9
|
+
* Apply this effect to a target at the given time
|
|
10
|
+
*
|
|
11
|
+
* @param target
|
|
12
|
+
* @param reltime - the movie's current time relative to the layer
|
|
13
|
+
* (will soon be replaced with an instance getter)
|
|
14
|
+
* @abstract
|
|
15
|
+
*/
|
|
16
|
+
apply(target: Movie | VisualLayer, reltime: number): void;
|
|
6
17
|
}
|
package/dist/etro-cjs.js
CHANGED
|
@@ -485,6 +485,8 @@ function mapPixels(mapper, canvas, ctx, x, y, width, height, flush) {
|
|
|
485
485
|
* <p>Must be called before any watchable properties are set, and only once in
|
|
486
486
|
* the prototype chain.
|
|
487
487
|
*
|
|
488
|
+
* @deprecated Will be removed in the future (see issue #130)
|
|
489
|
+
*
|
|
488
490
|
* @param target - object to watch
|
|
489
491
|
*/
|
|
490
492
|
function watchPublic(target) {
|
|
@@ -618,7 +620,10 @@ function AudioSourceMixin(superclass) {
|
|
|
618
620
|
this.audioNode.connect(movie.actx.destination);
|
|
619
621
|
};
|
|
620
622
|
MixedAudioSource.prototype.detach = function () {
|
|
621
|
-
|
|
623
|
+
// Cache dest before super.detach() unsets this.movie
|
|
624
|
+
var dest = this.movie.actx.destination;
|
|
625
|
+
_super.prototype.detach.call(this);
|
|
626
|
+
this.audioNode.disconnect(dest);
|
|
622
627
|
};
|
|
623
628
|
MixedAudioSource.prototype.start = function () {
|
|
624
629
|
this.source.currentTime = this.currentTime + this.sourceStartTime;
|
|
@@ -836,7 +841,7 @@ var Base = /** @class */ (function () {
|
|
|
836
841
|
// id for events (independent of instance, but easy to access when on prototype
|
|
837
842
|
// chain)
|
|
838
843
|
Base.prototype.type = 'layer';
|
|
839
|
-
Base.prototype.publicExcludes = [];
|
|
844
|
+
Base.prototype.publicExcludes = ['active'];
|
|
840
845
|
Base.prototype.propertyFilters = {};
|
|
841
846
|
|
|
842
847
|
// TODO: rename to something more consistent with the naming convention of Visual and VisualSourceMixin
|
|
@@ -1282,6 +1287,18 @@ var Visual$1 = /** @class */ (function (_super) {
|
|
|
1282
1287
|
function Visual() {
|
|
1283
1288
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
1284
1289
|
}
|
|
1290
|
+
// subclasses must implement apply
|
|
1291
|
+
/**
|
|
1292
|
+
* Apply this effect to a target at the given time
|
|
1293
|
+
*
|
|
1294
|
+
* @param target
|
|
1295
|
+
* @param reltime - the movie's current time relative to the layer
|
|
1296
|
+
* (will soon be replaced with an instance getter)
|
|
1297
|
+
* @abstract
|
|
1298
|
+
*/
|
|
1299
|
+
Visual.prototype.apply = function (target, reltime) {
|
|
1300
|
+
_super.prototype.apply.call(this, target, reltime);
|
|
1301
|
+
};
|
|
1285
1302
|
return Visual;
|
|
1286
1303
|
}(Base$1));
|
|
1287
1304
|
|
|
@@ -2312,16 +2329,16 @@ var Transform = /** @class */ (function (_super) {
|
|
|
2312
2329
|
*/
|
|
2313
2330
|
|
|
2314
2331
|
var index$1 = /*#__PURE__*/Object.freeze({
|
|
2315
|
-
GaussianBlur: GaussianBlur,
|
|
2316
|
-
GaussianBlurHorizontal: GaussianBlurHorizontal,
|
|
2317
|
-
GaussianBlurVertical: GaussianBlurVertical,
|
|
2318
2332
|
Base: Base$1,
|
|
2333
|
+
Brightness: Brightness,
|
|
2319
2334
|
Channels: Channels,
|
|
2320
2335
|
ChromaKey: ChromaKey,
|
|
2321
2336
|
Contrast: Contrast,
|
|
2322
2337
|
EllipticalMaskOptions: EllipticalMaskOptions,
|
|
2323
2338
|
EllipticalMask: EllipticalMask,
|
|
2324
|
-
|
|
2339
|
+
GaussianBlur: GaussianBlur,
|
|
2340
|
+
GaussianBlurHorizontal: GaussianBlurHorizontal,
|
|
2341
|
+
GaussianBlurVertical: GaussianBlurVertical,
|
|
2325
2342
|
Grayscale: Grayscale,
|
|
2326
2343
|
Pixelate: Pixelate,
|
|
2327
2344
|
Shader: Shader,
|
|
@@ -2615,18 +2632,27 @@ var Movie = /** @class */ (function () {
|
|
|
2615
2632
|
return;
|
|
2616
2633
|
}
|
|
2617
2634
|
this._updateCurrentTime(timestamp);
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2635
|
+
// TODO: Is calling duration every frame bad for performance? (remember,
|
|
2636
|
+
// it's calling Array.reduce)
|
|
2637
|
+
var end = this.recording ? this._recordEndTime : this.duration;
|
|
2638
|
+
if (this.currentTime > end) {
|
|
2639
|
+
if (this.recording)
|
|
2640
|
+
publish(this, 'movie.recordended', { movie: this });
|
|
2641
|
+
if (this.currentTime > this.duration)
|
|
2642
|
+
publish(this, 'movie.ended', { movie: this, repeat: this.repeat });
|
|
2643
|
+
// TODO: only reset currentTime if repeating
|
|
2644
|
+
if (this.repeat) {
|
|
2645
|
+
// Don't use setter, which publishes 'movie.seek'. Instead, update the
|
|
2646
|
+
// value and publish a 'movie.timeupdate' event.
|
|
2647
|
+
this._currentTime = 0;
|
|
2648
|
+
publish(this, 'movie.timeupdate', { movie: this });
|
|
2649
|
+
}
|
|
2626
2650
|
this._lastPlayed = performance.now();
|
|
2627
2651
|
this._lastPlayedOffset = 0; // this.currentTime
|
|
2628
2652
|
this._renderingFrame = false;
|
|
2629
|
-
if (
|
|
2653
|
+
// Stop playback or recording if done (except if it's playing and repeat
|
|
2654
|
+
// is true)
|
|
2655
|
+
if (!(!this.recording && this.repeat)) {
|
|
2630
2656
|
this._paused = true;
|
|
2631
2657
|
this._ended = true;
|
|
2632
2658
|
// Deactivate all layers
|
|
@@ -2635,22 +2661,15 @@ var Movie = /** @class */ (function () {
|
|
|
2635
2661
|
var layer = this.layers[i];
|
|
2636
2662
|
// A layer that has been deleted before layers.length has been updated
|
|
2637
2663
|
// (see the layers proxy in the constructor).
|
|
2638
|
-
if (!layer)
|
|
2664
|
+
if (!layer || !layer.active)
|
|
2639
2665
|
continue;
|
|
2640
2666
|
layer.stop();
|
|
2641
2667
|
layer.active = false;
|
|
2642
2668
|
}
|
|
2669
|
+
if (done)
|
|
2670
|
+
done();
|
|
2671
|
+
return;
|
|
2643
2672
|
}
|
|
2644
|
-
publish(this, 'movie.ended', { movie: this, repeat: this.repeat });
|
|
2645
|
-
// TODO: only reset currentTime if repeating
|
|
2646
|
-
this._currentTime = 0; // don't use setter
|
|
2647
|
-
publish(this, 'movie.timeupdate', { movie: this });
|
|
2648
|
-
}
|
|
2649
|
-
// Stop playback or recording if done
|
|
2650
|
-
if (recordingEnded || (ended && !this.repeat)) {
|
|
2651
|
-
if (done)
|
|
2652
|
-
done();
|
|
2653
|
-
return;
|
|
2654
2673
|
}
|
|
2655
2674
|
// Do render
|
|
2656
2675
|
this._renderBackground(timestamp);
|
|
@@ -2678,8 +2697,11 @@ var Movie = /** @class */ (function () {
|
|
|
2678
2697
|
if (!this._renderingFrame) {
|
|
2679
2698
|
// if ((timestamp - this._lastUpdate) >= this._updateInterval) {
|
|
2680
2699
|
var sinceLastPlayed = (timestamp - this._lastPlayed) / 1000;
|
|
2681
|
-
|
|
2682
|
-
|
|
2700
|
+
var currentTime = this._lastPlayedOffset + sinceLastPlayed; // don't use setter
|
|
2701
|
+
if (this.currentTime !== currentTime) {
|
|
2702
|
+
this._currentTime = currentTime;
|
|
2703
|
+
publish(this, 'movie.timeupdate', { movie: this });
|
|
2704
|
+
}
|
|
2683
2705
|
// this._lastUpdate = timestamp;
|
|
2684
2706
|
// }
|
|
2685
2707
|
}
|
package/dist/etro-iife.js
CHANGED
|
@@ -486,6 +486,8 @@ var etro = (function () {
|
|
|
486
486
|
* <p>Must be called before any watchable properties are set, and only once in
|
|
487
487
|
* the prototype chain.
|
|
488
488
|
*
|
|
489
|
+
* @deprecated Will be removed in the future (see issue #130)
|
|
490
|
+
*
|
|
489
491
|
* @param target - object to watch
|
|
490
492
|
*/
|
|
491
493
|
function watchPublic(target) {
|
|
@@ -619,7 +621,10 @@ var etro = (function () {
|
|
|
619
621
|
this.audioNode.connect(movie.actx.destination);
|
|
620
622
|
};
|
|
621
623
|
MixedAudioSource.prototype.detach = function () {
|
|
622
|
-
|
|
624
|
+
// Cache dest before super.detach() unsets this.movie
|
|
625
|
+
var dest = this.movie.actx.destination;
|
|
626
|
+
_super.prototype.detach.call(this);
|
|
627
|
+
this.audioNode.disconnect(dest);
|
|
623
628
|
};
|
|
624
629
|
MixedAudioSource.prototype.start = function () {
|
|
625
630
|
this.source.currentTime = this.currentTime + this.sourceStartTime;
|
|
@@ -837,7 +842,7 @@ var etro = (function () {
|
|
|
837
842
|
// id for events (independent of instance, but easy to access when on prototype
|
|
838
843
|
// chain)
|
|
839
844
|
Base.prototype.type = 'layer';
|
|
840
|
-
Base.prototype.publicExcludes = [];
|
|
845
|
+
Base.prototype.publicExcludes = ['active'];
|
|
841
846
|
Base.prototype.propertyFilters = {};
|
|
842
847
|
|
|
843
848
|
// TODO: rename to something more consistent with the naming convention of Visual and VisualSourceMixin
|
|
@@ -1283,6 +1288,18 @@ var etro = (function () {
|
|
|
1283
1288
|
function Visual() {
|
|
1284
1289
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
1285
1290
|
}
|
|
1291
|
+
// subclasses must implement apply
|
|
1292
|
+
/**
|
|
1293
|
+
* Apply this effect to a target at the given time
|
|
1294
|
+
*
|
|
1295
|
+
* @param target
|
|
1296
|
+
* @param reltime - the movie's current time relative to the layer
|
|
1297
|
+
* (will soon be replaced with an instance getter)
|
|
1298
|
+
* @abstract
|
|
1299
|
+
*/
|
|
1300
|
+
Visual.prototype.apply = function (target, reltime) {
|
|
1301
|
+
_super.prototype.apply.call(this, target, reltime);
|
|
1302
|
+
};
|
|
1286
1303
|
return Visual;
|
|
1287
1304
|
}(Base$1));
|
|
1288
1305
|
|
|
@@ -2313,16 +2330,16 @@ var etro = (function () {
|
|
|
2313
2330
|
*/
|
|
2314
2331
|
|
|
2315
2332
|
var index$1 = /*#__PURE__*/Object.freeze({
|
|
2316
|
-
GaussianBlur: GaussianBlur,
|
|
2317
|
-
GaussianBlurHorizontal: GaussianBlurHorizontal,
|
|
2318
|
-
GaussianBlurVertical: GaussianBlurVertical,
|
|
2319
2333
|
Base: Base$1,
|
|
2334
|
+
Brightness: Brightness,
|
|
2320
2335
|
Channels: Channels,
|
|
2321
2336
|
ChromaKey: ChromaKey,
|
|
2322
2337
|
Contrast: Contrast,
|
|
2323
2338
|
EllipticalMaskOptions: EllipticalMaskOptions,
|
|
2324
2339
|
EllipticalMask: EllipticalMask,
|
|
2325
|
-
|
|
2340
|
+
GaussianBlur: GaussianBlur,
|
|
2341
|
+
GaussianBlurHorizontal: GaussianBlurHorizontal,
|
|
2342
|
+
GaussianBlurVertical: GaussianBlurVertical,
|
|
2326
2343
|
Grayscale: Grayscale,
|
|
2327
2344
|
Pixelate: Pixelate,
|
|
2328
2345
|
Shader: Shader,
|
|
@@ -2616,18 +2633,27 @@ var etro = (function () {
|
|
|
2616
2633
|
return;
|
|
2617
2634
|
}
|
|
2618
2635
|
this._updateCurrentTime(timestamp);
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2636
|
+
// TODO: Is calling duration every frame bad for performance? (remember,
|
|
2637
|
+
// it's calling Array.reduce)
|
|
2638
|
+
var end = this.recording ? this._recordEndTime : this.duration;
|
|
2639
|
+
if (this.currentTime > end) {
|
|
2640
|
+
if (this.recording)
|
|
2641
|
+
publish(this, 'movie.recordended', { movie: this });
|
|
2642
|
+
if (this.currentTime > this.duration)
|
|
2643
|
+
publish(this, 'movie.ended', { movie: this, repeat: this.repeat });
|
|
2644
|
+
// TODO: only reset currentTime if repeating
|
|
2645
|
+
if (this.repeat) {
|
|
2646
|
+
// Don't use setter, which publishes 'movie.seek'. Instead, update the
|
|
2647
|
+
// value and publish a 'movie.timeupdate' event.
|
|
2648
|
+
this._currentTime = 0;
|
|
2649
|
+
publish(this, 'movie.timeupdate', { movie: this });
|
|
2650
|
+
}
|
|
2627
2651
|
this._lastPlayed = performance.now();
|
|
2628
2652
|
this._lastPlayedOffset = 0; // this.currentTime
|
|
2629
2653
|
this._renderingFrame = false;
|
|
2630
|
-
if (
|
|
2654
|
+
// Stop playback or recording if done (except if it's playing and repeat
|
|
2655
|
+
// is true)
|
|
2656
|
+
if (!(!this.recording && this.repeat)) {
|
|
2631
2657
|
this._paused = true;
|
|
2632
2658
|
this._ended = true;
|
|
2633
2659
|
// Deactivate all layers
|
|
@@ -2636,22 +2662,15 @@ var etro = (function () {
|
|
|
2636
2662
|
var layer = this.layers[i];
|
|
2637
2663
|
// A layer that has been deleted before layers.length has been updated
|
|
2638
2664
|
// (see the layers proxy in the constructor).
|
|
2639
|
-
if (!layer)
|
|
2665
|
+
if (!layer || !layer.active)
|
|
2640
2666
|
continue;
|
|
2641
2667
|
layer.stop();
|
|
2642
2668
|
layer.active = false;
|
|
2643
2669
|
}
|
|
2670
|
+
if (done)
|
|
2671
|
+
done();
|
|
2672
|
+
return;
|
|
2644
2673
|
}
|
|
2645
|
-
publish(this, 'movie.ended', { movie: this, repeat: this.repeat });
|
|
2646
|
-
// TODO: only reset currentTime if repeating
|
|
2647
|
-
this._currentTime = 0; // don't use setter
|
|
2648
|
-
publish(this, 'movie.timeupdate', { movie: this });
|
|
2649
|
-
}
|
|
2650
|
-
// Stop playback or recording if done
|
|
2651
|
-
if (recordingEnded || (ended && !this.repeat)) {
|
|
2652
|
-
if (done)
|
|
2653
|
-
done();
|
|
2654
|
-
return;
|
|
2655
2674
|
}
|
|
2656
2675
|
// Do render
|
|
2657
2676
|
this._renderBackground(timestamp);
|
|
@@ -2679,8 +2698,11 @@ var etro = (function () {
|
|
|
2679
2698
|
if (!this._renderingFrame) {
|
|
2680
2699
|
// if ((timestamp - this._lastUpdate) >= this._updateInterval) {
|
|
2681
2700
|
var sinceLastPlayed = (timestamp - this._lastPlayed) / 1000;
|
|
2682
|
-
|
|
2683
|
-
|
|
2701
|
+
var currentTime = this._lastPlayedOffset + sinceLastPlayed; // don't use setter
|
|
2702
|
+
if (this.currentTime !== currentTime) {
|
|
2703
|
+
this._currentTime = currentTime;
|
|
2704
|
+
publish(this, 'movie.timeupdate', { movie: this });
|
|
2705
|
+
}
|
|
2684
2706
|
// this._lastUpdate = timestamp;
|
|
2685
2707
|
// }
|
|
2686
2708
|
}
|
package/dist/layer/image.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare type ImageOptions =
|
|
1
|
+
import { VisualSourceOptions } from './visual-source';
|
|
2
|
+
declare type ImageOptions = VisualSourceOptions;
|
|
3
3
|
declare const Image_base: new (...args: unknown[]) => import("./visual-source").VisualSource;
|
|
4
4
|
declare class Image extends Image_base {
|
|
5
5
|
}
|
package/dist/movie.d.ts
CHANGED
|
@@ -32,10 +32,19 @@ export declare class MovieOptions {
|
|
|
32
32
|
*/
|
|
33
33
|
export declare class Movie {
|
|
34
34
|
type: string;
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Auto-refresh will be removed in the future (see issue #130).
|
|
37
|
+
*/
|
|
35
38
|
publicExcludes: string[];
|
|
36
39
|
propertyFilters: Record<string, <T>(value: T) => T>;
|
|
37
40
|
repeat: boolean;
|
|
38
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Call `refresh` when the user changes a property on the movie or any of its
|
|
43
|
+
* layers or effects
|
|
44
|
+
*
|
|
45
|
+
* @deprecated Auto-refresh will be removed in the future. If you want to
|
|
46
|
+
* refresh the canvas, call `refresh`. See issue #130.
|
|
47
|
+
*/
|
|
39
48
|
autoRefresh: boolean;
|
|
40
49
|
/** The background color of the movie as a cSS string */
|
|
41
50
|
background: Dynamic<string>;
|
package/dist/util.d.ts
CHANGED
|
@@ -120,6 +120,8 @@ export declare function mapPixels(mapper: (pixels: Uint8ClampedArray, i: number)
|
|
|
120
120
|
* <p>Must be called before any watchable properties are set, and only once in
|
|
121
121
|
* the prototype chain.
|
|
122
122
|
*
|
|
123
|
+
* @deprecated Will be removed in the future (see issue #130)
|
|
124
|
+
*
|
|
123
125
|
* @param target - object to watch
|
|
124
126
|
*/
|
|
125
127
|
export declare function watchPublic(target: EtroObject): EtroObject;
|
package/karma.conf.js
CHANGED
|
@@ -67,12 +67,22 @@ module.exports = function (config) {
|
|
|
67
67
|
captureConsole: true
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
+
browserConsoleLogOptions: {
|
|
71
|
+
level: 'log'
|
|
72
|
+
},
|
|
73
|
+
|
|
70
74
|
// Continuous Integration mode
|
|
71
75
|
// if true, Karma captures browsers, runs the tests and exits
|
|
72
76
|
singleRun: true,
|
|
73
77
|
|
|
74
78
|
// Concurrency level
|
|
75
79
|
// how many browser should be started simultaneous
|
|
76
|
-
concurrency: Infinity
|
|
80
|
+
concurrency: Infinity,
|
|
81
|
+
|
|
82
|
+
client: {
|
|
83
|
+
jasmine: {
|
|
84
|
+
timeoutInterval: 10000
|
|
85
|
+
}
|
|
86
|
+
}
|
|
77
87
|
})
|
|
78
88
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "etro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "An extendable video-editing framework for the browser and Node",
|
|
5
5
|
"browser": "dist/etro-cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"eslint-plugin-promise": "^4.2.1",
|
|
24
24
|
"eslint-plugin-standard": "^4.0.1",
|
|
25
25
|
"ev": "0.0.7",
|
|
26
|
-
"http-server": "^
|
|
26
|
+
"http-server": "^14.1.1",
|
|
27
27
|
"jasmine": "^3.4.0",
|
|
28
28
|
"karma": "^6.1.1",
|
|
29
29
|
"karma-es6-shim": "^1.0.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"rollup-plugin-node-resolve": "^5.2.0",
|
|
41
41
|
"rollup-plugin-typescript2": "^0.29.0",
|
|
42
42
|
"rollup-plugin-uglify-es": "^0.0.1",
|
|
43
|
-
"shipjs": "0.
|
|
43
|
+
"shipjs": "^0.24.4",
|
|
44
44
|
"typedoc": "^0.22.11",
|
|
45
45
|
"typescript": "^4.1.3"
|
|
46
46
|
},
|
package/private-todo.txt
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
(A) 2021-04-21 offline recording with ffmpeg.wasm
|
|
2
|
+
(A) 2021-04-21 document events
|
|
3
|
+
(A) 2021-05-17 test recording to mp4
|
|
4
|
+
(A) 2021-05-17 test that keyframes extend last frame for infinity!!
|
|
5
|
+
(B) 2020-08-03 make sure each event's purpose is to notify the public world of notable things that happen in the object.
|
|
6
|
+
(B) 2020-08-27 transitions?
|
|
7
|
+
(B) 2020-12-30 emit modify events when effects are added to layer?
|
|
8
|
+
(B) 2020-12-30 ensure order of `set` and `deleteProperty` are correct in array proxy with `pop`
|
|
9
|
+
(B) 2021-04-12 disable autoRefresh in tests and test integration with this switch some other way
|
|
10
|
+
(C) 2019-10-13 idea: layer inheritance
|
|
11
|
+
(C) 2019-10-13 ignore leading underscore in shader uniform property names
|
|
12
|
+
(C) 2019-10-13 fix opacity with shader effects
|
|
13
|
+
(C) 2020-08-08 Replace val(element, 'property', reltime) with element.property.value
|
|
14
|
+
(C) 2020-08-12 call URL.revokeObjectURL when recording
|
|
15
|
+
(C) 2020-12-30 simplify movie.change.* into movie.change
|
|
16
|
+
(C) 2021-03-28 make all color properties use `Color`
|
|
17
|
+
(C) 2021-04-02 abort recording
|
|
18
|
+
(C) 2021-04-21 webcam example doesn't work on FF unless autoRefresh is set to false
|
|
19
|
+
(C) 2021-07-13 make all layers canvases the same size as the movie
|
|
20
|
+
(C) 2021-07-18 movie stops recording a few frames late when duration is supplied
|
|
21
|
+
(D) 2019-10-15 change chroma key constructor signature
|
|
22
|
+
(D) 2019-11-11 treat zero as invalid for pixelate radius
|
|
23
|
+
(D) 2019-11-11 decide on effect.Transform using hardware acceleration
|
|
24
|
+
(D) 2019-11-18 Look at linearInterp objectKeys default value
|
|
25
|
+
(D) 2019-12-25 Rename `Stack` to something else
|
|
26
|
+
(D) 2020-08-02 Not every option should be set as a property on the object
|
|
27
|
+
(D) 2021-01-24 Remove path support in val (because users would expect it to evaluate every path part)
|
|
28
|
+
(D) 2021-01-26 Fix inheritance checking for media mixin
|
|
29
|
+
(D) 2021-01-26 Media docstring type
|
|
30
|
+
(D) 2021-01-26 Call super in all media mixin methods
|
|
31
|
+
(D) 2021-01-27 Use options.js
|
|
32
|
+
(D) 2021-04-02 error on invalid `record` options
|
|
33
|
+
(D) 2021-04-12 use val() when recalculating AudioSource#duration based on playbackRate
|
|
34
|
+
(D) 2021-07-09 multiple layers of proxies in watched objects
|
|
35
|
+
|
|
36
|
+
x (B) 2021-04-12 make error range for pixel tests
|
|
37
|
+
x (C) 2021-02-26 make sure that movie background gets val'd
|
|
38
|
+
x (B) 2021-04-03 expose MovieOptions
|
|
39
|
+
x (D) 2019-10-09 probably convert to typescript
|
|
40
|
+
x (C) 2019-10-22 make image and video both extend a mixin
|
|
41
|
+
x (C) 2021-04-03 2019-01-07 record for interval of time
|
|
42
|
+
x (B) 2021-04-03 2021-04-03 add missing properties to MixedVisualSource
|
|
43
|
+
x (D) 2021-04-03 2021-04-03 move opacity out of `border` in Visual
|
|
44
|
+
x (B) 2021-01-28 2020-12-18 split layers up into multiple files
|
|
45
|
+
x (B) 2021-01-28 2020-12-18 split effects up into multiple files
|
|
46
|
+
x (B) 2020-08-27 individual interpolation for keyframe sets
|
|
47
|
+
x (B) 2019-12-24 support node
|
|
48
|
+
x (B) 2020-12-31 2020-12-30 Detach effect when replaced in layer
|
|
49
|
+
x (D) 2020-12-18 2020-08-02 Rename `cctx` -> `vctx`
|
|
50
|
+
x (B) 2019-01-02 fix movie record test failing with GitHub actions
|
|
51
|
+
x (B) 2020-08-03 2020-08-03 don't set Image#clipWidth in init
|
|
52
|
+
x (B) 2020-08-03 2020-08-03 remove properties like Video#mediaWidth, effectively removing layer borders
|
|
53
|
+
x (B) 2020-08-03 2019-10-04 decide on the purpose of events - it's to notify the outside world of notable things that happen in the object
|
|
54
|
+
x (B) 2019-12-25 decide on public / private properties
|
|
55
|
+
x (C) 2019-12-25 2019-12-24 make getDefaultOptions private
|
|
56
|
+
x (D) 2019-11-18 Change Color constructor default a from 255 -> 1.0
|
|
57
|
+
x (A) 2019-12-06 2019-11-11 Start roadmap
|
|
58
|
+
x (A) 2019-11-19 2019-10-22 Util tests
|
|
59
|
+
x (A) 2019-10-22 Effect tests
|
|
60
|
+
x (D) 2019-11-18 2019-11-18 update watchPublic description, removing part that says "after all public properties are initialized in constructor"
|
|
61
|
+
x (B) 2019-10-13 mv examples/media examples/assets
|
|
62
|
+
x (A) 2019-10-22 2019-10-22 Layer tests
|
|
63
|
+
x (B) 2019-10-12 support media live streams
|
|
64
|
+
x (C) 2019-10-03 research if dist/etris-esm.js is necessary
|
|
65
|
+
x (A) 2019-10-04 upload to npm
|
|
66
|
+
x (C) 2019-10-07 lint examples
|
|
67
|
+
x (B) 2019-10-04 fix jsdoc comments after linting
|
|
68
|
+
x (A) 2019-10-07 2019-10-07 fix recording silent movie on chrome
|
|
69
|
+
x (A) 2019-10-05 2019-10-03 research if I can include open media in my repo
|
|
70
|
+
x 2019-10-04 2019-10-03 use one of eslint's official configs
|
package/src/effect/base.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { watchPublic } from '../util'
|
|
2
2
|
import { publish, subscribe } from '../event'
|
|
3
3
|
import { Movie } from '../movie'
|
|
4
|
-
import {
|
|
4
|
+
import { Base as BaseLayer } from '../layer/index'
|
|
5
5
|
import BaseObject from '../object'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -14,7 +14,7 @@ export class Base implements BaseObject {
|
|
|
14
14
|
|
|
15
15
|
enabled: boolean
|
|
16
16
|
|
|
17
|
-
private _target: Movie |
|
|
17
|
+
private _target: Movie | BaseLayer
|
|
18
18
|
/**
|
|
19
19
|
* The number of times this effect has been attached to a target minus the
|
|
20
20
|
* number of times it's been detached. (Used for the target's array proxy with
|
|
@@ -45,14 +45,14 @@ export class Base implements BaseObject {
|
|
|
45
45
|
* Attaches this effect to `target` if not already attached.
|
|
46
46
|
* @ignore
|
|
47
47
|
*/
|
|
48
|
-
tryAttach (target: Movie |
|
|
48
|
+
tryAttach (target: Movie | BaseLayer): void {
|
|
49
49
|
if (this._occurrenceCount === 0)
|
|
50
50
|
this.attach(target)
|
|
51
51
|
|
|
52
52
|
this._occurrenceCount++
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
attach (movie: Movie |
|
|
55
|
+
attach (movie: Movie | BaseLayer): void {
|
|
56
56
|
this._target = movie
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -87,7 +87,7 @@ export class Base implements BaseObject {
|
|
|
87
87
|
* (will soon be replaced with an instance getter)
|
|
88
88
|
* @abstract
|
|
89
89
|
*/
|
|
90
|
-
apply (target: Movie |
|
|
90
|
+
apply (target: Movie | BaseLayer, reltime: number): void {} // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* The current time of the target
|
|
@@ -96,7 +96,7 @@ export class Base implements BaseObject {
|
|
|
96
96
|
return this._target ? this._target.currentTime : undefined
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
get parent (): Movie |
|
|
99
|
+
get parent (): Movie | BaseLayer {
|
|
100
100
|
return this._target
|
|
101
101
|
}
|
|
102
102
|
|
package/src/effect/visual.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
+
import { Movie } from '../movie'
|
|
2
|
+
import { Visual as VisualLayer } from '../layer/index'
|
|
1
3
|
import { Base } from './base'
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Modifies the visual contents of a layer.
|
|
5
7
|
*/
|
|
6
|
-
export class Visual extends Base {
|
|
8
|
+
export class Visual extends Base {
|
|
9
|
+
// subclasses must implement apply
|
|
10
|
+
/**
|
|
11
|
+
* Apply this effect to a target at the given time
|
|
12
|
+
*
|
|
13
|
+
* @param target
|
|
14
|
+
* @param reltime - the movie's current time relative to the layer
|
|
15
|
+
* (will soon be replaced with an instance getter)
|
|
16
|
+
* @abstract
|
|
17
|
+
*/
|
|
18
|
+
apply (target: Movie | VisualLayer, reltime: number): void { // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
|
19
|
+
super.apply(target, reltime)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -134,7 +134,10 @@ function AudioSourceMixin<OptionsSuperclass extends BaseOptions> (superclass: Co
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
detach () {
|
|
137
|
-
|
|
137
|
+
// Cache dest before super.detach() unsets this.movie
|
|
138
|
+
const dest = this.movie.actx.destination
|
|
139
|
+
super.detach()
|
|
140
|
+
this.audioNode.disconnect(dest)
|
|
138
141
|
}
|
|
139
142
|
|
|
140
143
|
start () {
|
package/src/layer/base.ts
CHANGED
|
@@ -169,7 +169,7 @@ class Base implements EtroObject {
|
|
|
169
169
|
// id for events (independent of instance, but easy to access when on prototype
|
|
170
170
|
// chain)
|
|
171
171
|
Base.prototype.type = 'layer'
|
|
172
|
-
Base.prototype.publicExcludes = []
|
|
172
|
+
Base.prototype.publicExcludes = ['active']
|
|
173
173
|
Base.prototype.propertyFilters = {}
|
|
174
174
|
|
|
175
175
|
export { Base, BaseOptions }
|
package/src/layer/image.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Visual
|
|
2
|
-
import { VisualSourceMixin } from './visual-source'
|
|
1
|
+
import { Visual } from './visual'
|
|
2
|
+
import { VisualSourceMixin, VisualSourceOptions } from './visual-source'
|
|
3
3
|
|
|
4
|
-
type ImageOptions =
|
|
4
|
+
type ImageOptions = VisualSourceOptions
|
|
5
5
|
|
|
6
6
|
class Image extends VisualSourceMixin(Visual) {}
|
|
7
7
|
|
package/src/movie.ts
CHANGED
|
@@ -44,11 +44,20 @@ export class MovieOptions {
|
|
|
44
44
|
// TODO: rename renderingFrame -> refreshing
|
|
45
45
|
export class Movie {
|
|
46
46
|
type: string
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated Auto-refresh will be removed in the future (see issue #130).
|
|
49
|
+
*/
|
|
47
50
|
publicExcludes: string[]
|
|
48
51
|
propertyFilters: Record<string, <T>(value: T) => T>
|
|
49
52
|
|
|
50
53
|
repeat: boolean
|
|
51
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Call `refresh` when the user changes a property on the movie or any of its
|
|
56
|
+
* layers or effects
|
|
57
|
+
*
|
|
58
|
+
* @deprecated Auto-refresh will be removed in the future. If you want to
|
|
59
|
+
* refresh the canvas, call `refresh`. See issue #130.
|
|
60
|
+
*/
|
|
52
61
|
autoRefresh: boolean
|
|
53
62
|
/** The background color of the movie as a cSS string */
|
|
54
63
|
background: Dynamic<string>
|
|
@@ -379,19 +388,32 @@ export class Movie {
|
|
|
379
388
|
}
|
|
380
389
|
|
|
381
390
|
this._updateCurrentTime(timestamp)
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
+
|
|
392
|
+
// TODO: Is calling duration every frame bad for performance? (remember,
|
|
393
|
+
// it's calling Array.reduce)
|
|
394
|
+
const end = this.recording ? this._recordEndTime : this.duration
|
|
395
|
+
if (this.currentTime > end) {
|
|
396
|
+
if (this.recording)
|
|
397
|
+
publish(this, 'movie.recordended', { movie: this })
|
|
398
|
+
|
|
399
|
+
if (this.currentTime > this.duration)
|
|
400
|
+
publish(this, 'movie.ended', { movie: this, repeat: this.repeat })
|
|
401
|
+
|
|
402
|
+
// TODO: only reset currentTime if repeating
|
|
403
|
+
if (this.repeat) {
|
|
404
|
+
// Don't use setter, which publishes 'movie.seek'. Instead, update the
|
|
405
|
+
// value and publish a 'movie.timeupdate' event.
|
|
406
|
+
this._currentTime = 0
|
|
407
|
+
publish(this, 'movie.timeupdate', { movie: this })
|
|
408
|
+
}
|
|
409
|
+
|
|
391
410
|
this._lastPlayed = performance.now()
|
|
392
411
|
this._lastPlayedOffset = 0 // this.currentTime
|
|
393
412
|
this._renderingFrame = false
|
|
394
|
-
|
|
413
|
+
|
|
414
|
+
// Stop playback or recording if done (except if it's playing and repeat
|
|
415
|
+
// is true)
|
|
416
|
+
if (!(!this.recording && this.repeat)) {
|
|
395
417
|
this._paused = true
|
|
396
418
|
this._ended = true
|
|
397
419
|
// Deactivate all layers
|
|
@@ -400,27 +422,18 @@ export class Movie {
|
|
|
400
422
|
const layer = this.layers[i]
|
|
401
423
|
// A layer that has been deleted before layers.length has been updated
|
|
402
424
|
// (see the layers proxy in the constructor).
|
|
403
|
-
if (!layer)
|
|
425
|
+
if (!layer || !layer.active)
|
|
404
426
|
continue
|
|
405
427
|
|
|
406
428
|
layer.stop()
|
|
407
429
|
layer.active = false
|
|
408
430
|
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
publish(this, 'movie.ended', { movie: this, repeat: this.repeat })
|
|
412
431
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
publish(this, 'movie.timeupdate', { movie: this })
|
|
416
|
-
}
|
|
432
|
+
if (done)
|
|
433
|
+
done()
|
|
417
434
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (done)
|
|
421
|
-
done()
|
|
422
|
-
|
|
423
|
-
return
|
|
435
|
+
return
|
|
436
|
+
}
|
|
424
437
|
}
|
|
425
438
|
|
|
426
439
|
// Do render
|
|
@@ -454,8 +467,11 @@ export class Movie {
|
|
|
454
467
|
if (!this._renderingFrame) {
|
|
455
468
|
// if ((timestamp - this._lastUpdate) >= this._updateInterval) {
|
|
456
469
|
const sinceLastPlayed = (timestamp - this._lastPlayed) / 1000
|
|
457
|
-
|
|
458
|
-
|
|
470
|
+
const currentTime = this._lastPlayedOffset + sinceLastPlayed // don't use setter
|
|
471
|
+
if (this.currentTime !== currentTime) {
|
|
472
|
+
this._currentTime = currentTime
|
|
473
|
+
publish(this, 'movie.timeupdate', { movie: this })
|
|
474
|
+
}
|
|
459
475
|
// this._lastUpdate = timestamp;
|
|
460
476
|
// }
|
|
461
477
|
}
|
package/src/util.ts
CHANGED
|
@@ -415,6 +415,8 @@ export function mapPixels (
|
|
|
415
415
|
* <p>Must be called before any watchable properties are set, and only once in
|
|
416
416
|
* the prototype chain.
|
|
417
417
|
*
|
|
418
|
+
* @deprecated Will be removed in the future (see issue #130)
|
|
419
|
+
*
|
|
418
420
|
* @param target - object to watch
|
|
419
421
|
*/
|
|
420
422
|
export function watchPublic (target: EtroObject): EtroObject {
|