etro 0.12.1 → 0.14.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 (145) hide show
  1. package/.github/dependabot.yml +6 -0
  2. package/.github/scripts/update-changelog.js +72 -0
  3. package/.github/workflows/dependabot-changelog.yml +57 -0
  4. package/.github/workflows/nodejs.yml +6 -2
  5. package/.github/workflows/shipjs-trigger.yml +2 -1
  6. package/.husky/pre-commit +1 -1
  7. package/AGENTS.md +106 -0
  8. package/CHANGELOG.md +46 -0
  9. package/CONTRIBUTING.md +5 -5
  10. package/README.md +8 -7
  11. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/base.css +224 -0
  12. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/block-navigation.js +87 -0
  13. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/favicon.png +0 -0
  14. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/index.html +161 -0
  15. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/prettify.css +1 -0
  16. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/prettify.js +2 -0
  17. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  18. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/sorter.js +196 -0
  19. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/custom-array.ts.html +214 -0
  20. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/base.ts.html +481 -0
  21. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/brightness.ts.html +214 -0
  22. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/channels.ts.html +235 -0
  23. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/chroma-key.ts.html +331 -0
  24. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/contrast.ts.html +211 -0
  25. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/elliptical-mask.ts.html +310 -0
  26. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/gaussian-blur.ts.html +796 -0
  27. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/grayscale.ts.html +187 -0
  28. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/index.html +311 -0
  29. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/index.ts.html +154 -0
  30. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/pixelate.ts.html +259 -0
  31. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/shader.ts.html +1774 -0
  32. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/stack.ts.html +358 -0
  33. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/transform.ts.html +685 -0
  34. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/effect/visual.ts.html +148 -0
  35. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/etro.ts.html +163 -0
  36. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/event.ts.html +691 -0
  37. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/index.html +176 -0
  38. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/index.ts.html +109 -0
  39. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/audio-source.ts.html +835 -0
  40. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/audio.ts.html +241 -0
  41. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/base.ts.html +826 -0
  42. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/image.ts.html +181 -0
  43. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/index.html +236 -0
  44. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/index.ts.html +124 -0
  45. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/text.ts.html +658 -0
  46. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/video.ts.html +211 -0
  47. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/visual-source.ts.html +721 -0
  48. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/layer/visual.ts.html +760 -0
  49. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/movie/effects.ts.html +163 -0
  50. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/movie/index.html +161 -0
  51. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/movie/index.ts.html +88 -0
  52. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/movie/layers.ts.html +163 -0
  53. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/movie/movie.ts.html +3037 -0
  54. package/coverage/Chrome Headless 148.0.0.0 (Mac OS 10.15.7)/html/src/util.ts.html +1765 -0
  55. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/base.css +224 -0
  56. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/block-navigation.js +87 -0
  57. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/favicon.png +0 -0
  58. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/index.html +161 -0
  59. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/prettify.css +1 -0
  60. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/prettify.js +2 -0
  61. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/sort-arrow-sprite.png +0 -0
  62. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/sorter.js +196 -0
  63. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/custom-array.ts.html +214 -0
  64. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/base.ts.html +481 -0
  65. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/brightness.ts.html +214 -0
  66. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/channels.ts.html +235 -0
  67. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/chroma-key.ts.html +331 -0
  68. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/contrast.ts.html +211 -0
  69. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/elliptical-mask.ts.html +310 -0
  70. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/gaussian-blur.ts.html +796 -0
  71. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/grayscale.ts.html +187 -0
  72. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/index.html +311 -0
  73. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/index.ts.html +154 -0
  74. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/pixelate.ts.html +259 -0
  75. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/shader.ts.html +1774 -0
  76. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/stack.ts.html +358 -0
  77. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/transform.ts.html +685 -0
  78. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/effect/visual.ts.html +148 -0
  79. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/etro.ts.html +163 -0
  80. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/event.ts.html +691 -0
  81. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/index.html +176 -0
  82. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/index.ts.html +109 -0
  83. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/audio-source.ts.html +835 -0
  84. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/audio.ts.html +241 -0
  85. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/base.ts.html +826 -0
  86. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/image.ts.html +181 -0
  87. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/index.html +236 -0
  88. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/index.ts.html +124 -0
  89. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/text.ts.html +658 -0
  90. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/video.ts.html +211 -0
  91. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/visual-source.ts.html +721 -0
  92. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/layer/visual.ts.html +760 -0
  93. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/movie/effects.ts.html +163 -0
  94. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/movie/index.html +161 -0
  95. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/movie/index.ts.html +88 -0
  96. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/movie/layers.ts.html +163 -0
  97. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/movie/movie.ts.html +3037 -0
  98. package/coverage/Firefox 151.0 (Mac OS 10.15)/html/src/util.ts.html +1765 -0
  99. package/dist/custom-array.d.ts +10 -10
  100. package/dist/effect/base.d.ts +61 -60
  101. package/dist/effect/brightness.d.ts +16 -16
  102. package/dist/effect/channels.d.ts +23 -23
  103. package/dist/effect/chroma-key.d.ts +23 -23
  104. package/dist/effect/contrast.d.ts +15 -15
  105. package/dist/effect/elliptical-mask.d.ts +31 -31
  106. package/dist/effect/gaussian-blur.d.ts +60 -60
  107. package/dist/effect/grayscale.d.ts +7 -7
  108. package/dist/effect/index.d.ts +16 -16
  109. package/dist/effect/pixelate.d.ts +18 -18
  110. package/dist/effect/shader.d.ts +109 -109
  111. package/dist/effect/stack.d.ts +27 -27
  112. package/dist/effect/transform.d.ts +73 -73
  113. package/dist/effect/visual.d.ts +17 -17
  114. package/dist/etro-cjs.js +3601 -3556
  115. package/dist/etro-iife.js +3602 -3557
  116. package/dist/etro.d.ts +7 -7
  117. package/dist/event.d.ts +40 -40
  118. package/dist/index.d.ts +6 -6
  119. package/dist/layer/audio-source.d.ts +28 -28
  120. package/dist/layer/audio.d.ts +27 -27
  121. package/dist/layer/base.d.ts +129 -128
  122. package/dist/layer/image.d.ts +20 -20
  123. package/dist/layer/index.d.ts +11 -11
  124. package/dist/layer/text.d.ts +78 -78
  125. package/dist/layer/video.d.ts +23 -23
  126. package/dist/layer/visual-source.d.ts +47 -47
  127. package/dist/layer/visual.d.ts +62 -62
  128. package/dist/movie/effects.d.ts +6 -6
  129. package/dist/movie/index.d.ts +1 -1
  130. package/dist/movie/layers.d.ts +6 -6
  131. package/dist/movie/movie.d.ts +280 -277
  132. package/dist/object.d.ts +19 -19
  133. package/dist/util.d.ts +128 -121
  134. package/karma.conf.js +70 -3
  135. package/package.json +14 -17
  136. package/ship.config.js +9 -11
  137. package/src/effect/base.ts +16 -0
  138. package/src/effect/shader.ts +1 -1
  139. package/src/layer/base.ts +19 -1
  140. package/src/movie/movie.ts +123 -8
  141. package/src/util.ts +116 -3
  142. package/tsconfig.json +3 -2
  143. package/.husky/commit-msg +0 -4
  144. package/.husky/prepare-commit-msg +0 -11
  145. package/commitlint.config.ts +0 -39
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "npm"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -0,0 +1,72 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { parser } = require('keep-a-changelog');
4
+
5
+ const changelogPath = path.join(process.cwd(), 'CHANGELOG.md');
6
+
7
+ const [
8
+ nodePath,
9
+ scriptPath,
10
+ depName,
11
+ oldVer,
12
+ newVer,
13
+ prNum,
14
+ prUrl,
15
+ isSecurityStr
16
+ ] = process.argv;
17
+
18
+ const isSecurity = isSecurityStr === 'true';
19
+
20
+ if (!depName || !prNum || !prUrl) {
21
+ console.error('Missing required arguments. Usage: node update-changelog.js <depName> <oldVer> <newVer> <prNum> <prUrl> <isSecurity>');
22
+ process.exit(1);
23
+ }
24
+
25
+ try {
26
+ // Read and parse the existing changelog
27
+ const content = fs.readFileSync(changelogPath, 'utf8');
28
+ const changelog = parser(content);
29
+
30
+ // Construct the new entry message
31
+ let message = '';
32
+ if (oldVer && newVer && oldVer !== 'undefined' && newVer !== 'undefined') {
33
+ message = `Bump ${depName} from ${oldVer} to ${newVer} ([#${prNum}](${prUrl})).`;
34
+ } else {
35
+ message = `Bump ${depName} ([#${prNum}](${prUrl})).`;
36
+ }
37
+
38
+ // Find the "Unreleased" release
39
+ // keep-a-changelog typically looks for a release with no version or date, or explicitly named "Unreleased"
40
+ // We can try to find the first release which should be unreleased if following standard practice
41
+ const unreleased = changelog.releases.find(r => !r.date && (r.version === undefined || r.version === 'Unreleased'));
42
+
43
+ if (!unreleased) {
44
+ console.error('Could not find "Unreleased" section in CHANGELOG.md');
45
+ process.exit(1);
46
+ }
47
+
48
+ // Determine the type (section) for the change
49
+ // 'changed' or 'security' are the typical types in Keep a Changelog
50
+ const type = isSecurity ? 'security' : 'changed';
51
+
52
+ // Check for duplicates in the specific section
53
+ // changes is a Map<string, Change[]> where string is the type
54
+ const existingChanges = unreleased.changes.get(type) || [];
55
+ const isDuplicate = existingChanges.some(change => change.title.trim() === message);
56
+
57
+ if (isDuplicate) {
58
+ console.log('Entry already exists in CHANGELOG.md');
59
+ process.exit(0);
60
+ }
61
+
62
+ // Add the new change
63
+ unreleased.addChange(type, message);
64
+
65
+ // Write back to file
66
+ fs.writeFileSync(changelogPath, changelog.toString());
67
+ console.log('Successfully updated CHANGELOG.md');
68
+
69
+ } catch (err) {
70
+ console.error('Error updating changelog:', err);
71
+ process.exit(1);
72
+ }
@@ -0,0 +1,57 @@
1
+ name: Dependabot Changelog Updater
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
+
7
+ permissions:
8
+ contents: write
9
+ pull-requests: read
10
+
11
+ jobs:
12
+ update-changelog:
13
+ runs-on: ubuntu-latest
14
+ if: ${{ github.actor == 'dependabot[bot]' }}
15
+
16
+ steps:
17
+ - name: Checkout code
18
+ uses: actions/checkout@v4
19
+ with:
20
+ ref: ${{ github.event.pull_request.head.ref }}
21
+
22
+ - name: Fetch Dependabot metadata
23
+ id: metadata
24
+ uses: dependabot/fetch-metadata@v1
25
+ with:
26
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
27
+
28
+ - name: Setup Node.js
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: '16'
32
+
33
+ - name: Install dependencies
34
+ run: npm install keep-a-changelog
35
+
36
+ - name: Update Changelog
37
+ env:
38
+ DEP_NAME: ${{ steps.metadata.outputs.dependency-names }}
39
+ OLD_VER: ${{ steps.metadata.outputs.previous-version }}
40
+ NEW_VER: ${{ steps.metadata.outputs.new-version }}
41
+ PR_NUM: ${{ github.event.pull_request.number }}
42
+ PR_URL: ${{ github.event.pull_request.html_url }}
43
+ IS_SECURITY: ${{ contains(steps.metadata.outputs.update-type, 'security') }}
44
+ run: |
45
+ node .github/scripts/update-changelog.js "$DEP_NAME" "$OLD_VER" "$NEW_VER" "$PR_NUM" "$PR_URL" "$IS_SECURITY"
46
+
47
+ - name: Commit and push changes
48
+ run: |
49
+ git config user.name "dependabot[bot]"
50
+ git config user.email "dependabot[bot]@users.noreply.github.com"
51
+ git add CHANGELOG.md
52
+ if git diff --staged --quiet; then
53
+ echo "No changes to commit"
54
+ else
55
+ git commit -m "Update CHANGELOG.md [dependabot skip]"
56
+ git push
57
+ fi
@@ -10,7 +10,7 @@ jobs:
10
10
 
