@remotion/effects 4.0.537 → 4.0.539

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 (99) hide show
  1. package/THIRD_PARTY_LICENSES.md +4 -0
  2. package/dist/barrel-distortion/index.d.ts +1 -1
  3. package/dist/bevel-alpha/index.d.ts +1 -1
  4. package/dist/bevel-alpha/shaders.d.ts +1 -1
  5. package/dist/blur/index.d.ts +1 -1
  6. package/dist/brightness.d.ts +1 -1
  7. package/dist/burlap.d.ts +1 -1
  8. package/dist/checkerboard.d.ts +17 -17
  9. package/dist/chromatic-aberration/index.d.ts +1 -1
  10. package/dist/color-correction.d.ts +1 -1
  11. package/dist/color-key.d.ts +9 -9
  12. package/dist/color-utils.d.ts +8 -8
  13. package/dist/contour-lines.d.ts +23 -23
  14. package/dist/contrast.d.ts +1 -1
  15. package/dist/corner-pin/index.d.ts +1 -1
  16. package/dist/curves.d.ts +65 -0
  17. package/dist/cylinder/index.d.ts +1 -1
  18. package/dist/dot-grid.d.ts +7 -7
  19. package/dist/drop-shadow/index.d.ts +1 -1
  20. package/dist/duotone.d.ts +7 -7
  21. package/dist/emboss.d.ts +15 -15
  22. package/dist/esm/curves.mjs +373 -0
  23. package/dist/esm/levels.mjs +80 -10
  24. package/dist/esm/long-shadows.mjs +410 -0
  25. package/dist/esm/shatter.mjs +888 -0
  26. package/dist/evolve.d.ts +8 -8
  27. package/dist/exposure.d.ts +1 -1
  28. package/dist/fisheye/index.d.ts +1 -1
  29. package/dist/flannel.d.ts +1 -1
  30. package/dist/fractal-noise/index.d.ts +3 -3
  31. package/dist/gaussian-blur-shader.d.ts +1 -1
  32. package/dist/glow/index.d.ts +1 -1
  33. package/dist/grayscale.d.ts +1 -1
  34. package/dist/gridlines.d.ts +23 -23
  35. package/dist/halftone-linear-gradient.d.ts +21 -21
  36. package/dist/halftone.d.ts +25 -25
  37. package/dist/hue.d.ts +1 -1
  38. package/dist/invert.d.ts +1 -1
  39. package/dist/lens-blur/index.d.ts +2 -2
  40. package/dist/levels.d.ts +70 -3
  41. package/dist/light-leak.d.ts +7 -7
  42. package/dist/light-trail/index.d.ts +1 -1
  43. package/dist/linear-gradient-tint.d.ts +1 -1
  44. package/dist/linear-gradient.d.ts +1 -1
  45. package/dist/linear-progressive-blur/index.d.ts +1 -1
  46. package/dist/linear-progressive-blur/linear-progressive-blur-shaders.d.ts +1 -1
  47. package/dist/linear-progressive-pixelate/index.d.ts +1 -1
  48. package/dist/lines.d.ts +18 -18
  49. package/dist/liquid-contours.d.ts +21 -21
  50. package/dist/long-shadows.d.ts +13 -0
  51. package/dist/lut/index.d.ts +3 -3
  52. package/dist/mirror/index.d.ts +1 -1
  53. package/dist/noise-displacement.d.ts +1 -1
  54. package/dist/noise.d.ts +1 -1
  55. package/dist/outline/polygonize-alpha.d.ts +1 -1
  56. package/dist/outline.d.ts +11 -11
  57. package/dist/page-turn/index.d.ts +1 -1
  58. package/dist/paper.d.ts +1 -1
  59. package/dist/pattern.d.ts +1 -1
  60. package/dist/pixel-dissolve.d.ts +1 -1
  61. package/dist/pixelate.d.ts +1 -1
  62. package/dist/radial-progressive-blur/index.d.ts +1 -1
  63. package/dist/radial-progressive-blur/radial-progressive-blur-shaders.d.ts +1 -1
  64. package/dist/radial-progressive-pixelate/index.d.ts +1 -1
  65. package/dist/region-blur/index.d.ts +11 -11
  66. package/dist/rings.d.ts +15 -15
  67. package/dist/roughen-edges.d.ts +1 -1
  68. package/dist/saturation.d.ts +1 -1
  69. package/dist/scale/index.d.ts +1 -1
  70. package/dist/scanlines.d.ts +1 -1
  71. package/dist/shadows-highlights.d.ts +1 -1
  72. package/dist/shatter/geometry.d.ts +19 -0
  73. package/dist/shatter/index.d.ts +39 -0
  74. package/dist/shatter/runtime.d.ts +19 -0
  75. package/dist/shatter.d.ts +1 -0
  76. package/dist/shine.d.ts +1 -1
  77. package/dist/shrinkwrap.d.ts +1 -1
  78. package/dist/skew.d.ts +1 -1
  79. package/dist/speckle.d.ts +1 -1
  80. package/dist/sphere/index.d.ts +1 -1
  81. package/dist/starburst.d.ts +13 -13
  82. package/dist/tear.d.ts +1 -1
  83. package/dist/thermal-vision.d.ts +7 -7
  84. package/dist/tile.d.ts +1 -1
  85. package/dist/tint.d.ts +5 -5
  86. package/dist/translate/index.d.ts +2 -2
  87. package/dist/turbulent-displace/index.d.ts +3 -3
  88. package/dist/tv-signal-off.d.ts +1 -1
  89. package/dist/venetian-blinds.d.ts +8 -8
  90. package/dist/vibrance.d.ts +1 -1
  91. package/dist/vignette.d.ts +16 -16
  92. package/dist/visual-test/visual-utils.d.ts +8 -8
  93. package/dist/wave/index.d.ts +1 -1
  94. package/dist/waves.d.ts +24 -24
  95. package/dist/white-balance.d.ts +1 -1
  96. package/dist/white-noise.d.ts +1 -1
  97. package/dist/zigzag.d.ts +22 -22
  98. package/dist/zoom-blur/index.d.ts +1 -1
  99. package/package.json +31 -7
