etro 0.9.0 → 0.10.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/CONTRIBUTING.md +25 -34
  3. package/README.md +9 -17
  4. package/dist/custom-array.d.ts +10 -0
  5. package/dist/effect/base.d.ts +10 -1
  6. package/dist/effect/shader.d.ts +11 -1
  7. package/dist/effect/stack.d.ts +6 -2
  8. package/dist/etro-cjs.js +1182 -592
  9. package/dist/etro-iife.js +1182 -592
  10. package/dist/event.d.ts +10 -5
  11. package/dist/layer/audio-source.d.ts +9 -4
  12. package/dist/layer/audio.d.ts +15 -2
  13. package/dist/layer/base.d.ts +49 -3
  14. package/dist/layer/image.d.ts +15 -1
  15. package/dist/layer/text.d.ts +6 -3
  16. package/dist/layer/video.d.ts +13 -1
  17. package/dist/layer/visual-source.d.ts +18 -3
  18. package/dist/layer/visual.d.ts +11 -7
  19. package/dist/movie/effects.d.ts +6 -0
  20. package/dist/movie/index.d.ts +1 -0
  21. package/dist/movie/layers.d.ts +6 -0
  22. package/dist/movie/movie.d.ts +260 -0
  23. package/dist/object.d.ts +9 -2
  24. package/dist/util.d.ts +4 -10
  25. package/eslint.conf.js +4 -2
  26. package/eslint.test-conf.js +1 -2
  27. package/karma.conf.js +10 -14
  28. package/package.json +23 -22
  29. package/scripts/{gen-effect-samples.html → effect/gen-effect-samples.html} +24 -0
  30. package/scripts/{save-effect-samples.js → effect/save-effect-samples.js} +1 -1
  31. package/src/custom-array.ts +43 -0
  32. package/src/effect/base.ts +23 -22
  33. package/src/effect/gaussian-blur.ts +11 -6
  34. package/src/effect/pixelate.ts +3 -3
  35. package/src/effect/shader.ts +33 -27
  36. package/src/effect/stack.ts +43 -30
  37. package/src/effect/transform.ts +16 -9
  38. package/src/event.ts +111 -21
  39. package/src/layer/audio-source.ts +60 -20
  40. package/src/layer/audio.ts +25 -3
  41. package/src/layer/base.ts +79 -25
  42. package/src/layer/image.ts +26 -2
  43. package/src/layer/text.ts +11 -4
  44. package/src/layer/video.ts +31 -4
  45. package/src/layer/visual-source.ts +70 -8
  46. package/src/layer/visual.ts +57 -35
  47. package/src/movie/effects.ts +26 -0
  48. package/src/movie/index.ts +1 -0
  49. package/src/movie/layers.ts +26 -0
  50. package/src/movie/movie.ts +855 -0
  51. package/src/object.ts +9 -2
  52. package/src/util.ts +68 -89
  53. package/tsconfig.json +3 -1
  54. package/dist/movie.d.ts +0 -201
  55. package/examples/application/readme-screenshot.html +0 -85
  56. package/examples/application/video-player.html +0 -130
  57. package/examples/application/webcam.html +0 -28
  58. package/examples/introduction/audio.html +0 -64
  59. package/examples/introduction/effects.html +0 -79
  60. package/examples/introduction/export.html +0 -83
  61. package/examples/introduction/functions.html +0 -37
  62. package/examples/introduction/hello-world1.html +0 -37
  63. package/examples/introduction/hello-world2.html +0 -32
  64. package/examples/introduction/keyframes.html +0 -79
  65. package/examples/introduction/media.html +0 -63
  66. package/examples/introduction/text.html +0 -31
  67. package/private-todo.txt +0 -70
  68. package/src/movie.ts +0 -742
package/dist/util.d.ts CHANGED
@@ -7,6 +7,10 @@ import { Movie } from './movie';
7
7
  * Merges `options` with `defaultOptions`, and then copies the properties with
8
8
  * the keys in `defaultOptions` from the merged object to `destObj`.
9
9
  *
