etro 0.6.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 (157) hide show
  1. package/.github/workflows/nodejs.yml +4 -2
  2. package/CHANGELOG.md +85 -4
  3. package/CODE_OF_CONDUCT.md +5 -5
  4. package/CONTRIBUTING.md +33 -79
  5. package/README.md +93 -26
  6. package/dist/effect/base.d.ts +51 -0
  7. package/dist/effect/brightness.d.ts +16 -0
  8. package/dist/effect/channels.d.ts +23 -0
  9. package/dist/effect/chroma-key.d.ts +23 -0
  10. package/dist/effect/contrast.d.ts +15 -0
  11. package/dist/effect/elliptical-mask.d.ts +31 -0
  12. package/dist/effect/gaussian-blur.d.ts +60 -0
  13. package/dist/effect/grayscale.d.ts +7 -0
  14. package/dist/effect/index.d.ts +15 -0
  15. package/dist/effect/pixelate.d.ts +18 -0
  16. package/dist/effect/shader.d.ts +99 -0
  17. package/dist/effect/stack.d.ts +23 -0
  18. package/dist/effect/transform.d.ts +73 -0
  19. package/dist/etro-cjs.js +9387 -0
  20. package/dist/etro-iife.js +9390 -0
  21. package/dist/etro.d.ts +7 -0
  22. package/dist/event.d.ts +35 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/layer/audio-source.d.ts +24 -0
  25. package/dist/layer/audio.d.ts +14 -0
  26. package/dist/layer/base.d.ts +82 -0
  27. package/dist/layer/image.d.ts +6 -0
  28. package/dist/layer/index.d.ts +11 -0
  29. package/dist/layer/text.d.ts +60 -0
  30. package/dist/layer/video.d.ts +11 -0
  31. package/dist/layer/visual-source.d.ts +32 -0
  32. package/dist/layer/visual.d.ts +58 -0
  33. package/dist/movie.d.ts +192 -0
  34. package/dist/object.d.ts +12 -0
  35. package/dist/util.d.ts +125 -0
  36. package/eslint.conf.js +2 -9
  37. package/eslint.example-conf.js +9 -0
  38. package/eslint.test-conf.js +1 -0
  39. package/eslint.typescript-conf.js +5 -0
  40. package/examples/application/readme-screenshot.html +16 -17
  41. package/examples/application/video-player.html +10 -11
  42. package/examples/application/webcam.html +6 -6
  43. package/examples/introduction/audio.html +30 -18
  44. package/examples/introduction/effects.html +37 -14
  45. package/examples/introduction/export.html +40 -27
  46. package/examples/introduction/functions.html +6 -4
  47. package/examples/introduction/hello-world1.html +9 -5
  48. package/examples/introduction/hello-world2.html +5 -5
  49. package/examples/introduction/keyframes.html +35 -23
  50. package/examples/introduction/media.html +26 -18
  51. package/examples/introduction/text.html +9 -5
  52. package/karma.conf.js +6 -4
  53. package/package.json +34 -13
  54. package/rollup.config.js +19 -3
  55. package/scripts/gen-effect-samples.html +27 -26
  56. package/scripts/save-effect-samples.js +14 -15
  57. package/src/effect/base.ts +115 -0
  58. package/src/effect/brightness.ts +43 -0
  59. package/src/effect/channels.ts +50 -0
  60. package/src/effect/chroma-key.ts +82 -0
  61. package/src/effect/contrast.ts +42 -0
  62. package/src/effect/elliptical-mask.ts +75 -0
  63. package/src/effect/gaussian-blur.ts +232 -0
  64. package/src/effect/grayscale.ts +34 -0
  65. package/src/effect/index.ts +22 -0
  66. package/src/effect/pixelate.ts +58 -0
  67. package/src/effect/shader.ts +557 -0
  68. package/src/effect/stack.ts +77 -0
  69. package/src/effect/transform.ts +193 -0
  70. package/src/etro.ts +26 -0
  71. package/src/event.ts +112 -0
  72. package/src/index.ts +8 -0
  73. package/src/layer/audio-source.ts +219 -0
  74. package/src/layer/audio.ts +34 -0
  75. package/src/layer/base.ts +175 -0
  76. package/src/layer/image.ts +8 -0
  77. package/src/layer/index.ts +13 -0
  78. package/src/layer/text.ts +138 -0
  79. package/src/layer/video.ts +15 -0
  80. package/src/layer/visual-source.ts +150 -0
  81. package/src/layer/visual.ts +197 -0
  82. package/src/movie.ts +701 -0
  83. package/src/object.ts +14 -0
  84. package/src/util.ts +466 -0
  85. package/tsconfig.json +8 -0
  86. package/dist/etro.js +0 -3397
  87. package/docs/effect.js.html +0 -1215
  88. package/docs/event.js.html +0 -145
  89. package/docs/index.html +0 -81
  90. package/docs/index.js.html +0 -92
  91. package/docs/layer.js.html +0 -888
  92. package/docs/module-effect-GaussianBlurComponent.html +0 -345
  93. package/docs/module-effect.Brightness.html +0 -339
  94. package/docs/module-effect.Channels.html +0 -319
  95. package/docs/module-effect.ChromaKey.html +0 -611
  96. package/docs/module-effect.Contrast.html +0 -339
  97. package/docs/module-effect.EllipticalMask.html +0 -200
  98. package/docs/module-effect.GaussianBlur.html +0 -202
  99. package/docs/module-effect.GaussianBlurHorizontal.html +0 -242
  100. package/docs/module-effect.GaussianBlurVertical.html +0 -242
  101. package/docs/module-effect.Pixelate.html +0 -330
  102. package/docs/module-effect.Shader.html +0 -1227
  103. package/docs/module-effect.Stack.html +0 -406
  104. package/docs/module-effect.Transform.Matrix.html +0 -193
  105. package/docs/module-effect.Transform.html +0 -1174
  106. package/docs/module-effect.html +0 -148
  107. package/docs/module-event.html +0 -473
  108. package/docs/module-index.html +0 -186
  109. package/docs/module-layer-Media.html +0 -1116
  110. package/docs/module-layer-MediaMixin.html +0 -164
  111. package/docs/module-layer.Audio.html +0 -1188
  112. package/docs/module-layer.Base.html +0 -629
  113. package/docs/module-layer.Image.html +0 -1421
  114. package/docs/module-layer.Text.html +0 -1731
  115. package/docs/module-layer.Video.html +0 -1938
  116. package/docs/module-layer.Visual.html +0 -1698
  117. package/docs/module-layer.html +0 -137
  118. package/docs/module-movie.html +0 -3118
  119. package/docs/module-util.Color.html +0 -702
  120. package/docs/module-util.Font.html +0 -395
  121. package/docs/module-util.html +0 -845
  122. package/docs/movie.js.html +0 -689
  123. package/docs/scripts/collapse.js +0 -20
  124. package/docs/scripts/linenumber.js +0 -25
  125. package/docs/scripts/nav.js +0 -12
  126. package/docs/scripts/polyfill.js +0 -4
  127. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
  128. package/docs/scripts/prettify/lang-css.js +0 -2
  129. package/docs/scripts/prettify/prettify.js +0 -28
  130. package/docs/scripts/search.js +0 -83
  131. package/docs/styles/jsdoc.css +0 -671
  132. package/docs/styles/prettify.css +0 -79
  133. package/docs/util.js.html +0 -503
  134. package/screenshots/2019-08-17_0.png +0 -0
  135. package/spec/assets/effect/gaussian-blur-horizontal.png +0 -0
  136. package/spec/assets/effect/gaussian-blur-vertical.png +0 -0
  137. package/spec/assets/effect/original.png +0 -0
  138. package/spec/assets/effect/pixelate.png +0 -0
  139. package/spec/assets/effect/transform/multiply.png +0 -0
  140. package/spec/assets/effect/transform/rotate.png +0 -0
  141. package/spec/assets/effect/transform/scale-fraction.png +0 -0
  142. package/spec/assets/effect/transform/scale.png +0 -0
  143. package/spec/assets/effect/transform/translate-fraction.png +0 -0
  144. package/spec/assets/effect/transform/translate.png +0 -0
  145. package/spec/assets/layer/audio.wav +0 -0
  146. package/spec/assets/layer/image.jpg +0 -0
  147. package/spec/effect.spec.js +0 -352
  148. package/spec/event.spec.js +0 -25
  149. package/spec/layer.spec.js +0 -128
  150. package/spec/movie.spec.js +0 -154
  151. package/spec/util.spec.js +0 -285
  152. package/src/effect.js +0 -1265
  153. package/src/event.js +0 -78
  154. package/src/index.js +0 -23
  155. package/src/layer.js +0 -875
  156. package/src/movie.js +0 -636
  157. package/src/util.js +0 -487