@@ -0,0 +1,373 @@
1
+ // src/curves.ts
2
+ import { Internals } from "remotion";
3
+
4
+ // src/validate-effect-param.ts
5
+ var assertEffectParamsObject = (params, effectLabel) => {
6
+ if (params === null || typeof params !== "object") {
7
+ throw new TypeError(`${effectLabel} effect requires a parameters object, but got ${JSON.stringify(params)}`);
8
+ }
9
+ };
10
+ var assertRequiredFiniteNumber = (value, name) => {
11
+ if (typeof value !== "number" || !Number.isFinite(value)) {
12
+ throw new TypeError(`"${name}" must be a finite number, but got ${JSON.stringify(value)}`);
13
+ }
14
+ };
15
+ var assertRequiredColor = (value, name) => {
16
+ if (typeof value !== "string" || value.length === 0) {
17
+ throw new TypeError(`"${name}" must be a non-empty string, but got ${JSON.stringify(value)}`);
18
+ }
19
+ };
20
+ var assertOptionalColor = (value, name) => {
21
+ if (value === undefined) {
22
+ return;
23
+ }
24
+ assertRequiredColor(value, name);
25
+ };
26
+ var assertOptionalBoolean = (value, name) => {
27
+ if (value === undefined) {
28
+ return;
29
+ }
30
+ if (typeof value !== "boolean") {
31
+ throw new TypeError(`"${name}" must be a boolean, but got ${JSON.stringify(value)}`);
32
+ }
33
+ };
34
+
35
+ // src/color-utils.ts
36
+ var DEFAULT_AMOUNT = 1;
37
+ var DEFAULT_BRIGHTNESS_AMOUNT = 0;
38
+ var DEFAULT_HUE_DEGREES = 0;
39
+ var colorAmountSchema = {
40
+ type: "number",
41
+ min: 0,
42
+ max: 1,
43
+ step: 0.01,
44
+ default: DEFAULT_AMOUNT,
45
+ description: "Amount",
46
+ hiddenFromList: false
47
+ };
48
+ var colorMultiplierSchema = {
49
+ type: "number",
50
+ min: 0,
51
+ step: 0.01,
52
+ default: DEFAULT_AMOUNT,
53
+ description: "Amount",
54
+ hiddenFromList: false
55
+ };
56
+ var brightnessAmountSchema = {
57
+ type: "number",
58
+ min: -1,
59
+ max: 1,
60
+ step: 0.01,
61
+ default: DEFAULT_BRIGHTNESS_AMOUNT,
62
+ description: "Amount",
63
+ hiddenFromList: false
64
+ };
65
+ var hueDegreesSchema = {
66
+ type: "rotation-degrees",
67
+ step: 1,
68
+ default: DEFAULT_HUE_DEGREES,
69
+ description: "Degrees"
70
+ };
71
+ var assertOptionalFiniteNumber = (value, name) => {
72
+ if (value === undefined) {
73
+ return;
74
+ }
75
+ assertRequiredFiniteNumber(value, name);
76
+ };
77
+ var validateUnitInterval = (value, name) => {
78
+ if (value < 0) {
79
+ throw new TypeError(`"${name}" must be >= 0, but got ${JSON.stringify(value)}`);
80
+ }
81
+ if (value > 1) {
82
+ throw new TypeError(`"${name}" must be <= 1, but got ${JSON.stringify(value)}`);
83
+ }
84
+ };
85
+ var validateNonNegative = (value, name) => {
86
+ if (value < 0) {
87
+ throw new TypeError(`"${name}" must be >= 0, but got ${JSON.stringify(value)}`);
88
+ }
89
+ };
90
+ var validateSignedUnitInterval = (value, name) => {
91
+ if (value < -1) {
92
+ throw new TypeError(`"${name}" must be >= -1, but got ${JSON.stringify(value)}`);
93
+ }
94
+ if (value > 1) {
95
+ throw new TypeError(`"${name}" must be <= 1, but got ${JSON.stringify(value)}`);
96
+ }
97
+ };
98
+ var clampColorChannel = (value) => {
99
+ return Math.max(0, Math.min(255, value));
100
+ };
101
+ var parseColorRgba = (ctx, color) => {
102
+ ctx.clearRect(0, 0, 1, 1);
103
+ ctx.fillStyle = color;
104
+ ctx.fillRect(0, 0, 1, 1);
105
+ const { data } = ctx.getImageData(0, 0, 1, 1);
106
+ return [data[0], data[1], data[2], data[3]];
107
+ };
108
+
109
+ // src/curves.ts
110
+ var { createEffect, createCurveSampler, createWebGL2ContextError } = Internals;
111
+ var DEFAULT_POINTS = [
112
+ [0, 0],
113
+ [1, 1]
114
+ ];
115
+ var DEFAULT_CHANNEL = "rgb";
116
+ var DEFAULT_INTERPOLATION = "smooth";
117
+ var DEFAULT_AMOUNT2 = 1;
118
+ var MAX_POINTS = 32;
119
+ var LUT_SIZE = 1024;
120
+ var CURVES_CHANNELS = ["rgb", "red", "green", "blue"];
121
+ var CURVES_INTERPOLATIONS = ["smooth", "linear"];
122
+ var curvesSchema = {
123
+ channel: {
124
+ type: "enum",
125
+ variants: { rgb: {}, red: {}, green: {}, blue: {} },
126
+ default: DEFAULT_CHANNEL,
127
+ description: "Channel"
128
+ },
129
+ points: {
130
+ type: "array",
131
+ item: { type: "uv-coordinate", min: 0, max: 1, step: 0.001 },
132
+ default: DEFAULT_POINTS,
133
+ minLength: 2,
134
+ maxLength: MAX_POINTS,
135
+ newItemDefault: [0.5, 0.5],
136
+ description: "Points",
137
+ keyframable: false
138
+ },
139
+ interpolation: {
140
+ type: "enum",
141
+ variants: { smooth: {}, linear: {} },
142
+ default: DEFAULT_INTERPOLATION,
143
+ description: "Interpolation"
144
+ },
145
+ amount: colorAmountSchema
146
+ };
147
+ var resolve = (params) => ({
148
+ points: params.points ?? DEFAULT_POINTS,
149
+ channel: params.channel ?? DEFAULT_CHANNEL,
150
+ interpolation: params.interpolation ?? DEFAULT_INTERPOLATION,
151
+ amount: params.amount ?? DEFAULT_AMOUNT2
152
+ });
153
+ var validateCurvesParams = (params) => {
154
+ assertEffectParamsObject(params, "Curves");
155
+ assertOptionalFiniteNumber(params.amount, "amount");
156
+ validateUnitInterval(params.amount ?? DEFAULT_AMOUNT2, "amount");
157
+ if (params.channel !== undefined && !CURVES_CHANNELS.includes(params.channel)) {
158
+ throw new TypeError(`"channel" must be "rgb", "red", "green" or "blue", but got ${JSON.stringify(params.channel)}`);
159
+ }
160
+ if (params.interpolation !== undefined && !CURVES_INTERPOLATIONS.includes(params.interpolation)) {
161
+ throw new TypeError(`"interpolation" must be "smooth" or "linear", but got ${JSON.stringify(params.interpolation)}`);
162
+ }
163
+ if (params.points === undefined)
164
+ return;
165
+ if (!Array.isArray(params.points) || params.points.length < 2 || params.points.length > MAX_POINTS) {
166
+ throw new TypeError(`"points" must be an array of 2 to ${MAX_POINTS} input/output pairs`);
167
+ }
168
+ for (let index = 0;index < params.points.length; index++) {
169
+ const point = params.points[index];
170
+ if (!Array.isArray(point) || point.length !== 2) {
171
+ throw new TypeError(`"points[${index}]" must be an [input, output] pair`);
172
+ }
173
+ assertRequiredFiniteNumber(point[0], `points[${index}][0]`);
174
+ assertRequiredFiniteNumber(point[1], `points[${index}][1]`);
175
+ validateUnitInterval(point[0], `points[${index}][0]`);
176
+ validateUnitInterval(point[1], `points[${index}][1]`);
177
+ if (index > 0 && point[0] <= params.points[index - 1][0]) {
178
+ throw new TypeError('"points" must have strictly increasing input values');
179
+ }
180
+ }
181
+ };
182
+ var VERTEX_SHADER = `#version 300 es
183
+ in vec2 aPos;
184
+ in vec2 aUv;
185
+ out vec2 vUv;
186
+
187
+ void main() {
188
+ vUv = aUv;
189
+ gl_Position = vec4(aPos, 0.0, 1.0);
190
+ }
191
+ `;
192
+ var FRAGMENT_SHADER = `#version 300 es
193
+ precision highp float;
194
+
195
+ in vec2 vUv;
196
+ out vec4 fragColor;
197
+
198
+ uniform sampler2D uSource;
199
+ uniform highp sampler2D uCurve;
200
+ uniform int uChannel;
201
+ uniform float uAmount;
202
+
203
+ float sampleCurve(float inputValue) {
204
+ float position = clamp(inputValue, 0.0, 1.0) * float(${LUT_SIZE - 1});
205
+ int lower = int(floor(position));
206
+ int upper = min(lower + 1, ${LUT_SIZE - 1});
207
+ return mix(
208
+ texelFetch(uCurve, ivec2(lower, 0), 0).r,
209
+ texelFetch(uCurve, ivec2(upper, 0), 0).r,
210
+ fract(position)
211
+ );
212
+ }
213
+
214
+ void main() {
215
+ vec4 sourceColor = texture(uSource, vUv);
216
+ float alpha = sourceColor.a;
217
+ if (alpha <= 0.0) {
218
+ fragColor = vec4(0.0);
219
+ return;
220
+ }
221
+
222
+ vec3 color = sourceColor.rgb / alpha;
223
+ vec3 corrected = color;
224
+ if (uChannel == 0 || uChannel == 1) corrected.r = sampleCurve(color.r);
225
+ if (uChannel == 0 || uChannel == 2) corrected.g = sampleCurve(color.g);
226
+ if (uChannel == 0 || uChannel == 3) corrected.b = sampleCurve(color.b);
227
+ fragColor = vec4(mix(color, corrected, uAmount) * alpha, alpha);
228
+ }
229
+ `;
230
+ var compileShader = (gl, type, source) => {
231
+ const shader = gl.createShader(type);
232
+ if (!shader)
233
+ throw new Error("Failed to create curves shader");
234
+ gl.shaderSource(shader, source);
235
+ gl.compileShader(shader);
236
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
237
+ const log = gl.getShaderInfoLog(shader);
238
+ gl.deleteShader(shader);
239
+ throw new Error(`Curves shader compile failed: ${log ?? "(no log)"}`);
240
+ }
241
+ return shader;
242
+ };
243
+ var createTexture = (gl, filter) => {
244
+ const texture = gl.createTexture();
245
+ if (!texture)
246
+ throw new Error("Failed to create curves texture");
247
+ gl.bindTexture(gl.TEXTURE_2D, texture);
248
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
249
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
250
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
251
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
252
+ gl.bindTexture(gl.TEXTURE_2D, null);
253
+ return texture;
254
+ };
255
+ var curves = createEffect({
256
+ type: "remotion/curves",
257
+ label: "curves()",
258
+ documentationLink: "https://www.remotion.dev/docs/effects/curves",
259
+ backend: "webgl2",
260
+ calculateKey: (params) => {
261
+ const { points, channel, interpolation, amount } = resolve(params);
262
+ return `curves-${JSON.stringify(points)}-${channel}-${interpolation}-${amount}`;
263
+ },
264
+ setup: (target) => {
265
+ const gl = target.getContext("webgl2", {
266
+ premultipliedAlpha: true,
267
+ alpha: true,
268
+ preserveDrawingBuffer: true
269
+ });
270
+ if (!gl)
271
+ throw createWebGL2ContextError("curves effect");
272
+ const vertexShader = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
273
+ const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
274
+ const program = gl.createProgram();
275
+ if (!program)
276
+ throw new Error("Failed to create curves shader program");
277
+ gl.attachShader(program, vertexShader);
278
+ gl.attachShader(program, fragmentShader);
279
+ gl.linkProgram(program);
280
+ gl.deleteShader(vertexShader);
281
+ gl.deleteShader(fragmentShader);
282
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
283
+ const log = gl.getProgramInfoLog(program);
284
+ gl.deleteProgram(program);
285
+ throw new Error(`Curves shader link failed: ${log ?? "(no log)"}`);
286
+ }
287
+ const vao = gl.createVertexArray();
288
+ if (!vao)
289
+ throw new Error("Failed to create curves vertex array");
290
+ const vbo = gl.createBuffer();
291
+ if (!vbo)
292
+ throw new Error("Failed to create curves vertex buffer");
293
+ gl.bindVertexArray(vao);
294
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
295
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1, 1, 1, 1, 1]), gl.STATIC_DRAW);
296
+ const aPos = gl.getAttribLocation(program, "aPos");
297
+ const aUv = gl.getAttribLocation(program, "aUv");
298
+ gl.enableVertexAttribArray(aPos);
299
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
300
+ gl.enableVertexAttribArray(aUv);
301
+ gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
302
+ gl.bindVertexArray(null);
303
+ return {
304
+ gl,
305
+ program,
306
+ vao,
307
+ vbo,
308
+ sourceTexture: createTexture(gl, gl.LINEAR),
309
+ curveTexture: createTexture(gl, gl.NEAREST),
310
+ uniforms: {
311
+ uSource: gl.getUniformLocation(program, "uSource"),
312
+ uCurve: gl.getUniformLocation(program, "uCurve"),
313
+ uChannel: gl.getUniformLocation(program, "uChannel"),
314
+ uAmount: gl.getUniformLocation(program, "uAmount")
315
+ },
316
+ cachedCurveKey: null
317
+ };
318
+ },
319
+ apply: ({ source, width, height, params, state, flipSourceY }) => {
320
+ const { points, channel, interpolation, amount } = resolve(params);
321
+ const { gl, program, sourceTexture, curveTexture, uniforms, vao } = state;
322
+ const curveKey = `${interpolation}-${JSON.stringify(points)}`;
323
+ gl.activeTexture(gl.TEXTURE1);
324
+ gl.bindTexture(gl.TEXTURE_2D, curveTexture);
325
+ if (state.cachedCurveKey !== curveKey) {
326
+ const sample = createCurveSampler(points, interpolation);
327
+ const data = new Float32Array(LUT_SIZE);
328
+ for (let index = 0;index < LUT_SIZE; index++) {
329
+ data[index] = sample(index / (LUT_SIZE - 1));
330
+ }
331
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
332
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
333
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, LUT_SIZE, 1, 0, gl.RED, gl.FLOAT, data);
334
+ state.cachedCurveKey = curveKey;
335
+ }
336
+ gl.viewport(0, 0, width, height);
337
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
338
+ gl.clearColor(0, 0, 0, 0);
339
+ gl.clear(gl.COLOR_BUFFER_BIT);
340
+ gl.activeTexture(gl.TEXTURE0);
341
+ gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
342
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
343
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipSourceY);
344
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
345
+ gl.useProgram(program);
346
+ if (uniforms.uSource)
347
+ gl.uniform1i(uniforms.uSource, 0);
348
+ if (uniforms.uCurve)
349
+ gl.uniform1i(uniforms.uCurve, 1);
350
+ if (uniforms.uChannel)
351
+ gl.uniform1i(uniforms.uChannel, CURVES_CHANNELS.indexOf(channel));
352
+ if (uniforms.uAmount)
353
+ gl.uniform1f(uniforms.uAmount, amount);
354
+ gl.bindVertexArray(vao);
355
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
356
+ gl.bindVertexArray(null);
357
+ gl.bindTexture(gl.TEXTURE_2D, null);
358
+ gl.useProgram(null);
359
+ },
360
+ cleanup: ({ gl, program, vao, vbo, sourceTexture, curveTexture }) => {
361
+ gl.deleteTexture(sourceTexture);
362
+ gl.deleteTexture(curveTexture);
363
+ gl.deleteBuffer(vbo);
364
+ gl.deleteProgram(program);
365
+ gl.deleteVertexArray(vao);
366
+ },
367
+ schema: curvesSchema,
368
+ validateParams: validateCurvesParams
369
+ });
370
+ export {
371
+ curves,
372
+ curvesSchema
373
+ };
@@ -111,16 +111,31 @@ var { createEffect, createWebGL2ContextError } = Internals;
111
111
  var DEFAULT_BLACK_POINT = 0;