10
+ * @deprecated Each option should be copied individually, and the default value
11
+ * should be set in the constructor. See
12
+ * {@link https://github.com/etro-js/etro/issues/131} for more info.
13
+ *
10
14
  * @return
11
15
  */
12
16
  export declare function applyOptions(options: object, destObj: EtroObject): void;
@@ -115,13 +119,3 @@ export declare function parseFont(str: string): Font;
115
119
  * @deprecated Use {@link effect.Shader} instead
116
120
  */
117
121
  export declare function mapPixels(mapper: (pixels: Uint8ClampedArray, i: number) => void, canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, flush?: boolean): void;
118
- /**
119
- * <p>Emits "change" event when public properties updated, recursively.
120
- * <p>Must be called before any watchable properties are set, and only once in
121
- * the prototype chain.
122
- *
123
- * @deprecated Will be removed in the future (see issue #130)
124
- *
125
- * @param target - object to watch
126
- */
127
- export declare function watchPublic(target: EtroObject): EtroObject;
package/eslint.conf.js CHANGED
@@ -10,12 +10,14 @@ module.exports = {
10
10
  Atomics: 'readonly',
11
11
  SharedArrayBuffer: 'readonly'
12
12
  },
13
+ parser: '@typescript-eslint/parser',
13
14
  parserOptions: {
15
+ // requireConfigFile: false,
14
16
  ecmaVersion: 2018,
15
17
  sourceType: 'module'
16
18
  },
17
19
  rules: {
18
- 'brace-style': ['error', '1tbs', { allowSingleLine: false }],
19
- curly: ['error', 'multi', 'consistent']
20
+ 'brace-style': ['error', '1tbs'],
21
+ curly: ['error', 'all']
20
22
  },
21
23
  }
@@ -1,5 +1,4 @@
1
1
  const conf = require('./eslint.conf.js')
2
2
  conf.env.jasmine = true
3
- conf.globals.define = 'readonly'
4
- conf.globals.etro = 'readonly'
3
+
5
4
  module.exports = conf
