@remotion/effects 4.0.490 → 4.0.492

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.
@@ -0,0 +1,8 @@
1
+ export declare const EffectInternals: {
2
+ readonly halftone: (params?: (import("./halftone.js").HalftoneParams & {
3
+ readonly disabled?: boolean | undefined;
4
+ }) | undefined) => import("remotion").EffectDescriptor<unknown>;
5
+ readonly tint: (params: import("./tint.js").TintParams & {
6
+ readonly disabled?: boolean | undefined;
7
+ }) => import("remotion").EffectDescriptor<unknown>;
8
+ };
@@ -0,0 +1,6 @@
1
+ import * as blurExports from '../blur/index.js';
2
+ export type { BlurParams } from '../blur/index.js';
3
+ declare const blur: (params: blurExports.BlurParams & {
4
+ readonly disabled?: boolean | undefined;
5
+ }) => import("remotion").EffectDescriptor<unknown>;
6
+ export { blur };
@@ -0,0 +1,399 @@
1
+ // src/flannel.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/flannel.ts
110
+ var { createEffect, createWebGL2ContextError } = Internals;
111
+ var DEFAULT_AMOUNT2 = 0.7;
112
+ var DEFAULT_SIZE = 96;
113
+ var DEFAULT_SOFTNESS = 0.18;
114
+ var DEFAULT_BASE_COLOR = "#c92f3d";
115
+ var DEFAULT_STRIPE_COLOR = "#241015";
116
+ var flannelSchema = {
117
+ amount: {
118
+ type: "number",
119
+ min: 0,
120
+ max: 1,
121
+ step: 0.01,
122
+ default: DEFAULT_AMOUNT2,
123
+ description: "Amount",
124
+ hiddenFromList: false
125
+ },
126
+ size: {
127
+ type: "number",
128
+ min: 1,
129
+ max: 500,
130
+ step: 1,
131
+ default: DEFAULT_SIZE,
132
+ description: "Pattern size",
133
+ hiddenFromList: false
134
+ },
135
+ softness: {
136
+ type: "number",
137
+ min: 0,
138
+ max: 1,
139
+ step: 0.01,
140
+ default: DEFAULT_SOFTNESS,
141
+ description: "Softness",
142
+ hiddenFromList: false
143
+ },
144
+ baseColor: {
145
+ type: "color",
146
+ default: DEFAULT_BASE_COLOR,
147
+ description: "Base color"
148
+ },
149
+ stripeColor: {
150
+ type: "color",
151
+ default: DEFAULT_STRIPE_COLOR,
152
+ description: "Stripe color"
153
+ }
154
+ };
155
+ var resolve = (params) => ({
156
+ amount: params.amount ?? DEFAULT_AMOUNT2,
157
+ size: params.size ?? DEFAULT_SIZE,
158
+ softness: params.softness ?? DEFAULT_SOFTNESS,
159
+ baseColor: params.baseColor ?? DEFAULT_BASE_COLOR,
160
+ stripeColor: params.stripeColor ?? DEFAULT_STRIPE_COLOR
161
+ });
162
+ var validateFlannelParams = (params) => {
163
+ assertEffectParamsObject(params, "Flannel");
164
+ assertOptionalFiniteNumber(params.amount, "amount");
165
+ assertOptionalFiniteNumber(params.size, "size");
166
+ assertOptionalFiniteNumber(params.softness, "softness");
167
+ assertOptionalColor(params.baseColor, "baseColor");
168
+ assertOptionalColor(params.stripeColor, "stripeColor");
169
+ const resolved = resolve(params);
170
+ validateUnitInterval(resolved.amount, "amount");
171
+ validateUnitInterval(resolved.softness, "softness");
172
+ if (resolved.size <= 0) {
173
+ throw new TypeError(`"size" must be greater than 0, but got ${JSON.stringify(resolved.size)}`);
174
+ }
175
+ };
176
+ var FLANNEL_VS = `#version 300 es
177
+ in vec2 aPos;
178
+ in vec2 aUv;
179
+ out vec2 vUv;
180
+
181
+ void main() {
182
+ vUv = aUv;
183
+ gl_Position = vec4(aPos, 0.0, 1.0);
184
+ }
185
+ `;
186
+ var FLANNEL_FS = `#version 300 es
187
+ precision highp float;
188
+
189
+ in vec2 vUv;
190
+ out vec4 fragColor;
191
+
192
+ uniform sampler2D uSource;
193
+ uniform vec2 uResolution;
194
+ uniform float uAmount;
195
+ uniform float uSize;
196
+ uniform float uSoftness;
197
+ uniform vec4 uBaseColor;
198
+ uniform vec4 uStripeColor;
199
+
200
+ float stripe(float coordinate, float center, float width, float softness) {
201
+ float distanceFromCenter = abs(fract(coordinate) - center);
202
+ float halfWidth = width * 0.5;
203
+ return 1.0 - smoothstep(halfWidth, halfWidth + softness, distanceFromCenter);
204
+ }
205
+
206
+ void main() {
207
+ vec4 source = texture(uSource, vUv);
208
+ if (source.a <= 0.001 || uAmount <= 0.0) {
209
+ fragColor = source;
210
+ return;
211
+ }
212
+
213
+ vec2 pixel = vUv * uResolution;
214
+ vec2 plaid = pixel / max(uSize, 0.001);
215
+ float edge = mix(0.002, 0.08, uSoftness);
216
+
217
+ float verticalWide = stripe(plaid.x, 0.5, 0.34, edge);
218
+ float horizontalWide = stripe(plaid.y, 0.5, 0.34, edge);
219
+ float verticalFine = stripe(plaid.x * 2.0, 0.5, 0.07, edge * 0.5);
220
+ float horizontalFine = stripe(plaid.y * 2.0, 0.5, 0.07, edge * 0.5);
221
+ float bands = max(max(verticalWide, horizontalWide), max(verticalFine, horizontalFine) * 0.72);
222
+ float crossing = max(verticalWide * horizontalWide, verticalFine * horizontalFine);
223
+
224
+ float threadX = 0.5 + 0.5 * sin(pixel.x * 3.14159265);
225
+ float threadY = 0.5 + 0.5 * sin(pixel.y * 3.14159265);
226
+ float weave = (threadX - 0.5) * (threadY - 0.5) * 0.12;
227
+
228
+ vec3 sourceRgb = source.rgb / source.a;
229
+ float luminance = dot(sourceRgb, vec3(0.2126, 0.7152, 0.0722));
230
+ vec3 plaidColor = mix(uBaseColor.rgb, uStripeColor.rgb, bands * uStripeColor.a);
231
+ plaidColor = mix(plaidColor, uStripeColor.rgb * 0.72, crossing * uStripeColor.a);
232
+ plaidColor *= mix(0.58, 1.18, luminance) + weave;
233
+ vec3 result = mix(sourceRgb, clamp(plaidColor, 0.0, 1.0), uAmount);
234
+
235
+ fragColor = vec4(result * source.a, source.a);
236
+ }
237
+ `;
238
+ var compileShader = (gl, type, source) => {
239
+ const shader = gl.createShader(type);
240
+ if (!shader) {
241
+ throw new Error("Failed to create WebGL shader");
242
+ }
243
+ gl.shaderSource(shader, source);
244
+ gl.compileShader(shader);
245
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
246
+ const log = gl.getShaderInfoLog(shader);
247
+ gl.deleteShader(shader);
248
+ throw new Error(`Flannel shader compile failed: ${log ?? "(no log)"}`);
249
+ }
250
+ return shader;
251
+ };
252
+ var setupFlannel = (target) => {
253
+ const gl = target.getContext("webgl2", {
254
+ premultipliedAlpha: true,
255
+ alpha: true,
256
+ preserveDrawingBuffer: true
257
+ });
258
+ if (!gl) {
259
+ throw createWebGL2ContextError("flannel effect");
260
+ }
261
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
262
+ const vertexShader = compileShader(gl, gl.VERTEX_SHADER, FLANNEL_VS);
263
+ const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, FLANNEL_FS);
264
+ const program = gl.createProgram();
265
+ if (!program) {
266
+ throw new Error("Failed to create WebGL program");
267
+ }
268
+ gl.attachShader(program, vertexShader);
269
+ gl.attachShader(program, fragmentShader);
270
+ gl.linkProgram(program);
271
+ gl.deleteShader(vertexShader);
272
+ gl.deleteShader(fragmentShader);
273
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
274
+ const log = gl.getProgramInfoLog(program);
275
+ gl.deleteProgram(program);
276
+ throw new Error(`Flannel program link failed: ${log ?? "(no log)"}`);
277
+ }
278
+ const vao = gl.createVertexArray();
279
+ const vbo = gl.createBuffer();
280
+ if (!vao || !vbo) {
281
+ throw new Error("Failed to create WebGL geometry");
282
+ }
283
+ gl.bindVertexArray(vao);
284
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
285
+ 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);
286
+ const aPos = gl.getAttribLocation(program, "aPos");
287
+ const aUv = gl.getAttribLocation(program, "aUv");
288
+ gl.enableVertexAttribArray(aPos);
289
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
290
+ gl.enableVertexAttribArray(aUv);
291
+ gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
292
+ gl.bindVertexArray(null);
293
+ const texture = gl.createTexture();
294
+ if (!texture) {
295
+ throw new Error("Failed to create WebGL texture");
296
+ }
297
+ gl.bindTexture(gl.TEXTURE_2D, texture);
298
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
299
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
300
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
301
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
302
+ gl.bindTexture(gl.TEXTURE_2D, null);
303
+ const colorCanvas = document.createElement("canvas");
304
+ colorCanvas.width = 1;
305
+ colorCanvas.height = 1;
306
+ const colorCtx = colorCanvas.getContext("2d", { willReadFrequently: true });
307
+ if (!colorCtx) {
308
+ throw new Error("Failed to acquire 2D context for color parsing");
309
+ }
310
+ return {
311
+ gl,
312
+ program,
313
+ vao,
314
+ vbo,
315
+ texture,
316
+ uSource: gl.getUniformLocation(program, "uSource"),
317
+ uResolution: gl.getUniformLocation(program, "uResolution"),
318
+ uAmount: gl.getUniformLocation(program, "uAmount"),
319
+ uSize: gl.getUniformLocation(program, "uSize"),
320
+ uSoftness: gl.getUniformLocation(program, "uSoftness"),
321
+ uBaseColor: gl.getUniformLocation(program, "uBaseColor"),
322
+ uStripeColor: gl.getUniformLocation(program, "uStripeColor"),
323
+ colorCtx,
324
+ cachedBaseColor: "",
325
+ cachedBaseColorRgba: [0, 0, 0, 255],
326
+ cachedStripeColor: "",
327
+ cachedStripeColorRgba: [0, 0, 0, 255]
328
+ };
329
+ };
330
+ var normalizedRgba = (color) => [
331
+ color[0] / 255,
332
+ color[1] / 255,
333
+ color[2] / 255,
334
+ color[3] / 255
335
+ ];
336
+ var flannel = createEffect({
337
+ type: "dev.remotion.effects.flannel",
338
+ label: "flannel()",
339
+ documentationLink: "https://www.remotion.dev/docs/effects/flannel",
340
+ backend: "webgl2",
341
+ calculateKey: (params) => {
342
+ const resolved = resolve(params);
343
+ return `flannel-${resolved.amount}-${resolved.size}-${resolved.softness}-${resolved.baseColor}-${resolved.stripeColor}`;
344
+ },
345
+ setup: setupFlannel,
346
+ apply: ({ source, width, height, params, state, flipSourceY }) => {
347
+ const resolved = resolve(params);
348
+ if (state.cachedBaseColor !== resolved.baseColor) {
349
+ state.cachedBaseColor = resolved.baseColor;
350
+ state.cachedBaseColorRgba = parseColorRgba(state.colorCtx, resolved.baseColor);
351
+ }
352
+ if (state.cachedStripeColor !== resolved.stripeColor) {
353
+ state.cachedStripeColor = resolved.stripeColor;
354
+ state.cachedStripeColorRgba = parseColorRgba(state.colorCtx, resolved.stripeColor);
355
+ }
356
+ const base = normalizedRgba(state.cachedBaseColorRgba);
357
+ const stripe = normalizedRgba(state.cachedStripeColorRgba);
358
+ const { gl } = state;
359
+ gl.viewport(0, 0, width, height);
360
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
361
+ gl.clearColor(0, 0, 0, 0);
362
+ gl.clear(gl.COLOR_BUFFER_BIT);
363
+ gl.useProgram(state.program);
364
+ gl.bindVertexArray(state.vao);
365
+ gl.activeTexture(gl.TEXTURE0);
366
+ gl.bindTexture(gl.TEXTURE_2D, state.texture);
367
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipSourceY);
368
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
369
+ if (state.uSource)
370
+ gl.uniform1i(state.uSource, 0);
371
+ if (state.uResolution)
372
+ gl.uniform2f(state.uResolution, width, height);
373
+ if (state.uAmount)
374
+ gl.uniform1f(state.uAmount, resolved.amount);
375
+ if (state.uSize)
376
+ gl.uniform1f(state.uSize, resolved.size);
377
+ if (state.uSoftness)
378
+ gl.uniform1f(state.uSoftness, resolved.softness);
379
+ if (state.uBaseColor)
380
+ gl.uniform4f(state.uBaseColor, ...base);
381
+ if (state.uStripeColor)
382
+ gl.uniform4f(state.uStripeColor, ...stripe);
383
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
384
+ gl.bindVertexArray(null);
385
+ gl.bindTexture(gl.TEXTURE_2D, null);
386
+ gl.useProgram(null);
387
+ },
388
+ cleanup: ({ gl, program, vao, vbo, texture }) => {
389
+ gl.deleteTexture(texture);
390
+ gl.deleteBuffer(vbo);
391
+ gl.deleteProgram(program);
392
+ gl.deleteVertexArray(vao);
393
+ },
394
+ schema: flannelSchema,
395
+ validateParams: validateFlannelParams
396
+ });
397
+ export {
398
+ flannel
399
+ };