11
11
  strategy:
12
12
  matrix:
13
- node-version: [15.x, 16.x, 17.x]
13
+ node-version: [22.x, 24.x]
14
14
 
15
15
  steps:
16
16
  - uses: actions/checkout@v1
@@ -20,7 +20,7 @@ jobs:
20
20
  node-version: ${{ matrix.node-version }}
21
21
  - name: Update npm
22
22
  run: |
23
- npm i -g npm@^7.x
23
+ npm i -g npm@latest
24
24
  - name: Install npm dependencies
25
25
  run: |
26
26
  npm ci
@@ -39,7 +39,11 @@ jobs:
39
39
  run: xvfb-run --auto-servernum npm run test:unit
40
40
  env:
41
41
  CI: true
42
+ # Force Mesa's software renderer so headless Firefox has WebGL on
43
+ # GPU-less runners (Chrome uses SwiftShader via its launcher flags).
44
+ LIBGL_ALWAYS_SOFTWARE: true
42
45
  - name: run smoke tests
43
46
  run: xvfb-run --auto-servernum npm run test:smoke
44
47
  env:
45
48
  CI: true
49
+ LIBGL_ALWAYS_SOFTWARE: true
@@ -13,8 +13,9 @@ jobs:
13
13
  with:
14
14
  fetch-depth: 0