package/karma.conf.js CHANGED
@@ -11,15 +11,13 @@ module.exports = function (config) {
11
11
 
12
12
  // frameworks to use
13
13
  // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
14
- frameworks: ['jasmine', 'requirejs', 'es6-shim'],
14
+ frameworks: ['jasmine', 'karma-typescript'],
15
15
 
16
16
  // list of files / patterns to load in the browser
17
17
  files: [
18
- 'dist/etro-iife.js',
19
- { pattern: 'spec/*.spec.js', included: false },
20
- { pattern: 'node_modules/resemblejs/*.js', included: false },
21
- 'spec/main.js',
22
- { pattern: 'spec/assets/**/*', included: false }
18
+ 'src/**/*.ts',
19
+ 'spec/**/*.ts',
20
+ { pattern: 'spec/integration/assets/**/*', included: false }
23
21
  ],
24
22
 
25
23
  // list of files / patterns to exclude
@@ -29,12 +27,13 @@ module.exports = function (config) {
29
27
  // preprocess matching files before serving them to the browser
30
28
  // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
31
29
  preprocessors: {
30
+ '**/*.ts': ['karma-typescript']
32
31
  },
33
32
 
34
33
  // test results reporter to use
35
34
  // possible values: 'dots', 'progress'
36
35
  // available reporters: https://npmjs.org/browse/keyword/karma-reporter
37
- reporters: ['dots'],
36
+ reporters: ['dots', 'karma-typescript'],
38
37
 
39
38
  // web server port
40
39
  port: 9876,
@@ -64,7 +63,10 @@ module.exports = function (config) {
64
63
  },
65
64
 
66
65
  client: {
67
- captureConsole: true
66
+ captureConsole: true,
67
+ jasmine: {
68
+ timeoutInterval: 20000
69
+ }
68
70
  },
69
71
 
70
72
  browserConsoleLogOptions: {
@@ -78,11 +80,5 @@ module.exports = function (config) {
78
80
  // Concurrency level
79
81
  // how many browser should be started simultaneous
80
82
  concurrency: Infinity,
81
-
82
- client: {
83
- jasmine: {
84
- timeoutInterval: 10000
85
- }
86
- }
87
83
  })
88
84
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "etro",
3
- "version": "0.9.0",
4
- "description": "An extendable video-editing framework for the browser and Node",
3
+ "version": "0.10.0",
4
+ "description": "An extendable video-editing framework for the browser",
5
5
  "browser": "dist/etro-cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "directories": {
@@ -10,49 +10,50 @@
10
10
  "test": "spec"
11
11
  },
12
12
  "devDependencies": {
13
- "@types/dom-mediacapture-record": "^1.0.7",
14
- "@typescript-eslint/eslint-plugin": "^4.15.2",
15
- "@typescript-eslint/parser": "^4.15.2",
13
+ "@rollup/plugin-eslint": "^8.0.2",
14
+ "@types/jest": "^29.0.0",
15
+ "@typescript-eslint/eslint-plugin": "^5.30.7",
16
+ "@typescript-eslint/parser": "^5.30.7",
17
+ "canvas": "^2.11.2",
16
18
  "docdash": "^1.1.1",
17
19
  "ecstatic": ">=4.1.3",
18
- "eslint": "^6.5.1",
19
- "eslint-config-standard": "^14.1.0",
20
- "eslint-plugin-html": "^6.0.0",
21
- "eslint-plugin-import": "^2.18.2",
22
- "eslint-plugin-node": "^10.0.0",
23
- "eslint-plugin-promise": "^4.2.1",
24
- "eslint-plugin-standard": "^4.0.1",
20
+ "eslint": "^8.20.0",
21
+ "eslint-config-standard": "^17.0.0",
22
+ "eslint-plugin-html": "^7.0.0",
23
+ "eslint-plugin-import": "^2.26.0",
24
+ "eslint-plugin-node": "^11.1.0",
25
+ "eslint-plugin-promise": "^6.0.0",
26
+ "eslint-plugin-standard": "^5.0.0",
25
27
  "ev": "0.0.7",
26
28
  "http-server": "^14.1.1",
27
29
  "jasmine": "^3.4.0",
30
+ "jasmine-ts": "^0.4.0",
28
31
  "karma": "^6.1.1",
29
- "karma-es6-shim": "^1.0.0",
30
32
  "karma-firefox-launcher": "^2.1.2",
31
33
  "karma-jasmine": "^2.0.1",
32
- "karma-requirejs": "^1.1.0",
33
34
  "karma-super-dots-reporter": "^0.2.0",
35
+ "karma-typescript": "^5.5.3",
34
36
  "keep-a-changelog": "^0.10.4",
35
37
  "puppeteer": "^2.0.0",
36
38
  "resemblejs": "^4.1.0",
37
39
  "rollup": "^1.19.4",
38
40
  "rollup-plugin-cleaner": "^1.0.0",
39
- "rollup-plugin-eslint": "^7.0.0",
40
41
  "rollup-plugin-node-resolve": "^5.2.0",
41
42
  "rollup-plugin-typescript2": "^0.29.0",
42
43
  "rollup-plugin-uglify-es": "^0.0.1",
43
- "shipjs": "^0.24.4",
44
- "typedoc": "^0.22.11",
45
- "typescript": "^4.1.3"
44
+ "shipjs": "^0.26.3",
45
+ "typedoc": "^0.23.8",
46
+ "typescript": "^4.7.4"
46
47
  },
47
48
  "scripts": {
48
49
  "build": "rollup -c",
49
50
  "doc": "rm -rf docs && npx typedoc src/etro.ts --excludePrivate --readme none",
50
51
  "assets": "git fetch origin example-assets:example-assets && git cherry-pick example-assets && git reset --soft HEAD^ && git reset HEAD examples/assets",
51
- "effects": "node scripts/save-effect-samples.js",
52
+ "effects": "node scripts/effect/save-effect-samples.js",
52
53
  "lint": "npm run --silent lint:main && npm run --silent lint:test && npm run --silent lint:examples",
53
- "lint:main": "eslint -c eslint.typescript-conf.js --ext .ts src",
54
- "lint:test": "eslint -c eslint.test-conf.js spec",
55
- "lint:examples": "eslint -c eslint.example-conf.js --ext .html examples",
54
+ "lint:main": "eslint -c eslint.typescript-conf.js --ext .ts --fix src",
55
+ "lint:test": "eslint -c eslint.test-conf.js --ext .ts --fix spec",
56
+ "lint:examples": "eslint -c eslint.example-conf.js --ext .html --fix examples",
56
57
  "start": "http-server",
57
58
  "test": "karma start",
58
59
  "release": "shipjs prepare"
@@ -76,10 +76,34 @@
76
76
  save(original, 'original.png')
77
77
 
78
78
  const samples = {
79
+ 'brightness.png': new etro.effect.Brightness({
80
+ brightness: -100
81
+ }),
82
+ 'contrast.png': new etro.effect.Contrast({
83
+ contrast: 0.5
84
+ }),
85
+ 'channels.png': new etro.effect.Channels({
86
+ factors: {
87
+ r: 0.25,
88
+ g: 0.5,
89
+ b: 0.75
90
+ }
91
+ }),
92
+ 'chroma-key.png': new etro.effect.ChromaKey({
93
+ target: etro.parseColor('green'),
94
+ threshold: 100
95
+ }),
79
96
  'gaussian-blur-horizontal.png': new etro.effect.GaussianBlurHorizontal({ radius: 5 }),
80
97
  'gaussian-blur-vertical.png': new etro.effect.GaussianBlurVertical({ radius: 5 }),
81
98
  'grayscale.png': new etro.effect.Grayscale(),
82
99
  'pixelate.png': new etro.effect.Pixelate({ pixelSize: 3 }),
100
+ 'shader.png': new etro.effect.Shader(),
101
+ 'stack.png': new etro.effect.Stack({
102
+ effects: [
103
+ new etro.effect.Brightness({ brightness: -100 }),
104
+ new etro.effect.Contrast({ contrast: 0.5 })
105
+ ]
106
+ }),
83
107
  'transform/translate.png': new etro.effect.Transform({
84
108
  matrix: new etro.effect.Transform.Matrix().translate(-3, 5)
85
109
  }),
@@ -39,7 +39,7 @@ function createDirs(filePath) {
39
39
  // remove prefix and save to png
40
40
  const buffer = Buffer.from(item.data.replace(/^data:image\/png;base64,/, ''), 'base64')
41
41
  console.log(`writing ${item.path} ...`)
42
- const path = projectDir + '/spec/assets/effect/' + item.path
42
+ const path = projectDir + '/spec/integration/assets/effect/' + item.path
43
43
  createDirs(path)
44
44
  fs.writeFileSync(path, buffer)
45
45
  })
@@ -0,0 +1,43 @@
1
+ export abstract class CustomArrayListener<T> {
2
+ abstract onAdd(item: T): void
3
+ abstract onRemove(item: T): void
4
+ }
5
+
6
+ /**
7
+ * An array that notifies a listener when items are added or removed.
8
+ */
9
+ export class CustomArray<T> extends Array<T> {
10
+ constructor (target: T[], listener: CustomArrayListener<T>) {
11
+ super()
12
+
13
+ for (const item of target) {
14
+ listener.onAdd(item)
15
+ }
16
+
17
+ // Create proxy
18
+ return new Proxy(target, {
19
+ deleteProperty (target, property): boolean {
20
+ const value = target[property]
21
+ delete target[property]
22
+ listener.onRemove(value)
23
+ return true
24
+ },
25
+
26
+ set (target, property, value): boolean {
27
+ const oldValue = target[property]
28
+ target[property] = value
29
+
30
+ // Check if property is a number (index)
31
+ if (!isNaN(Number(property))) {
32
+ if (oldValue !== undefined) {
33
+ listener.onRemove(oldValue)
34
+ }
35
+
36
+ listener.onAdd(value)
37
+ }
38
+
39
+ return true
40
+ }
41
+ }) as T[]
42
+ }
43
+ }
@@ -1,5 +1,3 @@
1
- import { watchPublic } from '../util'
2
- import { publish, subscribe } from '../event'
3
1
  import { Movie } from '../movie'
4
2
  import { Base as BaseLayer } from '../layer/index'
5
3
  import BaseObject from '../object'
@@ -23,31 +21,24 @@ export class Base implements BaseObject {
23
21
  private _occurrenceCount: number
24
22
 
25
23
  constructor () {
26
- const newThis = watchPublic(this) as Base // proxy that will be returned by constructor
27
-
28
- newThis.enabled = true
29
- newThis._occurrenceCount = 0
30
- newThis._target = null
31
-
32
- // Propogate up to target
33
- subscribe(newThis, 'effect.change.modify', event => {
34
- if (!newThis._target)
35
- return
36
-
37
- const type = `${newThis._target.type}.change.effect.modify`
38
- publish(newThis._target, type, { ...event, target: newThis._target, source: newThis, type })
39
- })
40
-
41
- return newThis
24
+ this.enabled = true
25
+ this._occurrenceCount = 0
26
+ this._target = null
42
27
  }
43
28
 
29
+ /**
30
+ * Wait until this effect is ready to be applied
31
+ */
32
+ async whenReady (): Promise<void> {} // eslint-disable-line @typescript-eslint/no-empty-function
33
+
44
34
  /**
45
35
  * Attaches this effect to `target` if not already attached.
46
36
  * @ignore
47
37
  */
48
38
  tryAttach (target: Movie | BaseLayer): void {
49
- if (this._occurrenceCount === 0)
39
+ if (this._occurrenceCount === 0) {
50
40
  this.attach(target)
41
+ }
51
42
 
52
43
  this._occurrenceCount++
53
44
  }
@@ -57,21 +48,23 @@ export class Base implements BaseObject {
57
48
  }
58
49
 
59
50
  /**
60
- * Dettaches this effect from its target if the number of times `tryDetach`
51
+ * Detaches this effect from its target if the number of times `tryDetach`
61
52
  * has been called (including this call) equals the number of times
62
53
  * `tryAttach` has been called.
63
54
  *
64
55
  * @ignore
65
56
  */
66
57
  tryDetach (): void {
67
- if (this._target === null)
58
+ if (this._target === null) {
68
59
  throw new Error('No movie to detach from')
60
+ }
69
61
 
70
62
  this._occurrenceCount--
71
63
  // If this effect occurs in another place in the containing array, do not
72
64
  // unset _target. (For calling `unshift` on the `layers` proxy)
73
- if (this._occurrenceCount === 0)
65
+ if (this._occurrenceCount === 0) {
74
66
  this.detach()
67
+ }
75
68
  }
76
69
 
77
70
  detach (): void {
@@ -96,6 +89,11 @@ export class Base implements BaseObject {
96
89
  return this._target ? this._target.currentTime : undefined
97
90
  }
98
91
 
92
+ /** `true` if this effect is ready to be applied */
93
+ get ready (): boolean {
94
+ return true
95
+ }
96
+
99
97
  get parent (): Movie | BaseLayer {
100
98
  return this._target
101
99
  }
@@ -104,6 +102,9 @@ export class Base implements BaseObject {
104
102
  return this._target ? this._target.movie : undefined
105
103
  }
106
104
 
105
+ /**
106
+ * @deprecated See {@link https://github.com/etro-js/etro/issues/131}
107
+ */
107
108
  getDefaultOptions (): Record<string, unknown> {
108
109
  return {}
109
110
  }
@@ -12,7 +12,7 @@ export interface GaussianBlurOptions {
12
12
  * Applies a Gaussian blur
13
13
  */
14
14
  // TODO: Improve performance
15
- // TODO: Make sure this is truly gaussian even though it doens't require a
15
+ // TODO: Make sure this is truly gaussian even though it doesn't require a
16
16
  // standard deviation
17
17
  export class GaussianBlur extends Stack {
18
18
  constructor (options: GaussianBlurOptions) {
@@ -63,11 +63,12 @@ class GaussianBlurComponent extends Shader {
63
63
 
64
64
  apply (target: Movie | Visual, reltime: number): void {
65
65
  const radiusVal = val(this, 'radius', reltime)
66
- if (radiusVal !== this._radiusCache)
66
+ if (radiusVal !== this._radiusCache) {
67
67
  // Regenerate gaussian distribution canvas.
68
68
  this.shape = GaussianBlurComponent._render1DKernel(
69
69
  GaussianBlurComponent._gen1DKernel(radiusVal)
70
70
  )
71
+ }
71
72
 
72
73
  this._radiusCache = radiusVal
73
74
 
@@ -106,18 +107,21 @@ class GaussianBlurComponent extends Shader {
106
107
  const pascal = GaussianBlurComponent._genPascalRow(2 * radius + 1)
107
108
  // don't use `reduce` and `map` (overhead?)
108
109
  let sum = 0
109
- for (let i = 0; i < pascal.length; i++)
110
+ for (let i = 0; i < pascal.length; i++) {
110
111
  sum += pascal[i]
112
+ }
111
113
 
112
- for (let i = 0; i < pascal.length; i++)
114
+ for (let i = 0; i < pascal.length; i++) {
113
115
  pascal[i] /= sum
116
+ }
114
117
 
115
118
  return pascal
116
119
  }
117
120
 
118
121
  private static _genPascalRow (index: number): number[] {
119
- if (index < 0)
122
+ if (index < 0) {
120
123
  throw new Error(`Invalid index ${index}`)
124
+ }
121
125
 
122
126
  let currRow = [1]
123
127
  for (let i = 1; i < index; i++) {
@@ -125,8 +129,9 @@ class GaussianBlurComponent extends Shader {
125
129
  nextRow.length = currRow.length + 1
126
130
  // edges are always 1's
127
131
  nextRow[0] = nextRow[nextRow.length - 1] = 1
128
- for (let j = 1; j < nextRow.length - 1; j++)
132
+ for (let j = 1; j < nextRow.length - 1; j++) {
129
133
  nextRow[j] = currRow[j - 1] + currRow[j]
134
+ }
130
135
 
131
136
  currRow = nextRow
132
137
  }
@@ -43,15 +43,15 @@ export class Pixelate extends Shader {
43
43
  pixelSize: '1i'
44
44
  }
45
45
  })
46
- /**
47
- */
46
+
48
47
  this.pixelSize = options.pixelSize || 1
49
48
  }
50
49
 
51
50
  apply (target: Movie | Visual, reltime: number): void {
52
51
  const ps = val(this, 'pixelSize', reltime)
53
- if (ps % 1 !== 0 || ps < 0)
52
+ if (ps % 1 !== 0 || ps < 0) {
54
53
  throw new Error('Pixel size must be a nonnegative integer')
54
+ }
55
55
 
56
56
  super.apply(target, reltime)
57
57
  }
@@ -4,6 +4,9 @@ import { val } from '../util'
4
4
  import { Visual } from './visual'
5
5
 
6
6
  export interface UniformOptions {
7
+ /**
8
+ * The type of the uniform.
9
+ */
7
10
  type?: string
8
11
  defaultFloatComponent?: number
9
12
  }
@@ -117,8 +120,9 @@ export class Shader extends Visual {
117
120
  private _initGl () {
118
121
  this._canvas = document.createElement('canvas')
119
122
  const gl = this._canvas.getContext('webgl')
120
- if (gl === null)
123
+ if (gl === null) {
121
124
  throw new Error('Unable to initialize WebGL. Your browser or machine may not support it.')
125
+ }
122
126
 
123
127
  this._gl = gl
124
128
  return gl
@@ -127,8 +131,9 @@ export class Shader extends Visual {
127
131
  private _initTextures (userUniforms, userTextures, sourceTextureOptions) {
128
132
  const gl = this._gl
129
133
  const maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)
130
- if (userTextures.length > maxTextures)
134
+ if (userTextures.length > maxTextures) {
131
135
  console.warn('Too many textures!')
136
+ }
132
137
 
133
138
  this._userTextures = {}
134
139
  for (const name in userTextures) {
@@ -143,8 +148,9 @@ export class Shader extends Visual {
143
148
  * textures, without having to define multiple properties in the effect
144
149
  * object.
145
150
  */
146
- if (userUniforms[name])
151
+ if (userUniforms[name]) {
147
152
  throw new Error(`Texture - uniform naming conflict: ${name}!`)
153
+ }
148
154
 
149
155
  // Add this as a "user uniform".
150
156
  userUniforms[name] = '1i' // texture pointer
@@ -183,19 +189,6 @@ export class Shader extends Visual {
183
189
  }
184
190
  }
185
191
 
186
- // Not needed, right?
187
- /* watchWebGLOptions() {
188
- const pubChange = () => {
189
- this.publish("change", {});
190
- };
191
- for (let name in this._userTextures) {
192
- watch(this, name, pubChange);
193
- }
194
- for (let name in this._userUniforms) {
195
- watch(this, name, pubChange);
196
- }
197
- } */
198
-
199
192
  apply (target: Movie | VisualLayer, reltime: number): void {
200
193
  this._checkDimensions(target)
201
194
  this._refreshGl()
@@ -303,18 +296,24 @@ export class Shader extends Visual {
303
296
  }
304
297
  }
305
298
 
299
+ /**
300
+ * Set the shader's uniforms.
301
+ * @param target The movie or layer to apply the shader to.
302
+ * @param reltime The relative time of the movie or layer.
303
+ */
306
304
  private _prepareUniforms (target, reltime) {
307
305
  const gl = this._gl
308
- // Set the shader uniforms.
309
306
 
310
307
  // Tell the shader we bound the texture to texture unit 0.
311
308
  // All base (Shader class) uniforms are optional.
312
- if (this._uniformLocations.source)
309
+ if (this._uniformLocations.source) {
313
310
  gl.uniform1i(this._uniformLocations.source, 0)
311
+ }
314
312
 
315
313
  // All base (Shader class) uniforms are optional.
316
- if (this._uniformLocations.size)
314
+ if (this._uniformLocations.size) {
317
315
  gl.uniform2iv(this._uniformLocations.size, [target.canvas.width, target.canvas.height])
316
+ }
318
317
 
319
318
  for (const unprefixed in this._userUniforms) {
320
319
  const options = this._userUniforms[unprefixed] as UniformOptions
@@ -343,11 +342,13 @@ export class Shader extends Visual {
343
342
  /**
344
343
  * Converts a value of a standard type for javascript to a standard type for
345
344
  * GLSL
345
+ *
346
346
  * @param value - the raw value to prepare
347
347
  * @param outputType - the WebGL type of |value|; example:
348
348
  * <code>1f</code> for a float
349
349
  * @param reltime - current time, relative to the target
350
- * @param [options] - Optional config
350
+ * @param [options]
351
+ * @returns the prepared value
351
352
  */
352
353
  private _prepareValue (value, outputType, reltime, options: UniformOptions = {}) {
353
354
  const def = options.defaultFloatComponent || 0
@@ -369,8 +370,9 @@ export class Shader extends Visual {
369
370
  let i = 0
370
371
  for (const name in this._userTextures) {
371
372
  const testValue = val(this, name, reltime)
372
- if (value === testValue)
373
+ if (value === testValue) {
373
374
  value = Shader.INTERNAL_TEXTURE_UNITS + i // after the internal texture units
375
+ }
374
376
 
375
377
  i++
376
378
  }
@@ -378,32 +380,36 @@ export class Shader extends Visual {
378
380
 
379
381
  if (outputType === '3fv') {
380
382
  // allow 4-component vectors; TODO: why?
381
- if (Array.isArray(value) && (value.length === 3 || value.length === 4))
383
+ if (Array.isArray(value) && (value.length === 3 || value.length === 4)) {
382
384
  return value
385
+ }
383
386
 
384
387
  // kind of loose so this can be changed if needed
385
- if (typeof value === 'object')
388
+ if (typeof value === 'object') {
386
389
  return [
387
390
  value.r !== undefined ? value.r : def,
388
391
  value.g !== undefined ? value.g : def,
389
392
  value.b !== undefined ? value.b : def
390
393
  ]
394
+ }
391
395
 
392
396
  throw new Error(`Invalid type: ${outputType} or value: ${value}`)
393
397
  }
394
398
 
395
399
  if (outputType === '4fv') {
396
- if (Array.isArray(value) && value.length === 4)
400
+ if (Array.isArray(value) && value.length === 4) {
397
401
  return value
402
+ }
398
403
 
399
404
  // kind of loose so this can be changed if needed
400
- if (typeof value === 'object')
405
+ if (typeof value === 'object') {
401
406
  return [
402
407
  value.r !== undefined ? value.r : def,
403
408
  value.g !== undefined ? value.g : def,
404
409
  value.b !== undefined ? value.b : def,
405
410
  value.a !== undefined ? value.a : def
406
411
  ]
412
+ }
407
413
 
408
414
  throw new Error(`Invalid type: ${outputType} or value: ${value}`)
409
415
  }
@@ -509,8 +515,9 @@ export class Shader extends Visual {
509
515
  } else {
510
516
  // No, it's not a power of 2. Turn off mips and set
511
517
  // wrapping to clamp to edge
512
- if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE)
518
+ if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE) {
513
519
  console.warn('Wrap mode is not CLAMP_TO_EDGE for a non-power-of-two texture. Defaulting to CLAMP_TO_EDGE')
520
+ }
514
521
 
515
522
  gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
516
523
  gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
@@ -552,6 +559,5 @@ export class Shader extends Visual {
552
559
  return shader
553
560
  }
554
561
  }
555
- // Shader.prototype.getpublicExcludes = () =>
556
562
 
557
563
  const isPowerOf2 = value => (value && (value - 1)) === 0