etro 0.8.3 → 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.
@@ -1,9 +1,8 @@
1
- import { AudioContext, IAudioNode } from 'standardized-audio-context';
2
1
  import { Base, BaseOptions } from './base';
3
2
  declare type Constructor<T> = new (...args: unknown[]) => T;
4
3
  interface AudioSource extends Base {
5
4
  readonly source: HTMLMediaElement;
6
- readonly audioNode: IAudioNode<AudioContext>;
5
+ readonly audioNode: AudioNode;
7
6
  playbackRate: number;
8
7
  /** The audio source node for the media */
9
8
  sourceStartTime: number;
@@ -1,5 +1,5 @@
1
- import { VisualOptions } from './visual';
2
- declare type ImageOptions = VisualOptions;
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
  }
@@ -1,6 +1,6 @@
1
1
  import { Dynamic } from '../util';
2
2
  import { Base, BaseOptions } from './base';
3
- import { Base as BaseEffect } from '../effect/base';
3
+ import { Visual as VisualEffect } from '../effect/visual';
4
4
  interface VisualOptions extends BaseOptions {
5
5
  x?: Dynamic<number>;
6
6
  y?: Dynamic<number>;
@@ -33,7 +33,7 @@ declare class Visual extends Base {
33
33
  * The context of {@link Visual#canvas}
34
34
  */
35
35
  readonly cctx: CanvasRenderingContext2D;
36
- readonly effects: BaseEffect[];
36
+ readonly effects: VisualEffect[];
37
37
  private _effectsBack;
38
38
  /**
39
39
  * Creates a visual layer
@@ -52,7 +52,7 @@ declare class Visual extends Base {
52
52
  * @param effect
53
53
  * @return the layer (for chaining)
54
54
  */
55
- addEffect(effect: BaseEffect): Visual;
55
+ addEffect(effect: VisualEffect): Visual;
56
56
  getDefaultOptions(): VisualOptions;
57
57
  }
58
58
  export { Visual, VisualOptions };
package/dist/movie.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * @module movie
3
3
  */
4
- import { AudioContext } from 'standardized-audio-context';
5
4
  import { Dynamic } from './util';
6
5
  import { Base as BaseLayer } from './layer/index';
7
6
  import { Base as BaseEffect } from './effect/index';
8
7
  declare global {
8
+ interface Window {
9
+ webkitAudioContext: typeof AudioContext;
10
+ }
9
11
  interface HTMLCanvasElement {
10
12
  captureStream(frameRate?: number): MediaStream;
11
13
  }
@@ -30,10 +32,19 @@ export declare class MovieOptions {
30
32
  */
31
33
  export declare class Movie {
32
34
  type: string;
35
+ /**
36
+ * @deprecated Auto-refresh will be removed in the future (see issue #130).
37
+ */
33
38
  publicExcludes: string[];
34
39
  propertyFilters: Record<string, <T>(value: T) => T>;
35
40
  repeat: boolean;
36
- /** Call `refresh` when the user changes a property on the movie or any of its layers or effects */
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
+ */
37
48
  autoRefresh: boolean;
38
49
  /** The background color of the movie as a cSS string */
39
50
  background: Dynamic<string>;
@@ -186,7 +197,5 @@ export declare class Movie {
186
197
  get height(): number;
187
198
  set height(height: number);
188
199
  get movie(): Movie;
189
- getDefaultOptions(): MovieOptions & {
190
- _actx: AudioContext;
191
- };
200
+ getDefaultOptions(): MovieOptions;
192
201
  }
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
@@ -1,6 +1,8 @@
1
1
  // Karma configuration
2
2
  // Generated on Thu Sep 19 2019 02:05:06 GMT-0400 (Eastern Daylight Time)
3
3
 
4
+ process.env.CHROME_BIN = require('puppeteer').executablePath()
5
+
4
6
  module.exports = function (config) {
5
7
  config.set({
6
8
 
@@ -49,7 +51,25 @@ module.exports = function (config) {
49
51
 
50
52
  // start these browsers
51
53
  // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
52
- browsers: ['ChromeHeadless'],
54
+ browsers: ['FirefoxHeadless'],
55
+
56
+ customLaunchers: {
57
+ 'FirefoxHeadless': {
58
+ base: 'Firefox',
59
+ flags: ['-headless'],
60
+ prefs: {
61
+ 'network.proxy.type': 0
62
+ }
63
+ }
64
+ },
65
+
66
+ client: {
67
+ captureConsole: true
68
+ },
69
+
70
+ browserConsoleLogOptions: {
71
+ level: 'log'
72
+ },
53
73
 
54
74
  // Continuous Integration mode
55
75
  // if true, Karma captures browsers, runs the tests and exits
@@ -57,6 +77,12 @@ module.exports = function (config) {
57
77
 
58
78
  // Concurrency level
59
79
  // how many browser should be started simultaneous
60
- concurrency: Infinity
80
+ concurrency: Infinity,
81
+
82
+ client: {
83
+ jasmine: {
84
+ timeoutInterval: 10000
85
+ }
86
+ }
61
87
  })
62
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "etro",
3
- "version": "0.8.3",
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",
@@ -9,9 +9,6 @@
9
9
  "example": "examples",
10
10
  "test": "spec"
11
11
  },
12
- "dependencies": {
13
- "standardized-audio-context": "^25.1.13"
14
- },
15
12
  "devDependencies": {
16
13
  "@types/dom-mediacapture-record": "^1.0.7",
17
14
  "@typescript-eslint/eslint-plugin": "^4.15.2",
@@ -26,30 +23,30 @@
26
23
  "eslint-plugin-promise": "^4.2.1",
27
24
  "eslint-plugin-standard": "^4.0.1",
28
25
  "ev": "0.0.7",
29
- "http-server": "^0.12.3",
26
+ "http-server": "^14.1.1",
30
27
  "jasmine": "^3.4.0",
31
28
  "karma": "^6.1.1",
32
- "karma-chrome-launcher": "^3.1.0",
33
29
  "karma-es6-shim": "^1.0.0",
30
+ "karma-firefox-launcher": "^2.1.2",
34
31
  "karma-jasmine": "^2.0.1",
35
32
  "karma-requirejs": "^1.1.0",
36
33
  "karma-super-dots-reporter": "^0.2.0",
37
34
  "keep-a-changelog": "^0.10.4",
38
35
  "puppeteer": "^2.0.0",
39
- "resemblejs": "^3.2.5",
36
+ "resemblejs": "^4.1.0",
40
37
  "rollup": "^1.19.4",
41
38
  "rollup-plugin-cleaner": "^1.0.0",
42
39
  "rollup-plugin-eslint": "^7.0.0",
43
40
  "rollup-plugin-node-resolve": "^5.2.0",
44
41
  "rollup-plugin-typescript2": "^0.29.0",
45
42
  "rollup-plugin-uglify-es": "^0.0.1",
46
- "shipjs": "0.23.3",
47
- "typedoc": "^0.20.34",
43
+ "shipjs": "^0.24.4",
44
+ "typedoc": "^0.22.11",
48
45
  "typescript": "^4.1.3"
49
46
  },
50
47
  "scripts": {
51
48
  "build": "rollup -c",
52
- "doc": "rm -rf docs && npx typedoc src/etro.ts --excludePrivate --readme none --theme minimal",
49
+ "doc": "rm -rf docs && npx typedoc src/etro.ts --excludePrivate --readme none",
53
50
  "assets": "git fetch origin example-assets:example-assets && git cherry-pick example-assets && git reset --soft HEAD^ && git reset HEAD examples/assets",
54
51
  "effects": "node scripts/save-effect-samples.js",
55
52
  "lint": "npm run --silent lint:main && npm run --silent lint:test && npm run --silent lint:examples",
@@ -43,26 +43,35 @@
43
43
  /**
44
44
  * Save an effect sample to the disk
45
45
  */
46
- function saveSample(original, effect, path) {
47
- // don't overwrite original's contents
48
- const buffer = document.createElement('canvas')
49
- buffer.width = original.width
50
- buffer.height = original.height
51
- const ctx = buffer.getContext('2d')
52
- ctx.drawImage(original, 0, 0)
53
- const movie = {
54
- canvas: buffer, cctx: ctx,
55
- width: original.width, height: original.height
56
- }
57
- // for util.cache()
58
- effect._target = { movie }
59
- // Run effect
60
- effect.apply(movie)
46
+ async function saveSample(original, effect, path) {
47
+ // Create movie (needed for layer to render)
48
+ const movie = new etro.Movie({
49
+ canvas: document.createElement('canvas'),
50
+ autoRefresh: false
51
+ })
52
+
53
+ // Convert canvas to image
54
+ const originalImg = new Image()
55
+ await new Promise(resolve => {
56
+ originalImg.onload = resolve
57
+ originalImg.src = original.toDataURL()
58
+ })
59
+
60
+ // Add an image layer with the effect to the movie
61
+ const layer = new etro.layer.Image({
62
+ startTime: 0,
63
+ duration: 1,
64
+ source: originalImg
65
+ })
66
+ layer.effects.push(effect)
67
+ movie.layers.push(layer)
61
68
 
62
- save(buffer, path)
69
+ // Render and save the layer
70
+ layer.render()
71
+ save(layer.canvas, path)
63
72
  }
64
73
 
65
- window.onload = () => {
74
+ window.onload = async () => {
66
75
  const original = genRandomNoise(16, 16)
67
76
  save(original, 'original.png')
68
77
 
@@ -91,7 +100,7 @@
91
100
 
92
101
  for (let path in samples) {
93
102
  const effect = samples[path]
94
- saveSample(original, effect, path)
103
+ await saveSample(original, effect, path)
95
104
  }
96
105
  window.done = true
97
106
  }
@@ -20,8 +20,13 @@ function createDirs(filePath) {
20
20
  }
21
21
 
22
22
  (async () => {
23
- const browser = await puppeteer.launch()
23
+ const browser = await puppeteer.launch({
24
+ args: ['--autoplay-policy=no-user-gesture-required']
25
+ })
24
26
  const page = await browser.newPage()
27
+ page.on('console', msg => {
28
+ console.log(`[CONSOLE] ${msg.text()}`)
29
+ })
25
30
 
26
31
  await page.goto(`file://${__dirname}/gen-effect-samples.html`)
27
32
  await page.waitForFunction(() => window.done);
@@ -1,11 +1,11 @@
1
1
  import { watchPublic } from '../util'
2
2
  import { publish, subscribe } from '../event'
3
3
  import { Movie } from '../movie'
4
- import { Visual } from '../layer/index'
4
+ import { Base as BaseLayer } from '../layer/index'
5
5
  import BaseObject from '../object'
6
6
 
7
7
  /**
8
- * Modifies the visual contents of a layer.
8
+ * @deprecated All visual effects now inherit from `Visual` instead
9
9
  */
10
10
  export class Base implements BaseObject {
11
11
  type: string
@@ -14,7 +14,7 @@ export class Base implements BaseObject {
14
14
 
15
15
  enabled: boolean
16
16
 
17
- private _target: Movie | Visual
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 | Visual): void {
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 | Visual): void {
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 | Visual, reltime: number): void {} // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
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 | Visual {
99
+ get parent (): Movie | BaseLayer {
100
100
  return this._target
101
101
  }
102
102
 
@@ -1,7 +1,7 @@
1
1
  import { Movie } from '../movie'
2
2
  import { Dynamic, val } from '../util'
3
- import { Base } from './base'
4
- import { Visual } from '../layer/index'
3
+ import { Visual } from './visual'
4
+ import { Visual as VisualLayer } from '../layer/index'
5
5
 
6
6
  export class EllipticalMaskOptions {
7
7
  x: Dynamic<number>
@@ -18,7 +18,7 @@ export class EllipticalMaskOptions {
18
18
  * Preserves an ellipse of the layer and clears the rest
19
19
  */
20
20
  // TODO: Parent layer mask effects will make more complex masks easier
21
- export class EllipticalMask extends Base {
21
+ export class EllipticalMask extends Visual {
22
22
  x: Dynamic<number>
23
23
  y: Dynamic<number>
24
24
  radiusX: Dynamic<number>
@@ -46,7 +46,7 @@ export class EllipticalMask extends Base {
46
46
  this._tmpCtx = this._tmpCanvas.getContext('2d')
47
47
  }
48
48
 
49
- apply (target: Movie | Visual, reltime: number): void {
49
+ apply (target: Movie | VisualLayer, reltime: number): void {
50
50
  const ctx = target.cctx
51
51
  const canvas = target.canvas
52
52
  const x = val(this, 'x', reltime)
@@ -20,3 +20,4 @@ export * from './pixelate'
20
20
  export * from './shader'
21
21
  export * from './stack'
22
22
  export * from './transform'
23
+ export * from './visual'
@@ -1,7 +1,7 @@
1
- import { Visual } from '../layer/index'
1
+ import { Visual as VisualLayer } from '../layer/index'
2
2
  import { Movie } from '../movie'
3
3
  import { val } from '../util'
4
- import { Base } from './base'
4
+ import { Visual } from './visual'
5
5
 
6
6
  export interface UniformOptions {
7
7
  type?: string
@@ -32,7 +32,7 @@ export interface ShaderOptions {
32
32
  * A hardware-accelerated pixel mapping using WebGL
33
33
  */
34
34
  // TODO: can `v_TextureCoord` be replaced by `gl_FragUV`?
35
- export class Shader extends Base {
35
+ export class Shader extends Visual {
36
36
  /**
37
37
  * WebGL texture units consumed by {@link Shader}
38
38
  */
@@ -196,7 +196,7 @@ export class Shader extends Base {
196
196
  }
197
197
  } */
198
198
 
199
- apply (target: Movie | Visual, reltime: number): void {
199
+ apply (target: Movie | VisualLayer, reltime: number): void {
200
200
  this._checkDimensions(target)
201
201
  this._refreshGl()
202
202
 
@@ -1,19 +1,19 @@
1
1
  import { Movie } from '../movie'
2
- import { Base } from './base'
3
- import { Visual } from '../layer'
2
+ import { Visual } from './visual'
3
+ import { Visual as VisualLayer } from '../layer'
4
4
 
5
5
  export interface StackOptions {
6
- effects: Base[]
6
+ effects: Visual[]
7
7
  }
8
8
 
9
9
  /**
10
10
  * A sequence of effects to apply, treated as one effect. This can be useful
11
11
  * for defining reused effect sequences as one effect.
12
12
  */
13
- export class Stack extends Base {
14
- readonly effects: Base[]
13
+ export class Stack extends Visual {
14
+ readonly effects: Visual[]
15
15
 
16
- private _effectsBack: Base[]
16
+ private _effectsBack: Visual[]
17
17
 
18
18
  constructor (options: StackOptions) {
19
19
  super()
@@ -21,13 +21,13 @@ export class Stack extends Base {
21
21
  this._effectsBack = []
22
22
  // TODO: Throw 'change' events in handlers
23
23
  this.effects = new Proxy(this._effectsBack, {
24
- deleteProperty: function (target: Base[], property: number | string): boolean {
24
+ deleteProperty: function (target: Visual[], property: number | string): boolean {
25
25
  const value = target[property]
26
26
  value.detach() // Detach effect from movie
27
27
  delete target[property]
28
28
  return true
29
29
  },
30
- set: function (target: Base[], property: number | string, value: Base): boolean {
30
+ set: function (target: Visual[], property: number | string, value: Visual): boolean {
31
31
  // TODO: make sure type check works
32
32
  if (!isNaN(Number(property))) { // if property is a number (index)
33
33
  if (target[property])
@@ -59,7 +59,7 @@ export class Stack extends Base {
59
59
  })
60
60
  }
61
61
 
62
- apply (target: Movie | Visual, reltime: number): void {
62
+ apply (target: Movie | VisualLayer, reltime: number): void {
63
63
  for (let i = 0; i < this.effects.length; i++) {
64
64
  const effect = this.effects[i]
65
65
  if (!effect) continue
@@ -71,7 +71,7 @@ export class Stack extends Base {
71
71
  * Convenience method for chaining
72
72
  * @param effect - the effect to append
73
73
  */
74
- addEffect (effect: Base): Stack {
74
+ addEffect (effect: Visual): Stack {
75
75
  this.effects.push(effect)
76
76
  return this
77
77
  }
@@ -1,7 +1,7 @@
1
- import { Visual } from '../layer/index'
1
+ import { Visual as VisualLayer } from '../layer/index'
2
2
  import { Movie } from '../movie'
3
3
  import { val, Dynamic } from '../util'
4
- import { Base } from './base'
4
+ import { Visual } from './visual'
5
5
 
6
6
  export interface TransformOptions {
7
7
  matrix: Dynamic<Transform.Matrix> // eslint-disable-line no-use-before-define
@@ -13,7 +13,7 @@ export interface TransformOptions {
13
13
  * translations, scalings and rotations) or B) input the matrix values
14
14
  * directly, using the optional argument in the constructor.
15
15
  */
16
- class Transform extends Base {
16
+ class Transform extends Visual {
17
17
  /** Matrix that determines how to transform the target */
18
18
  matrix: Dynamic<Transform.Matrix>
19
19
 
@@ -35,7 +35,7 @@ class Transform extends Base {
35
35
  this._tmpCtx = this._tmpCanvas.getContext('2d')
36
36
  }
37
37
 
38
- apply (target: Movie | Visual, reltime: number): void {
38
+ apply (target: Movie | VisualLayer, reltime: number): void {
39
39
  if (target.canvas.width !== this._tmpCanvas.width)
40
40
  this._tmpCanvas.width = target.canvas.width
41
41
 
@@ -0,0 +1,21 @@
1
+ import { Movie } from '../movie'
2
+ import { Visual as VisualLayer } from '../layer/index'
3
+ import { Base } from './base'
4
+
5
+ /**
6
+ * Modifies the visual contents of a layer.
7
+ */
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
+ }
@@ -1,4 +1,3 @@
1
- import { AudioContext, IAudioNode, IAudioDestinationNode } from 'standardized-audio-context'
2
1
  import { Movie } from '../movie'
3
2
  import { subscribe } from '../event'
4
3
  import { applyOptions, val } from '../util'
@@ -8,7 +7,7 @@ type Constructor<T> = new (...args: unknown[]) => T
8
7
 
9
8
  interface AudioSource extends Base {
10
9
  readonly source: HTMLMediaElement
11
- readonly audioNode: IAudioNode<AudioContext>
10
+ readonly audioNode: AudioNode
12
11
  playbackRate: number
13
12
  /** The audio source node for the media */
14
13
  sourceStartTime: number
@@ -41,7 +40,7 @@ function AudioSourceMixin<OptionsSuperclass extends BaseOptions> (superclass: Co
41
40
  readonly source: HTMLMediaElement
42
41
 
43
42
  private __startTime: number
44
- private _audioNode: IAudioNode<AudioContext>
43
+ private _audioNode: AudioNode
45
44
  private _sourceStartTime: number
46
45
  private _unstretchedDuration: number
47
46
  private _playbackRate: number
@@ -117,12 +116,12 @@ function AudioSourceMixin<OptionsSuperclass extends BaseOptions> (superclass: Co
117
116
  // Spy on connect and disconnect to remember if it connected to
118
117
  // actx.destination (for Movie#record).
119
118
  const oldConnect = this._audioNode.connect.bind(this.audioNode)
120
- this._audioNode.connect = <T extends IAudioDestinationNode<AudioContext>>(destination: T, outputIndex?: number, inputIndex?: number): AudioNode => {
119
+ this._audioNode.connect = <T extends AudioDestinationNode>(destination: T, outputIndex?: number, inputIndex?: number): AudioNode => {
121
120
  this._connectedToDestination = destination === movie.actx.destination
122
121
  return oldConnect(destination, outputIndex, inputIndex)
123
122
  }
124
123
  const oldDisconnect = this._audioNode.disconnect.bind(this.audioNode)
125
- this._audioNode.disconnect = <T extends IAudioDestinationNode<AudioContext>>(destination?: T | number, output?: number, input?: number): AudioNode => {
124
+ this._audioNode.disconnect = <T extends AudioDestinationNode>(destination?: T | number, output?: number, input?: number): AudioNode => {
126
125
  if (this._connectedToDestination &&
127
126
  destination === movie.actx.destination)
128
127
  this._connectedToDestination = false
@@ -135,7 +134,10 @@ function AudioSourceMixin<OptionsSuperclass extends BaseOptions> (superclass: Co
135
134
  }
136
135
 
137
136
  detach () {
138
- this.audioNode.disconnect(this.movie.actx.destination)
137
+ // Cache dest before super.detach() unsets this.movie
138
+ const dest = this.movie.actx.destination
139
+ super.detach()
140
+ this.audioNode.disconnect(dest)
139
141
  }
140
142
 
141
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 }
@@ -1,7 +1,7 @@
1
- import { Visual, VisualOptions } from './visual'
2
- import { VisualSourceMixin } from './visual-source'
1
+ import { Visual } from './visual'
2
+ import { VisualSourceMixin, VisualSourceOptions } from './visual-source'
3
3
 
4
- type ImageOptions = VisualOptions
4
+ type ImageOptions = VisualSourceOptions
5
5
 
6
6
  class Image extends VisualSourceMixin(Visual) {}
7
7
 
@@ -1,6 +1,6 @@
1
1
  import { Dynamic, val, applyOptions } from '../util'
2
2
  import { Base, BaseOptions } from './base'
3
- import { Base as BaseEffect } from '../effect/base'
3
+ import { Visual as VisualEffect } from '../effect/visual'
4
4
 
5
5
  interface VisualOptions extends BaseOptions {
6
6
  x?: Dynamic<number>
@@ -41,9 +41,9 @@ class Visual extends Base {
41
41
  readonly cctx: CanvasRenderingContext2D
42
42
 
43
43
  // readonly because it's a proxy
44
- readonly effects: BaseEffect[]
44
+ readonly effects: VisualEffect[]
45
45
 
46
- private _effectsBack: BaseEffect[]
46
+ private _effectsBack: VisualEffect[]
47
47
 
48
48
  /**
49
49
  * Creates a visual layer
@@ -142,7 +142,7 @@ class Visual extends Base {
142
142
  * @param effect
143
143
  * @return the layer (for chaining)
144
144
  */
145
- addEffect (effect: BaseEffect): Visual {
145
+ addEffect (effect: VisualEffect): Visual {
146
146
  this.effects.push(effect); return this
147
147
  }
148
148