15
15
  ref: master
16
- - uses: actions/setup-node@v1
16
+ - uses: actions/setup-node@v6
17
17
  with:
18
+ node-version: 24
18
19
  registry-url: "https://registry.npmjs.org"
19
20
  - run: |
20
21
  if [ -f "yarn.lock" ]; then
package/.husky/pre-commit CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env sh
2
2
  . "$(dirname -- "$0")/_/husky.sh"
3
3
 
4
- npm run lint
4
+ npm run fix
5
5
 
6
6
  if [ -z "$SKIP_TESTS" ]; then
7
7
  npm run test:unit
package/AGENTS.md ADDED
@@ -0,0 +1,106 @@
1
+ # AGENTS.md — Etro Contributor Context
2
+
3
+ ## What is Etro?
4
+
5
+ Etro is a TypeScript video-editing framework for the browser. It composites
6
+ layers (video, audio, image, text, or custom) onto an HTML `<canvas>`, applies
7
+ GPU-accelerated GLSL shader effects, and outputs via `play()`, `stream()`
8
+ (WebRTC), or `record()` (Blob). Audio routes through the Web Audio API.
9
+
10
+ ## Repository Layout
11
+
12
+ ```
13
+ src/
14
+ spec/ # Tests (Karma + Jasmine)
15
+ ├── unit/ # Mocked unit tests
16
+ ├── smoke/ # End-to-end without audio (runs in CI)
17
+ ├── integration/ # End-to-end with audio (local only)
18
+ ├── mocks/ # Shared mock factories (dom, movie, layer, effect)
19
+ └── assets/ # Test fixtures (images, audio, video, effect references)
20
+ examples/ # Browser demos (hello-world, keyframes, effects, webcam)
21
+ scripts/effect/ # Effect sample generation tooling
22
+ dist/ # Build output (gitignored)
23
+ ```
24
+
25
+ ## Architecture Concepts
26
+
27
+ - **Movie** — the root composition. Owns a `<canvas>`, an `AudioContext`, a
28
+ `layers` list, and an `effects` list. Renders via `play()`, `stream()`,
29
+ `record()`, or `refresh()`.
30
+ - **Layer** — a time-sliced content source (`startTime` + `duration`). Visual
31
+ layers draw to the canvas; audio layers route through Web Audio.
32
+ - **Effect** — a filter applied to a layer or to the movie globally. Visual
33
+ effects use WebGL fragment shaders.
34
+ - **Dynamic Properties** — layer/effect properties can be a constant, a
35
+ `KeyFrame` animation, or a function `(element, time) => value`. Evaluate
36
+ with `etro.val(obj, 'prop', time)`.
37
+ - **Events** (deprecated) — pub/sub via `event.publish` / `event.subscribe`.
38
+ New code should prefer async callbacks (`onDraw`, `onStart`, etc.).
39
+
40
+ ## Build & Dev
41
+
42
+ | Command | Purpose |
43
+ |----------------------------|-----------------------------------------------|
44
+ | `npm run build` | Rollup → `dist/etro-cjs.js` + `dist/etro-iife.js` |
45
+ | `npm run lint` | ESLint (StandardJS + TypeScript rules) |
46
+ | `npm run fix` | ESLint with `--fix` |
47
+ | `npm run test:unit` | Unit tests (mocked DOM, runs in CI) |
48
+ | `npm run test:smoke` | Smoke tests (real browser, no audio, runs in CI) |
49
+ | `npm run test:integration` | Integration tests (audio required, local only)|
50
+ | `npm run doc` | Typedoc → `docs/` |
51
+ | `npm run effects` | Regenerate effect reference images |
52
+
53
+ Tests run in **headless Chrome and/or Firefox** via Karma (depending on local
54
+ browser availability). The test suite is selected by the `TEST_SUITE` env var
55
+ (`unit`, `smoke`, or `integration`).
56
+
57
+ ## Code Conventions
58
+
59
+ - **Language**: TypeScript, compiled to ES6. Target `"lib": ["es2016", "DOM"]`.
60
+ - **Style**: [StandardJS](https://standardjs.com/rules.html) — no semicolons,
61
+ 2-space indent, `1tbs` brace style, `curly: all`.
62
+ - **Commits**: Husky pre-commit runs lint + build + tests automatically.
63
+ - **Branching**: Work on a feature branch, never commit directly to master.
64
+ Rebase onto upstream/master before opening a PR.
65
+
66
+ ## Adding / Modifying Effects
67
+
68
+ 1. Create or edit the effect class in `src/effect/`.
69
+ 2. Effects with visual output should extend `etro.effect.Shader` (for custom
70
+ GLSL) or `etro.effect.Visual`.
71
+ 3. Register the effect in `src/effect/index.ts`.
72
+ 4. Add the effect to `scripts/gen-effect-samples.html`.
73
+ 5. Run `npm run effects` and review generated images in
74
+ `spec/integration/assets/effect/`.
75
+ 6. Add unit tests in `spec/unit/effect/` and smoke tests in `spec/smoke/effect/`.
76
+
77
+ ## Adding / Modifying Layers
78
+
79
+ 1. Create or edit the layer class in `src/layer/`.
80
+ 2. Visual layers should extend `etro.layer.Visual`; audio layers extend
81
+ `etro.layer.Base` and implement audio routing.
82
+ 3. Register the layer in `src/layer/index.ts`.
83
+ 4. Add unit tests in `spec/unit/layer/` using the mock factories in
84
+ `spec/unit/mocks/`.
85
+
86
+ ## Key Patterns
87
+
88
+ - Use `applyOptions()` (from `util.ts`) to merge constructor options with
89
+ defaults — though this is deprecated; new code should assign defaults
90
+ directly in the constructor.
91
+ - The `Dynamic<T>` type and `val()` helper enable keyframe-animated and
92
+ functional properties. Any property that should support animation must use
93
+ this pattern.
94
+ - Layers and effects use `tryAttach` / `tryDetach` lifecycle hooks when
95
+ added to or removed from a movie. Use `attach()` for setup and `detach()`
96
+ for teardown.
97
+ - The `publicExcludes` array on layers/effects controls which properties are
98
+ excluded from serialization.
99
+
100
+ ## Useful Links
101
+
102
+ - Docs: https://etrojs.dev/
103
+ - API Reference: https://etrojs.dev/docs/reference/movie
104
+ - Dynamic Properties: https://etrojs.dev/docs/reference/dynamic-properties
105
+ - Discord: https://discord.gg/myrBsQ8Cht
106
+ - CONTRIBUTING.md for full workflow details
package/CHANGELOG.md CHANGED
@@ -5,6 +5,50 @@ 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.14.0] - 2026-06-06
9
+ ### Added
10
+ - Movie serialization and deserialization ([#340](https://github.com/etro-js/etro/pull/340) by [@G3RRYGL3Z](https://github.com/G3RRYGL3Z)).
11
+
12
+ ### Changed
13
+ - Bump rollup-plugin-typescript2 to 0.37.0.
14
+ - Bump karma to 6.4.4.
15
+
16
+ ### Security
17
+ - Bump handlebars from 4.7.7 to 4.7.9 ([#329](https://github.com/etro-js/etro/pull/329)).
18
+ - Bump shipjs, tmp ([#343](https://github.com/etro-js/etro/pull/343)).
19
+ - Bump body-parser, qs ([#337](https://github.com/etro-js/etro/pull/337)).
20
+ - Bump rollup to 4.61.1.
21
+ - Bump typedoc to 0.28.19.
22
+ - Bump karma-jasmine to 5.1.0.
23
+
24
+ ## [0.13.0] - 2026-03-18
25
+ ### Added
26
+ - `Movie#play()` option `onDraw()` ([#266](https://github.com/etro-js/etro/pull/266)).
27
+
28
+ ### Changed
29
+ - The type for `KeyFrame.value` has been updated from `unknown[][]` to `(number|T|Interpolate)[][]` ([#259](https://github.com/etro-js/etro/pull/259)).
30
+
31
+ ### Fixed
32
+ - Shader effects producing solid black output in browsers whose GLSL linker does not assign `a_VertexPosition` to attribute location 0 (e.g., Firefox on macOS).
33
+
34
+ ### Security
35
+ - Bump ejs from 3.1.8 to 3.1.10 ([#271](https://github.com/etro-js/etro/pull/271)).
36
+ - Bump follow-redirects from 1.15.4 to 1.15.6 ([#267](https://github.com/etro-js/etro/pull/267)).
37
+ - Bump [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3 ([#274](https://github.com/etro-js/etro/pull/274)).
38
+ - Bump [socket.io](https://github.com/socketio/socket.io) from 4.6.1 to 4.7.5 ([#277](https://github.com/etro-js/etro/pull/277)).
39
+ - Bump [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1 ([#309](https://github.com/etro-js/etro/pull/309)).
40
+ - Bump [@rollup/plugin-eslint](https://github.com/rollup/plugins/tree/master/packages/eslint) from 8.0.2 to 9.2.0 ([#309](https://github.com/etro-js/etro/pull/309)).
41
+ - Bump validator from 13.11.0 to 13.15.20 ([#308](https://github.com/etro-js/etro/pull/308)).
42
+ - Bump pbkdf2 from 3.1.2 to 3.1.5 ([#307](https://github.com/etro-js/etro/pull/307)).
43
+ - Bump cipher-base from 1.0.4 to 1.0.6 ([#305](https://github.com/etro-js/etro/pull/305)).
44
+ - Bump rollup from 1.32.1 to 2.79.2 ([#300](https://github.com/etro-js/etro/pull/300)).
45
+ - Bump elliptic from 6.5.4 to 6.6.1 ([#299](https://github.com/etro-js/etro/pull/299)).
46
+ - Bump ws, socket.io-adapter ([#281](https://github.com/etro-js/etro/pull/281)).
47
+ - Bump cookie, socket.io ([#283](https://github.com/etro-js/etro/pull/283)).
48
+ - Bump body-parser from 1.20.1 to 1.20.3 ([#285](https://github.com/etro-js/etro/pull/285)).
49
+ - Bump shipjs from 0.26.3 to 0.27.0 ([#314](https://github.com/etro-js/etro/pull/314)).
50
+ - Bump basic-ftp from 5.0.4 to 5.2.0 ([#320](https://github.com/etro-js/etro/pull/320)).
51
+
8
52
  ## [0.12.1] - 2024-02-19
9
53
  ### Fixed
10
54
  - Importing etro in the client-side code of a NextJS project causing a "module not found" error ([#243](https://github.com/etro-js/etro/issues/243)).
@@ -308,6 +352,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
308
352
  - Gaussian blur
309
353
  - Transform
310
354
 
355
+ [0.14.0]: https://github.com/etro-js/etro/compare/v0.13.0...v0.14.0
356
+ [0.13.0]: https://github.com/etro-js/etro/compare/v0.12.1...v0.13.0
311
357
  [0.12.1]: https://github.com/etro-js/etro/compare/v0.12.0...v0.12.1
312
358
  [0.12.0]: https://github.com/etro-js/etro/compare/v0.11.0...v0.12.0
313
359
  [0.11.0]: https://github.com/etro-js/etro/compare/v0.10.1...v0.11.0
package/CONTRIBUTING.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Introduction
6
6
 
7
- 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 code for the library. This page covers how to make changes to the repository files (either code or jsdocs).
7
+ Thank you for considering contributing to Etro! There are many ways to contribute, such as reporting bugs, suggesting features, improving the documentation, or writing code. This guide covers how to make changes to the repository files (code or documentation).
8
8
 
9
9
  [Join our Discord](https://discord.gg/myrBsQ8Cht)
10
10
 
@@ -23,7 +23,7 @@ Thank you for considering contributing to Etro! There are many ways you can cont
23
23
 
24
24
  ## Making your changes
25
25
 
26
- - Make some changes and update tests
26
+ - Make your changes and update the relevant tests
27
27
  - If you are writing code, the linter uses [StandardJS](https://standardjs.com/rules.html) for style conventions
28
28
  - If you're adding or updating an effect:
29
29
  - Add your effect to **scripts/gen-effect-samples.html**
@@ -44,13 +44,13 @@ Thank you for considering contributing to Etro! There are many ways you can cont
44
44
 
45
45
  ## Submitting your changes
46
46
 
47
- - Before pushing to your fork, rebase (please avoid merging) to integrate your work with any new changes in the main repository
47
+ - Before pushing to your fork, please rebase onto the latest upstream changes (rather than merging) to keep the history clean:
48
48
  ```
49
49
  git fetch upstream
50
50
  git rebase upstream/master
51
51
  ```
52
- - Open a pull request from the branch in your fork to the main repository. If you changed any core functionality, make sure you explain your motives for those changes
53
- - A large part of the submission process is receiving feedback on how you can improve you pull request. If you need to change your pull request, feel free to push more commits.
52
+ - Open a pull request from the branch in your fork to the main repository. If your changes affect core functionality, please explain the reasoning behind them.
53
+ - We may provide feedback to help refine your pull request. Feel free to push additional commits to address any suggestions.
54
54
 
55
55
  ## Tests
56
56
 
package/README.md CHANGED
@@ -4,10 +4,10 @@
4
4
  [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fetro-js%2Fetro%2Fbadge&style=flat)](https://actions-badge.atrox.dev/etro-js/etro/goto)
5
5
  [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?style=flat&logo=discord&logoColor=white)](https://discord.gg/myrBsQ8Cht)
6
6
 
7
- Etro is a typescript framework for programmatically editing videos. It lets you
8
- composite layers and add filters (effects). Etro comes shipped with text, video,
9
- audio and image layers, along with a bunch of GLSL effects. You can also define
10
- your own layers and effects with javascript and GLSL.
7
+ Etro is a framework-agnostic TypeScript library for programmatically editing
8
+ videos. It lets you composite layers and add filters. Etro includes text, video,
9
+ audio and image layers, along with a variety of GLSL filters. You can also
10
+ define your own layers and filters with TypeScript and GLSL.
11
11
 
12
12
  ## Features
13
13
 
@@ -17,6 +17,7 @@ your own layers and effects with javascript and GLSL.
17
17
  - Manipulate audio with the web audio API *(audio effects coming soon)*
18
18
  - Define layer and effect parameters as keyframes or custom functions
19
19
  - Render to a blob in realtime *(offline rendering coming soon)*
20
+ - UI framework agnostic
20
21
 
21
22
  ## Installation
22
23
 
@@ -78,8 +79,8 @@ To use Etro in Node, see the [wrapper](https://github.com/etro-js/etro-node):
78
79
 
79
80
  ## Running the Examples
80
81
 
81
- Start the development server (only used for convenience while developing; you
82
- don't need a server to use Etro):
82
+ Start the development server (used for convenience during development; Etro does
83
+ not require a server):
83
84
 
84
85
  ```
85
86
  npm i
@@ -100,5 +101,5 @@ See the [contributing guide](CONTRIBUTING.md)
100
101
 
101
102
  ## License
102
103
 
103
- Distributed under GNU General Public License v3. See `LICENSE` for more
104
+ Distributed under GNU General Public License v3. See [LICENSE](LICENSE) for more
104
105
  information.
@@ -0,0 +1,224 @@
1
+ body, html {
2
+ margin:0; padding: 0;
3
+ height: 100%;
4
+ }
5
+ body {
6
+ font-family: Helvetica Neue, Helvetica, Arial;
7
+ font-size: 14px;
8
+ color:#333;
9
+ }
10
+ .small { font-size: 12px; }
11
+ *, *:after, *:before {
12
+ -webkit-box-sizing:border-box;
13
+ -moz-box-sizing:border-box;
14
+ box-sizing:border-box;
15
+ }
16
+ h1 { font-size: 20px; margin: 0;}
17
+ h2 { font-size: 14px; }
18
+ pre {
19
+ font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
20
+ margin: 0;
21
+ padding: 0;
22
+ -moz-tab-size: 2;
23
+ -o-tab-size: 2;
24
+ tab-size: 2;
25
+ }
26
+ a { color:#0074D9; text-decoration:none; }
27
+ a:hover { text-decoration:underline; }
28
+ .strong { font-weight: bold; }
29
+ .space-top1 { padding: 10px 0 0 0; }
30
+ .pad2y { padding: 20px 0; }
31
+ .pad1y { padding: 10px 0; }
32
+ .pad2x { padding: 0 20px; }
33
+ .pad2 { padding: 20px; }
34
+ .pad1 { padding: 10px; }
35
+ .space-left2 { padding-left:55px; }
36
+ .space-right2 { padding-right:20px; }
37
+ .center { text-align:center; }
38
+ .clearfix { display:block; }
39
+ .clearfix:after {
40
+ content:'';
41
+ display:block;
42
+ height:0;
43
+ clear:both;
44
+ visibility:hidden;
45
+ }
46
+ .fl { float: left; }
47
+ @media only screen and (max-width:640px) {
48
+ .col3 { width:100%; max-width:100%; }
49
+ .hide-mobile { display:none!important; }
50
+ }
51
+
52
+ .quiet {
53
+ color: #7f7f7f;
54
+ color: rgba(0,0,0,0.5);
55
+ }
56
+ .quiet a { opacity: 0.7; }
57
+
58
+ .fraction {
59
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
60
+ font-size: 10px;
61
+ color: #555;
62
+ background: #E8E8E8;
63
+ padding: 4px 5px;
64
+ border-radius: 3px;
65
+ vertical-align: middle;
66
+ }
67
+
68
+ div.path a:link, div.path a:visited { color: #333; }
69
+ table.coverage {
70
+ border-collapse: collapse;
71
+ margin: 10px 0 0 0;
72
+ padding: 0;
73
+ }
74
+
75
+ table.coverage td {
76
+ margin: 0;
77
+ padding: 0;
78
+ vertical-align: top;
79
+ }
80
+ table.coverage td.line-count {
81
+ text-align: right;
82
+ padding: 0 5px 0 20px;
83
+ }
84
+ table.coverage td.line-coverage {
85
+ text-align: right;
86
+ padding-right: 10px;
87
+ min-width:20px;
88
+ }
89
+
90
+ table.coverage td span.cline-any {
91
+ display: inline-block;
92
+ padding: 0 5px;
93
+ width: 100%;
94
+ }
95
+ .missing-if-branch {
96
+ display: inline-block;
97
+ margin-right: 5px;
98
+ border-radius: 3px;
99
+ position: relative;
100
+ padding: 0 4px;
101
+ background: #333;
102
+ color: yellow;
103
+ }
104
+
105
+ .skip-if-branch {
106
+ display: none;
107
+ margin-right: 10px;
108
+ position: relative;
109
+ padding: 0 4px;
110
+ background: #ccc;
111
+ color: white;
112
+ }
113
+ .missing-if-branch .typ, .skip-if-branch .typ {
114
+ color: inherit !important;
115
+ }
116
+ .coverage-summary {
117
+ border-collapse: collapse;
118
+ width: 100%;
119
+ }
120
+ .coverage-summary tr { border-bottom: 1px solid #bbb; }
121
+ .keyline-all { border: 1px solid #ddd; }
122
+ .coverage-summary td, .coverage-summary th { padding: 10px; }
123
+ .coverage-summary tbody { border: 1px solid #bbb; }
124
+ .coverage-summary td { border-right: 1px solid #bbb; }
125
+ .coverage-summary td:last-child { border-right: none; }
126
+ .coverage-summary th {
127
+ text-align: left;
128
+ font-weight: normal;
129
+ white-space: nowrap;
130
+ }
131
+ .coverage-summary th.file { border-right: none !important; }
132
+ .coverage-summary th.pct { }
133
+ .coverage-summary th.pic,
134
+ .coverage-summary th.abs,
135
+ .coverage-summary td.pct,
136
+ .coverage-summary td.abs { text-align: right; }
137
+ .coverage-summary td.file { white-space: nowrap; }
138
+ .coverage-summary td.pic { min-width: 120px !important; }
139
+ .coverage-summary tfoot td { }
140
+
141
+ .coverage-summary .sorter {
142
+ height: 10px;
143
+ width: 7px;
144
+ display: inline-block;
145
+ margin-left: 0.5em;
146
+ background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
147
+ }
148
+ .coverage-summary .sorted .sorter {
149
+ background-position: 0 -20px;
150
+ }
151
+ .coverage-summary .sorted-desc .sorter {
152
+ background-position: 0 -10px;
153
+ }
154
+ .status-line { height: 10px; }
155
+ /* yellow */
156
+ .cbranch-no { background: yellow !important; color: #111; }
157
+ /* dark red */
158
+ .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
159
+ .low .chart { border:1px solid #C21F39 }
160
+ .highlighted,
161
+ .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
162
+ background: #C21F39 !important;
163
+ }
164
+ /* medium red */
165
+ .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
166
+ /* light red */
167
+ .low, .cline-no { background:#FCE1E5 }
168
+ /* light green */
169
+ .high, .cline-yes { background:rgb(230,245,208) }
170
+ /* medium green */
171
+ .cstat-yes { background:rgb(161,215,106) }
172
+ /* dark green */
173
+ .status-line.high, .high .cover-fill { background:rgb(77,146,33) }
174
+ .high .chart { border:1px solid rgb(77,146,33) }
175
+ /* dark yellow (gold) */
176
+ .status-line.medium, .medium .cover-fill { background: #f9cd0b; }
177
+ .medium .chart { border:1px solid #f9cd0b; }
178
+ /* light yellow */
179
+ .medium { background: #fff4c2; }
180
+
181
+ .cstat-skip { background: #ddd; color: #111; }
182
+ .fstat-skip { background: #ddd; color: #111 !important; }
183
+ .cbranch-skip { background: #ddd !important; color: #111; }
184
+
185
+ span.cline-neutral { background: #eaeaea; }
186
+
187
+ .coverage-summary td.empty {
188
+ opacity: .5;
189
+ padding-top: 4px;
190
+ padding-bottom: 4px;
191
+ line-height: 1;
192
+ color: #888;
193
+ }
194
+
195
+ .cover-fill, .cover-empty {
196
+ display:inline-block;
197
+ height: 12px;
198
+ }
199
+ .chart {
200
+ line-height: 0;
201
+ }
202
+ .cover-empty {
203
+ background: white;
204
+ }
205
+ .cover-full {
206
+ border-right: none !important;
207
+ }
208
+ pre.prettyprint {
209
+ border: none !important;
210
+ padding: 0 !important;
211
+ margin: 0 !important;
212
+ }
213
+ .com { color: #999 !important; }
214
+ .ignore-none { color: #999; font-weight: normal; }
215
+
216
+ .wrapper {
217
+ min-height: 100%;
218
+ height: auto !important;
219
+ height: 100%;
220
+ margin: 0 auto -48px;
221
+ }
222
+ .footer, .push {
223
+ height: 48px;
224
+ }