112
112
  var DEFAULT_WHITE_POINT = 1;
113
113
  var DEFAULT_GAMMA = 1;
114
+ var DEFAULT_OUTPUT_BLACK = 0;
115
+ var DEFAULT_OUTPUT_WHITE = 1;
116
+ var DEFAULT_CHANNEL = "rgb";
117
+ var LEVELS_CHANNELS = ["rgb", "red", "green", "blue"];
114
118
  var MIN_GAMMA = 0.01;
115
119
  var MAX_GAMMA = 10;
116
120
  var levelsSchema = {
121
+ channel: {
122
+ type: "enum",
123
+ variants: {
124
+ rgb: {},
125
+ red: {},
126
+ green: {},
127
+ blue: {}
128
+ },
129
+ default: DEFAULT_CHANNEL,
130
+ description: "Channel"
131
+ },
117
132
  blackPoint: {
118
133
  type: "number",
119
134
  min: 0,
120
135
  max: 1,
121
136
  step: 0.01,
122
137
  default: DEFAULT_BLACK_POINT,
123
- description: "Black point",
138
+ description: "Input black",
124
139
  hiddenFromList: false
125
140
  },
126
141
  whitePoint: {
@@ -129,7 +144,7 @@ var levelsSchema = {
129
144
  max: 1,
130
145
  step: 0.01,
131
146
  default: DEFAULT_WHITE_POINT,
132
- description: "White point",
147
+ description: "Input white",
133
148
  hiddenFromList: false
134
149
  },
135
150
  gamma: {
@@ -140,21 +155,49 @@ var levelsSchema = {
140
155
  default: DEFAULT_GAMMA,
141
156
  description: "Gamma",
142
157
  hiddenFromList: false
158
+ },
159
+ outputBlack: {
160
+ type: "number",
161
+ min: 0,
162
+ max: 1,
163
+ step: 0.01,
164
+ default: DEFAULT_OUTPUT_BLACK,
165
+ description: "Output black",
166
+ hiddenFromList: false
167
+ },
168
+ outputWhite: {
169
+ type: "number",
170
+ min: 0,
171
+ max: 1,
172
+ step: 0.01,
173
+ default: DEFAULT_OUTPUT_WHITE,
174
+ description: "Output white",
175
+ hiddenFromList: false
143
176
  }
144
177
  };
145
178
  var resolve = (params) => ({
179
+ channel: params.channel ?? DEFAULT_CHANNEL,
146
180
  blackPoint: params.blackPoint ?? DEFAULT_BLACK_POINT,
147
181
  whitePoint: params.whitePoint ?? DEFAULT_WHITE_POINT,
148
- gamma: params.gamma ?? DEFAULT_GAMMA
182
+ gamma: params.gamma ?? DEFAULT_GAMMA,
183
+ outputBlack: params.outputBlack ?? DEFAULT_OUTPUT_BLACK,
184
+ outputWhite: params.outputWhite ?? DEFAULT_OUTPUT_WHITE
149
185
  });
150
186
  var validateLevelsParams = (params) => {
151
187
  assertEffectParamsObject(params, "Levels");
152
188
  assertOptionalFiniteNumber(params.blackPoint, "blackPoint");
153
189
  assertOptionalFiniteNumber(params.whitePoint, "whitePoint");
154
190
  assertOptionalFiniteNumber(params.gamma, "gamma");
155
- const { blackPoint, whitePoint, gamma } = resolve(params);
191
+ assertOptionalFiniteNumber(params.outputBlack, "outputBlack");
192
+ assertOptionalFiniteNumber(params.outputWhite, "outputWhite");
193
+ if (params.channel !== undefined && !LEVELS_CHANNELS.includes(params.channel)) {
194
+ throw new TypeError(`"channel" must be "rgb", "red", "green" or "blue", but got ${JSON.stringify(params.channel)}`);
195
+ }
196
+ const { blackPoint, whitePoint, gamma, outputBlack, outputWhite } = resolve(params);
156
197
  validateUnitInterval(blackPoint, "blackPoint");
157
198
  validateUnitInterval(whitePoint, "whitePoint");
199
+ validateUnitInterval(outputBlack, "outputBlack");
200
+ validateUnitInterval(outputWhite, "outputWhite");
158
201
  if (blackPoint >= whitePoint) {
159
202
  throw new TypeError(`"blackPoint" must be less than "whitePoint", but got ${JSON.stringify(blackPoint)} and ${JSON.stringify(whitePoint)}`);
160
203
  }
@@ -185,6 +228,9 @@ uniform sampler2D uSource;
185
228
  uniform float uBlackPoint;
186
229
  uniform float uWhitePoint;
187
230
  uniform float uGamma;
231
+ uniform float uOutputBlack;
232
+ uniform float uOutputWhite;
233
+ uniform int uChannel;
188
234
 
189
235
  void main() {
190
236
  vec4 sourceColor = texture(uSource, vUv);
@@ -202,8 +248,19 @@ void main() {
202
248
  1.0
203
249
  );
204
250
  vec3 corrected = pow(normalized, vec3(1.0 / uGamma));
251
+ vec3 outputColor = mix(vec3(uOutputBlack), vec3(uOutputWhite), corrected);
205
252
 
206
- fragColor = vec4(corrected * alpha, alpha);
253
+ if (uChannel == 1) {
254
+ color.r = outputColor.r;
255
+ } else if (uChannel == 2) {
256
+ color.g = outputColor.g;
257
+ } else if (uChannel == 3) {
258
+ color.b = outputColor.b;
259
+ } else {
260
+ color = outputColor;
261
+ }
262
+
263
+ fragColor = vec4(color * alpha, alpha);
207
264
  }
208
265
  `;
209
266
  var compileShader = (gl, type, source) => {
@@ -291,7 +348,10 @@ var setupLevels = (target) => {
291
348
  uSource: gl.getUniformLocation(program, "uSource"),
292
349
  uBlackPoint: gl.getUniformLocation(program, "uBlackPoint"),
293
350
  uWhitePoint: gl.getUniformLocation(program, "uWhitePoint"),
294
- uGamma: gl.getUniformLocation(program, "uGamma")
351
+ uGamma: gl.getUniformLocation(program, "uGamma"),
352
+ uOutputBlack: gl.getUniformLocation(program, "uOutputBlack"),
353
+ uOutputWhite: gl.getUniformLocation(program, "uOutputWhite"),
354
+ uChannel: gl.getUniformLocation(program, "uChannel")
295
355
  }
296
356
  };
297
357
  };
@@ -301,12 +361,12 @@ var levels = createEffect({
301
361
  documentationLink: "https://www.remotion.dev/docs/effects/levels",
302
362
  backend: "webgl2",
303
363
  calculateKey: (params) => {
304
- const { blackPoint, whitePoint, gamma } = resolve(params);
305
- return `levels-${blackPoint}-${whitePoint}-${gamma}`;
364
+ const { channel, blackPoint, whitePoint, gamma, outputBlack, outputWhite } = resolve(params);
365
+ return `levels-${channel}-${blackPoint}-${whitePoint}-${gamma}-${outputBlack}-${outputWhite}`;
306
366
  },
307
367
  setup: setupLevels,
308
368
  apply: ({ source, width, height, params, state, flipSourceY }) => {
309
- const { blackPoint, whitePoint, gamma } = resolve(params);
369
+ const { channel, blackPoint, whitePoint, gamma, outputBlack, outputWhite } = resolve(params);
310
370
  const { gl, program, textureSource, uniforms, vao } = state;
311
371
  gl.viewport(0, 0, width, height);
312
372
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
@@ -327,6 +387,15 @@ var levels = createEffect({
327
387
  }
328
388
  if (uniforms.uGamma)
329
389
  gl.uniform1f(uniforms.uGamma, gamma);
390
+ if (uniforms.uOutputBlack) {
391
+ gl.uniform1f(uniforms.uOutputBlack, outputBlack);
392
+ }
393
+ if (uniforms.uOutputWhite) {
394
+ gl.uniform1f(uniforms.uOutputWhite, outputWhite);
395
+ }
396
+ if (uniforms.uChannel) {
397
+ gl.uniform1i(uniforms.uChannel, LEVELS_CHANNELS.indexOf(channel));
398
+ }
330
399
  gl.bindVertexArray(vao);
331
400
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
332
401
  gl.bindVertexArray(null);
@@ -343,5 +412,6 @@ var levels = createEffect({
343
412
  validateParams: validateLevelsParams
344
413
  });
345
414
  export {
346
- levels
415
+ levels,
416
+ levelsSchema
347
417
  };