@@ -2,10 +2,10 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Keyframes in Etro</title>
5
+ <script src="../../dist/etro-iife.js"></script>
5
6
  </head>
6
7
  <body>
7
- <script type="module">
8
- import etro from '../../src/index.js'
8
+ <script>
9
9
  let movie
10
10
  window.addEventListener('load', () => {
11
11
  const canvas = document.createElement('canvas')
@@ -15,7 +15,7 @@
15
15
  })
16
16
 
17
17
  const initMovie = canvas => {
18
- movie = new etro.Movie(canvas)
18
+ movie = new etro.Movie({ canvas })
19
19
 
20
20
  canvas.width = canvas.height = 400
21
21
  movie
@@ -23,42 +23,54 @@
23
23
  // Keyframes let you make a dynamic property that interpolates.
24
24
  // For instance, you can set a layer's opacity to decrease over time, effectively making it fade out
25
25
  // Numbers and objects interpolate (animate smoothly)
26
- .addLayer(new etro.layer.Visual(0, 3, {
26
+ .addLayer(new etro.layer.Visual({
27
+ startTime: 0,
28
+ duration: 3,
27
29
  // omitting width or height sets the respective element to fill the screen
28
30
  background: 'green',
29
31
  // opacity=1 @ 0s (relative to the layer) -> opacity=0 @ 1s (relative to the layer)
30
- opacity: { 0: 1, 3: 0 }
32
+ opacity: new etro.KeyFrame([0, 1], [3, 0])
31
33
  }))
32
34
  // Because strings don't interpolate, you need to convert colors and fonts to objects
33
35
  // for a smooth effect (which will then be automatically `.toString()`ed when set on the canvas
34
36
  // context).
35
- .addLayer(new etro.layer.Visual(3, 3, {
36
- background: { 0: etro.parseColor('red'), 3: new etro.Color(0, 0, 255) }
37
+ .addLayer(new etro.layer.Visual({
38
+ startTime: 3,
39
+ duration: 3,
40
+ background: new etro.KeyFrame([0, etro.parseColor('red')], [3, new etro.Color(0, 0, 255)])
37
41
  }))
38
42
  // You can use other types in keyframes, but they will be used sequentially without interpolation
39
- .addLayer(new etro.layer.Text(6, 3, { 0: 'Hello ...', 1.5: '...world' }))
43
+ .addLayer(new etro.layer.Text({
44
+ startTime: 6,
45
+ duration: 3,
46
+ text: new etro.KeyFrame([0, 'Hello ...'], [1.5, '...world'])
47
+ }))
40
48
 
41
49
  // When interpolating, you can specify how the keyframes will be interpolated
42
- .addLayer(new etro.layer.Visual(9, 3, {
43
- width: { 0: movie.width, 3: 0, interpolate: etro.linearInterp }, // (obviously) linear
44
- height: { 0: movie.height, 3: 0, interpolate: etro.cosineInterp }, // curved
50
+ .addLayer(new etro.layer.Visual({
51
+ startTime: 9,
52
+ duration: 3,
53
+ width: new etro.KeyFrame([0, movie.width, etro.linearInterp], [3, 0]), // (obviously) linear
54
+ height: new etro.KeyFrame([0, movie.height, etro.linearInterp], [3, 0]), // (obviously) linear
45
55
  background: 'blue'
46
56
  }))
47
57
 
48
58
  // Of course, you can have more than two keyframes
49
- .addLayer(new etro.layer.Text(12, 6, 'Etro', {
50
- background: {
51
- 0: etro.parseColor('#0ff'),
52
- 2: etro.parseColor('#ff0'),
53
- 4: etro.parseColor('#f0f'),
54
- 6: etro.parseColor('#fff')
55
- },
59
+ .addLayer(new etro.layer.Text({
60
+ text: 'Etro',
61
+ startTime: 12,
62
+ duration: 6,
63
+ background: new etro.KeyFrame(
64
+ [0, etro.parseColor('#0ff')],
65
+ [2, etro.parseColor('#ff0')],
66
+ [4, etro.parseColor('#f0f')],
67
+ [6, etro.parseColor('#fff')]
68
+ ),
56
69
  // let's just add another property (fonts can be parsed into objects just like colors)
57
- font: {
58
- 0: etro.parseFont('28px monospace'),
59
- 6: etro.parseFont('36px monospace'),
60
- interpolate: etro.cosineInterp
61
- }
70
+ font: new etro.KeyFrame(
71
+ [0, etro.parseFont('28px monospace'), etro.cosineInterp],
72
+ [6, etro.parseFont('36px monospace')]
73
+ )
62
74
  }))
63
75
  .play()
64
76
  }
@@ -2,14 +2,18 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Media in Etro</title>
5
+ <script src="../../dist/etro-iife.js"></script>
5
6
  <style> img, video {display: none;} </style>
6
7
  </head>
7
8
  <body>
8
- <script type="module">
9
- import etro from '../../src/index.js'
10
-
11
- let movie
12
- window.addEventListener('load', () => {
9
+ <img src="../assets/lake.jpg"/>
10
+ <video src="../assets/desert.mp4"></video>
11
+ <audio src="../assets/strings.wav"></audio>
12
+ <button>Start</button>
13
+ <script>
14
+ const button = document.querySelector('button')
15
+ button.addEventListener('click', () => {
16
+ button.disabled = true
13
17
  const canvas = document.createElement('canvas')
14
18
  canvas.width = 600
15
19
  canvas.height = 400
@@ -19,37 +23,41 @@
19
23
  })
20
24
 
21
25
  const initMovie = canvas => {
22
- movie = new etro.Movie(canvas)
26
+ const movie = new etro.Movie({ canvas })
23
27
  const video = document.querySelector('video')
24
28
  movie.width = video.videoWidth
25
29
  movie.height = video.videoHeight
26
30
  movie
27
- .addLayer(new etro.layer.Image(0, 3, document.querySelector('img'), {
31
+ .addLayer(new etro.layer.Image({
32
+ startTime: 0,
33
+ duration: 3,
34
+ source: document.querySelector('img'),
28
35
  // crop @ (150, 150) extending (200, 200)
29
- clipX: 100,
30
- clipY: 100,
36
+ sourceX: 100,
37
+ sourceY: 100,
38
+ sourceWidth: 400,
39
+ sourceHeight: 400,
31
40
  x: 100,
32
41
  y: 100,
33
- clipWidth: 400,
34
- clipHeight: 400,
35
42
  width: 400,
36
43
  height: 400
37
44
  }))
38
- .addLayer(new etro.layer.Video(3, video, {
45
+ .addLayer(new etro.layer.Video({
46
+ source: video,
47
+ startTime: 3,
39
48
  // trim video to only include 3 seconds starting 2 minutes into the video in the video
40
- mediaStartTime: 120,
49
+ sourceStartTime: 5,
41
50
  duration: 3
42
51
  }))
43
- .addLayer(new etro.layer.Audio(6, document.querySelector('audio'), {
44
- mediaStartTime: 9, // start audio at 9s
52
+ .addLayer(new etro.layer.Audio({
53
+ startTime: 6,
54
+ source: document.querySelector('audio'),
55
+ sourceStartTime: 9, // start audio at 9s
45
56
  duration: 3 // last 3s
46
57
  // volume: 0.25 // 25% of default volume (same as setting volume attribute on audio element)
47
58
  }))
48
59
  .play()
49
60
  }
50
61
  </script>
51
- <img src="../assets/sample.jpg"/>
52
- <video src="../assets/sample.ogv"></video>
53
- <audio src="../assets/sample.wav"></audio>
54
62
  </body>
55
63
  </html>
@@ -2,10 +2,10 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Text in Etro</title>
5
+ <script src="../../dist/etro-iife.js"></script>
5
6
  </head>
6
7
  <body>
7
- <script type="module">
8
- import etro from '../../src/index.js'
8
+ <script>
9
9
  let movie
10
10
  window.addEventListener('load', () => {
11
11
  const canvas = document.createElement('canvas')
@@ -17,9 +17,13 @@
17
17
  })
18
18
 
19
19
  const initMovie = canvas => {
20
- movie = new etro.Movie(canvas)
21
- movie.addLayer(new etro.layer.Text(0, 4, 'Hello world', {
22
- font: '24px monospace', color: 'blue'
20
+ movie = new etro.Movie({ canvas })
21
+ movie.addLayer(new etro.layer.Text({
22
+ startTime: 0,
23
+ duration: 4,
24
+ text: 'Hello world',
25
+ font: '24px monospace',
26
+ color: 'blue'
23
27
  })).play()
24
28
  }
25
29
  </script>
package/karma.conf.js CHANGED
@@ -9,12 +9,14 @@ module.exports = function (config) {
9
9
 
10
10
  // frameworks to use
11
11
  // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
12
- frameworks: ['jasmine'],
12
+ frameworks: ['jasmine', 'requirejs', 'es6-shim'],
13
13
 
14
14
  // list of files / patterns to load in the browser
15
15
  files: [
16
- 'dist/etro.js',
17
- 'spec/*.spec.js',
16
+ 'dist/etro-iife.js',
17
+ { pattern: 'spec/*.spec.js', included: false },
18
+ { pattern: 'node_modules/resemblejs/*.js', included: false },
19
+ 'spec/main.js',
18
20
  { pattern: 'spec/assets/**/*', included: false }
19
21
  ],
20
22
 
@@ -30,7 +32,7 @@ module.exports = function (config) {
30
32
  // test results reporter to use
31
33
  // possible values: 'dots', 'progress'
32
34
  // available reporters: https://npmjs.org/browse/keyword/karma-reporter
33
- reporters: ['progress'],
35
+ reporters: ['dots'],
34
36
 
35
37
  // web server port
36
38
  port: 9876,
package/package.json CHANGED
@@ -1,16 +1,23 @@
1
1
  {
2
2
  "name": "etro",
3
- "version": "0.6.0",
4
- "description": "A flexible video-editing library for the browser",
5
- "browser": "src/index.js",
3
+ "version": "0.8.1",
4
+ "description": "An extendable video-editing framework for the browser and Node",
5
+ "browser": "dist/etro-cjs.js",
6
+ "types": "dist/index.d.ts",
6
7
  "directories": {
7
8
  "doc": "docs",
8
9
  "example": "examples",
9
10
  "test": "spec"
10
11
  },
11
- "dependencies": {},
12
+ "dependencies": {
13
+ "standardized-audio-context": "^25.1.13"
14
+ },
12
15
  "devDependencies": {
16
+ "@types/dom-mediacapture-record": "^1.0.7",
17
+ "@typescript-eslint/eslint-plugin": "^4.15.2",
18
+ "@typescript-eslint/parser": "^4.15.2",
13
19
  "docdash": "^1.1.1",
20
+ "ecstatic": ">=4.1.3",
14
21
  "eslint": "^6.5.1",
15
22
  "eslint-config-standard": "^14.1.0",
16
23
  "eslint-plugin-html": "^6.0.0",
@@ -19,28 +26,36 @@
19
26
  "eslint-plugin-promise": "^4.2.1",
20
27
  "eslint-plugin-standard": "^4.0.1",
21
28
  "ev": "0.0.7",
22
- "http-server": "^0.11.1",
29
+ "http-server": "^0.12.3",
23
30
  "jasmine": "^3.4.0",
24
31
  "jsdoc": "^3.6.3",
25
32
  "jsdoc-export-default-interop": "^0.3.1",
26
- "karma": "^4.3.0",
33
+ "karma": "^6.1.1",
27
34
  "karma-chrome-launcher": "^3.1.0",
35
+ "karma-es6-shim": "^1.0.0",
28
36
  "karma-jasmine": "^2.0.1",
37
+ "karma-requirejs": "^1.1.0",
38
+ "karma-super-dots-reporter": "^0.2.0",
29
39
  "puppeteer": "^2.0.0",
40
+ "resemblejs": "^3.2.5",
30
41
  "rollup": "^1.19.4",
42
+ "rollup-plugin-cleaner": "^1.0.0",
31
43
  "rollup-plugin-eslint": "^7.0.0",
32
44
  "rollup-plugin-node-resolve": "^5.2.0",
33
- "rollup-plugin-uglify-es": "^0.0.1"
45
+ "rollup-plugin-typescript2": "^0.29.0",
46
+ "rollup-plugin-uglify-es": "^0.0.1",
47
+ "typedoc": "^0.20.34",
48
+ "typescript": "^4.1.3"
34
49
  },
35
50
  "scripts": {
36
51
  "build": "rollup -c",
37
- "doc": "rm -rf docs && npx jsdoc -r src -d docs -t node_modules/docdash",
52
+ "doc": "rm -rf docs && npx typedoc src/etro.ts --excludePrivate --readme none --theme minimal",
53
+ "assets": "git fetch origin example-assets:example-assets && git cherry-pick example-assets && git reset --soft HEAD^ && git reset HEAD examples/assets",
38
54
  "effects": "node scripts/save-effect-samples.js",
39
- "fix:main": "eslint -c eslint.conf.js --fix --ext .js,.html src examples",
40
- "fix:test": "eslint -c eslint.test-conf.js --fix spec",
41
- "lint": "npm run --silent lint:main && npm run --silent lint:test",
42
- "lint:main": "eslint -c eslint.conf.js --ext .js,.html src examples",
55
+ "lint": "npm run --silent lint:main && npm run --silent lint:test && npm run --silent lint:examples",
56
+ "lint:main": "eslint -c eslint.typescript-conf.js --ext .ts src",
43
57
  "lint:test": "eslint -c eslint.test-conf.js spec",
58
+ "lint:examples": "eslint -c eslint.example-conf.js --ext .html examples",
44
59
  "start": "http-server",
45
60
  "test": "karma start"
46
61
  },
@@ -49,10 +64,16 @@
49
64
  "url": "git+https://github.com/etro-js/etro.git"
50
65
  },
51
66
  "keywords": [
67
+ "video",
68
+ "audio",
69
+ "blob",
52
70
  "video-editing",
53
71
  "video-editor",
72
+ "video-manipulation",
54
73
  "browser",
55
- "api-driven"
74
+ "nodejs",
75
+ "api-driven",
76
+ "etro"
56
77
  ],
57
78
  "author": "Caleb Sacks (https://calebsacks.me)",
58
79
  "license": "GPL-3.0",
package/rollup.config.js CHANGED
@@ -1,12 +1,28 @@
1
1
  // import uglify from "rollup-plugin-uglify-es";
2
+ import cleaner from 'rollup-plugin-cleaner'
2
3
  import resolve from 'rollup-plugin-node-resolve'
4
+ import typescript from 'rollup-plugin-typescript2'
3
5
 
4
6
  export default [
5
7
  // iife bundle
6
8
  {
7
- input: 'src/index.js',
8
- output: { file: 'dist/etro.js', format: 'iife', name: 'etro' },
9
- plugins: [resolve()]
9
+ input: 'src/index.ts',
10
+ output: { file: 'dist/etro-iife.js', format: 'iife', name: 'etro' },
11
+ plugins: [
12
+ cleaner({
13
+ targets: ['dist']
14
+ }),
15
+ typescript(),
16
+ resolve()
17
+ ]
18
+ },
19
+ {
20
+ input: 'src/index.ts',
21
+ output: { file: 'dist/etro-cjs.js', format: 'cjs' },
22
+ plugins: [
23
+ typescript(),
24
+ resolve()
25
+ ]
10
26
  }
11
27
  // // es6 module bundle
12
28
  // {
@@ -2,7 +2,7 @@
2
2
  <!DOCTYPE html>
3
3
  <html>
4
4
  <body>
5
- <script src="../dist/etro.js"></script>
5
+ <script src="../dist/etro-iife.js"></script>
6
6
  <script>
7
7
  /**
8
8
  * Prepares a canvas for saving
@@ -50,12 +50,14 @@
50
50
  buffer.height = original.height
51
51
  const ctx = buffer.getContext('2d')
52
52
  ctx.drawImage(original, 0, 0)
53
-
54
- // do effect
55
- effect.apply({
53
+ const movie = {
56
54
  canvas: buffer, cctx: ctx,
57
55
  width: original.width, height: original.height
58
- })
56
+ }
57
+ // for util.cache()
58
+ effect._target = { movie }
59
+ // Run effect
60
+ effect.apply(movie)
59
61
 
60
62
  save(buffer, path)
61
63
  }
@@ -65,34 +67,33 @@
65
67
  save(original, 'original.png')
66
68
 
67
69
  const samples = {
68
- 'gaussian-blur-horizontal.png': new etro.effect.GaussianBlurHorizontal(5),
69
- 'gaussian-blur-vertical.png': new etro.effect.GaussianBlurVertical(5),
70
- 'pixelate.png': new etro.effect.Pixelate(3),
71
- 'transform/translate.png': new etro.effect.Transform(
72
- new etro.effect.Transform.Matrix().translate(-3, 5)
73
- ),
74
- 'transform/translate-fraction.png': new etro.effect.Transform(
75
- new etro.effect.Transform.Matrix().translate(0.5, 0.5)
76
- ),
77
- 'transform/scale.png': new etro.effect.Transform(
78
- new etro.effect.Transform.Matrix().scale(2, 2)
79
- ),
80
- 'transform/scale-fraction.png': new etro.effect.Transform(
81
- new etro.effect.Transform.Matrix().scale(0.5, 0.5)
82
- ),
83
- 'transform/rotate.png': new etro.effect.Transform(
84
- new etro.effect.Transform.Matrix().rotate(Math.PI / 6)
85
- ),
86
- 'transform/multiply.png': new etro.effect.Transform(
87
- new etro.effect.Transform.Matrix().scale(2, 2)
70
+ 'gaussian-blur-horizontal.png': new etro.effect.GaussianBlurHorizontal({ radius: 5 }),
71
+ 'gaussian-blur-vertical.png': new etro.effect.GaussianBlurVertical({ radius: 5 }),
72
+ 'grayscale.png': new etro.effect.Grayscale(),
73
+ 'pixelate.png': new etro.effect.Pixelate({ pixelSize: 3 }),
74
+ 'transform/translate.png': new etro.effect.Transform({
75
+ matrix: new etro.effect.Transform.Matrix().translate(-3, 5)
76
+ }),
77
+ 'transform/scale.png': new etro.effect.Transform({
78
+ matrix: new etro.effect.Transform.Matrix().scale(2, 2)
79
+ }),
80
+ 'transform/scale-fraction.png': new etro.effect.Transform({
81
+ matrix: new etro.effect.Transform.Matrix().scale(0.5, 0.5)
82
+ }),
83
+ 'transform/rotate.png': new etro.effect.Transform({
84
+ matrix: new etro.effect.Transform.Matrix().rotate(Math.PI / 6)
85
+ }),
86
+ 'transform/multiply.png': new etro.effect.Transform({
87
+ matrix: new etro.effect.Transform.Matrix().scale(2, 2)
88
88
  .multiply(new etro.effect.Transform.Matrix().translate(-3, 5))
89
- )
89
+ })
90
90
  }
91
91
 
92
92
  for (let path in samples) {
93
93
  const effect = samples[path]
94
94
  saveSample(original, effect, path)
95
95
  }
96
+ window.done = true
96
97
  }
97
98
  </script>
98
99
  </body>
@@ -23,21 +23,20 @@ function createDirs(filePath) {
23
23
  const browser = await puppeteer.launch()
24
24
  const page = await browser.newPage()
25
25
 
26
- page.on('load', async () => {
27
- // console.log(await page.$$('p'));
28
- const items = await page.$$eval('p', elems => elems.map(p => {
29
- return { data: p.innerHTML, path: p.dataset.path }
30
- }))
26
+ await page.goto(`file://${__dirname}/gen-effect-samples.html`)
27
+ await page.waitForFunction(() => window.done);
28
+
29
+ const items = await page.$$eval('p', elems => elems.map(p => {
30
+ return { data: p.innerHTML, path: p.dataset.path }
31
+ }))
31
32
 
32
- items.forEach(item => {
33
- // remove prefix and save to png
34
- const buffer = Buffer.from(item.data.replace(/^data:image\/png;base64,/, ''), 'base64')
35
- console.log(`writing ${item.path} ...`)
36
- const path = projectDir + '/spec/assets/effect/' + item.path
37
- createDirs(path)
38
- fs.writeFileSync(path, buffer)
39
- })
40
- await browser.close()
33
+ items.forEach(item => {
34
+ // remove prefix and save to png
35
+ const buffer = Buffer.from(item.data.replace(/^data:image\/png;base64,/, ''), 'base64')
36
+ console.log(`writing ${item.path} ...`)
37
+ const path = projectDir + '/spec/assets/effect/' + item.path
38
+ createDirs(path)
39
+ fs.writeFileSync(path, buffer)
41
40
  })
42
- await page.goto(`file://${__dirname}/gen-effect-samples.html`)
41
+ await browser.close()
43
42
  })()
@@ -0,0 +1,115 @@
1
+ import { watchPublic } from '../util'
2
+ import { publish, subscribe } from '../event'
3
+ import { Movie } from '../movie'
4
+ import { Visual } from '../layer/index'
5
+ import BaseObject from '../object'
6
+
7
+ /**
8
+ * Modifies the visual contents of a layer.
9
+ */
10
+ export class Base implements BaseObject {
11
+ type: string
12
+ publicExcludes: string[]
13
+ propertyFilters: Record<string, <T>(value: T) => T>
14
+
15
+ enabled: boolean
16
+
17
+ private _target: Movie | Visual
18
+ /**
19
+ * The number of times this effect has been attached to a target minus the
20
+ * number of times it's been detached. (Used for the target's array proxy with
21
+ * `unshift`)
22
+ */
23
+ private _occurrenceCount: number
24
+
25
+ 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
42
+ }
43
+
44
+ /**
45
+ * Attaches this effect to `target` if not already attached.
46
+ * @ignore
47
+ */
48
+ tryAttach (target: Movie | Visual): void {
49
+ if (this._occurrenceCount === 0)
50
+ this.attach(target)
51
+
52
+ this._occurrenceCount++
53
+ }
54
+
55
+ attach (movie: Movie | Visual): void {
56
+ this._target = movie
57
+ }
58
+
59
+ /**
60
+ * Dettaches this effect from its target if the number of times `tryDetach`
61
+ * has been called (including this call) equals the number of times
62
+ * `tryAttach` has been called.
63
+ *
64
+ * @ignore
65
+ */
66
+ tryDetach (): void {
67
+ if (this._target === null)
68
+ throw new Error('No movie to detach from')
69
+
70
+ this._occurrenceCount--
71
+ // If this effect occurs in another place in the containing array, do not
72
+ // unset _target. (For calling `unshift` on the `layers` proxy)
73
+ if (this._occurrenceCount === 0)
74
+ this.detach()
75
+ }
76
+
77
+ detach (): void {
78
+ this._target = null
79
+ }
80
+
81
+ // subclasses must implement apply
82
+ /**
83
+ * Apply this effect to a target at the given time
84
+ *
85
+ * @param target
86
+ * @param reltime - the movie's current time relative to the layer
87
+ * (will soon be replaced with an instance getter)
88
+ * @abstract
89
+ */
90
+ apply (target: Movie | Visual, reltime: number): void {} // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
91
+
92
+ /**
93
+ * The current time of the target
94
+ */
95
+ get currentTime (): number {
96
+ return this._target ? this._target.currentTime : undefined
97
+ }
98
+
99
+ get parent (): Movie | Visual {
100
+ return this._target
101
+ }
102
+
103
+ get movie (): Movie {
104
+ return this._target ? this._target.movie : undefined
105
+ }
106
+
107
+ getDefaultOptions (): Record<string, unknown> {
108
+ return {}
109
+ }
110
+ }
111
+ // id for events (independent of instance, but easy to access when on prototype
112
+ // chain)
113
+ Base.prototype.type = 'effect'
114
+ Base.prototype.publicExcludes = []
115
+ Base.prototype.propertyFilters = {}
@@ -0,0 +1,43 @@
1
+ import { Dynamic } from '../util'
2
+ import { Shader } from './shader'
3
+
4
+ export interface BrightnessOptions {
5
+ brightness?: Dynamic<number>
6
+ }
7
+
8
+ /**
9
+ * Changes the brightness
10
+ */
11
+ export class Brightness extends Shader {
12
+ brightness: Dynamic<number>
13
+
14
+ /**
15
+ * @param [brightness=0] - the value to add to each pixel's color
16
+ * channels (between -255 and 255)
17
+ */
18
+ constructor (options: BrightnessOptions = {}) {
19
+ super({
20
+ fragmentSource: `
21
+ precision mediump float;
22
+
23
+ uniform sampler2D u_Source;
24
+ uniform float u_Brightness;
25
+
26
+ varying highp vec2 v_TextureCoord;
27
+
28
+ void main() {
29
+ vec4 color = texture2D(u_Source, v_TextureCoord);
30
+ vec3 rgb = clamp(color.rgb + u_Brightness / 255.0, 0.0, 1.0);
31
+ gl_FragColor = vec4(rgb, color.a);
32
+ }
33
+ `,
34
+ uniforms: {
35
+ brightness: '1f'
36
+ }
37
+ })
38
+ /**
39
+ * The value to add to each pixel's color channels (between -255 and 255)
40
+ */
41
+ this.brightness = options.brightness || 0
42
+ }
43
+ }