@remotion/effects 4.0.484 → 4.0.486

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,921 @@
1
+ // src/paper.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/paper.ts
110
+ var { createEffect, createWebGL2ContextError } = Internals;
111
+ var DEFAULT_AMOUNT2 = 1;
112
+ var DEFAULT_COLOR_FRONT = "#9fadbc";
113
+ var DEFAULT_COLOR_BACK = "#ffffff";
114
+ var DEFAULT_CONTRAST = 0.3;
115
+ var DEFAULT_ROUGHNESS = 0.4;
116
+ var DEFAULT_FIBER = 0.3;
117
+ var DEFAULT_FIBER_SIZE = 0.2;
118
+ var DEFAULT_CRUMPLES = 0.3;
119
+ var DEFAULT_CRUMPLE_SIZE = 0.35;
120
+ var DEFAULT_FOLDS = 0.65;
121
+ var DEFAULT_FOLD_COUNT = 5;
122
+ var DEFAULT_DROPS = 0.2;
123
+ var DEFAULT_FADE = 0;
124
+ var DEFAULT_SEED = 6;
125
+ var DEFAULT_SCALE = 0.6;
126
+ var MAX_FOLD_COUNT = 15;
127
+ var MAX_SEED = 1000;
128
+ var NOISE_TEXTURE_SIZE = 256;
129
+ var paperSchema = {
130
+ amount: {
131
+ type: "number",
132
+ min: 0,
133
+ max: 1,
134
+ step: 0.01,
135
+ default: DEFAULT_AMOUNT2,
136
+ description: "Amount",
137
+ hiddenFromList: false
138
+ },
139
+ colorFront: {
140
+ type: "color",
141
+ default: DEFAULT_COLOR_FRONT,
142
+ description: "Front color"
143
+ },
144
+ colorBack: {
145
+ type: "color",
146
+ default: DEFAULT_COLOR_BACK,
147
+ description: "Back color"
148
+ },
149
+ contrast: {
150
+ type: "number",
151
+ min: 0,
152
+ max: 1,
153
+ step: 0.01,
154
+ default: DEFAULT_CONTRAST,
155
+ description: "Contrast",
156
+ hiddenFromList: false
157
+ },
158
+ roughness: {
159
+ type: "number",
160
+ min: 0,
161
+ max: 1,
162
+ step: 0.01,
163
+ default: DEFAULT_ROUGHNESS,
164
+ description: "Roughness",
165
+ hiddenFromList: false
166
+ },
167
+ fiber: {
168
+ type: "number",
169
+ min: 0,
170
+ max: 1,
171
+ step: 0.01,
172
+ default: DEFAULT_FIBER,
173
+ description: "Fiber",
174
+ hiddenFromList: false
175
+ },
176
+ fiberSize: {
177
+ type: "number",
178
+ min: 0.01,
179
+ max: 1,
180
+ step: 0.01,
181
+ default: DEFAULT_FIBER_SIZE,
182
+ description: "Fiber size",
183
+ hiddenFromList: false
184
+ },
185
+ crumples: {
186
+ type: "number",
187
+ min: 0,
188
+ max: 1,
189
+ step: 0.01,
190
+ default: DEFAULT_CRUMPLES,
191
+ description: "Crumples",
192
+ hiddenFromList: false
193
+ },
194
+ crumpleSize: {
195
+ type: "number",
196
+ min: 0.01,
197
+ max: 1,
198
+ step: 0.01,
199
+ default: DEFAULT_CRUMPLE_SIZE,
200
+ description: "Crumple size",
201
+ hiddenFromList: false
202
+ },
203
+ folds: {
204
+ type: "number",
205
+ min: 0,
206
+ max: 1,
207
+ step: 0.01,
208
+ default: DEFAULT_FOLDS,
209
+ description: "Folds",
210
+ hiddenFromList: false
211
+ },
212
+ foldCount: {
213
+ type: "number",
214
+ min: 0,
215
+ max: MAX_FOLD_COUNT,
216
+ step: 1,
217
+ default: DEFAULT_FOLD_COUNT,
218
+ description: "Fold count",
219
+ hiddenFromList: false
220
+ },
221
+ drops: {
222
+ type: "number",
223
+ min: 0,
224
+ max: 1,
225
+ step: 0.01,
226
+ default: DEFAULT_DROPS,
227
+ description: "Drops",
228
+ hiddenFromList: false
229
+ },
230
+ fade: {
231
+ type: "number",
232
+ min: 0,
233
+ max: 1,
234
+ step: 0.01,
235
+ default: DEFAULT_FADE,
236
+ description: "Fade",
237
+ hiddenFromList: false
238
+ },
239
+ seed: {
240
+ type: "number",
241
+ min: 0,
242
+ max: MAX_SEED,
243
+ step: 0.01,
244
+ default: DEFAULT_SEED,
245
+ description: "Seed",
246
+ hiddenFromList: false
247
+ },
248
+ scale: {
249
+ type: "number",
250
+ min: 0.01,
251
+ max: 4,
252
+ step: 0.01,
253
+ default: DEFAULT_SCALE,
254
+ description: "Scale",
255
+ hiddenFromList: false
256
+ }
257
+ };
258
+ var resolve = (p) => ({
259
+ amount: p.amount ?? DEFAULT_AMOUNT2,
260
+ colorFront: p.colorFront ?? DEFAULT_COLOR_FRONT,
261
+ colorBack: p.colorBack ?? DEFAULT_COLOR_BACK,
262
+ contrast: p.contrast ?? DEFAULT_CONTRAST,
263
+ roughness: p.roughness ?? DEFAULT_ROUGHNESS,
264
+ fiber: p.fiber ?? DEFAULT_FIBER,
265
+ fiberSize: p.fiberSize ?? DEFAULT_FIBER_SIZE,
266
+ crumples: p.crumples ?? DEFAULT_CRUMPLES,
267
+ crumpleSize: p.crumpleSize ?? DEFAULT_CRUMPLE_SIZE,
268
+ folds: p.folds ?? DEFAULT_FOLDS,
269
+ foldCount: p.foldCount ?? DEFAULT_FOLD_COUNT,
270
+ drops: p.drops ?? DEFAULT_DROPS,
271
+ fade: p.fade ?? DEFAULT_FADE,
272
+ seed: p.seed ?? DEFAULT_SEED,
273
+ scale: p.scale ?? DEFAULT_SCALE
274
+ });
275
+ var validateAtMost = (value, max, name) => {
276
+ if (value > max) {
277
+ throw new TypeError(`"${name}" must be <= ${max}, but got ${JSON.stringify(value)}`);
278
+ }
279
+ };
280
+ var validatePositiveUnitInterval = (value, name) => {
281
+ if (value <= 0) {
282
+ throw new TypeError(`"${name}" must be greater than 0, but got ${JSON.stringify(value)}`);
283
+ }
284
+ validateAtMost(value, 1, name);
285
+ };
286
+ var validatePaperParams = (params) => {
287
+ assertEffectParamsObject(params, "Paper");
288
+ assertOptionalFiniteNumber(params.amount, "amount");
289
+ assertOptionalColor(params.colorFront, "colorFront");
290
+ assertOptionalColor(params.colorBack, "colorBack");
291
+ assertOptionalFiniteNumber(params.contrast, "contrast");
292
+ assertOptionalFiniteNumber(params.roughness, "roughness");
293
+ assertOptionalFiniteNumber(params.fiber, "fiber");
294
+ assertOptionalFiniteNumber(params.fiberSize, "fiberSize");
295
+ assertOptionalFiniteNumber(params.crumples, "crumples");
296
+ assertOptionalFiniteNumber(params.crumpleSize, "crumpleSize");
297
+ assertOptionalFiniteNumber(params.folds, "folds");
298
+ assertOptionalFiniteNumber(params.foldCount, "foldCount");
299
+ assertOptionalFiniteNumber(params.drops, "drops");
300
+ assertOptionalFiniteNumber(params.fade, "fade");
301
+ assertOptionalFiniteNumber(params.seed, "seed");
302
+ assertOptionalFiniteNumber(params.scale, "scale");
303
+ const r = resolve(params);
304
+ validateUnitInterval(r.amount, "amount");
305
+ validateUnitInterval(r.contrast, "contrast");
306
+ validateUnitInterval(r.roughness, "roughness");
307
+ validateUnitInterval(r.fiber, "fiber");
308
+ validatePositiveUnitInterval(r.fiberSize, "fiberSize");
309
+ validateUnitInterval(r.crumples, "crumples");
310
+ validatePositiveUnitInterval(r.crumpleSize, "crumpleSize");
311
+ validateUnitInterval(r.folds, "folds");
312
+ validateNonNegative(r.foldCount, "foldCount");
313
+ validateAtMost(r.foldCount, MAX_FOLD_COUNT, "foldCount");
314
+ validateUnitInterval(r.drops, "drops");
315
+ validateUnitInterval(r.fade, "fade");
316
+ validateNonNegative(r.seed, "seed");
317
+ validateAtMost(r.seed, MAX_SEED, "seed");
318
+ if (r.scale <= 0) {
319
+ throw new TypeError(`"scale" must be greater than 0, but got ${JSON.stringify(r.scale)}`);
320
+ }
321
+ validateAtMost(r.scale, 4, "scale");
322
+ };
323
+ var PAPER_VS = `#version 300 es
324
+ in vec2 aPos;
325
+ in vec2 aUv;
326
+ out vec2 vUv;
327
+
328
+ void main() {
329
+ vUv = aUv;
330
+ gl_Position = vec4(aPos, 0.0, 1.0);
331
+ }
332
+ `;
333
+ var PAPER_FS = `#version 300 es
334
+ precision highp float;
335
+
336
+ in vec2 vUv;
337
+ out vec4 fragColor;
338
+
339
+ uniform sampler2D uSource;
340
+ uniform vec2 uResolution;
341
+ uniform float uImageAspectRatio;
342
+
343
+ uniform vec4 uColorFront;
344
+ uniform vec4 uColorBack;
345
+ uniform float uAmount;
346
+ uniform float uContrast;
347
+ uniform float uRoughness;
348
+ uniform float uFiber;
349
+ uniform float uFiberSize;
350
+ uniform float uCrumples;
351
+ uniform float uCrumpleSize;
352
+ uniform float uFolds;
353
+ uniform float uFoldCount;
354
+ uniform float uDrops;
355
+ uniform float uFade;
356
+ uniform float uSeed;
357
+ uniform float uScale;
358
+ uniform sampler2D uNoiseTexture;
359
+
360
+ #define TWO_PI 6.28318530718
361
+ #define PI 3.14159265358979323846
362
+
363
+ float getUvFrame(vec2 uv) {
364
+ float aax = 2.0 * fwidth(uv.x);
365
+ float aay = 2.0 * fwidth(uv.y);
366
+
367
+ float left = smoothstep(0.0, aax, uv.x);
368
+ float right = 1.0 - smoothstep(1.0 - aax, 1.0, uv.x);
369
+ float bottom = smoothstep(0.0, aay, uv.y);
370
+ float top = 1.0 - smoothstep(1.0 - aay, 1.0, uv.y);
371
+
372
+ return left * right * bottom * top;
373
+ }
374
+
375
+ vec2 rotate(vec2 uv, float th) {
376
+ return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;
377
+ }
378
+
379
+ vec2 seedOffset(float salt) {
380
+ float seeded = uSeed + salt;
381
+ return fract(
382
+ sin(
383
+ vec2(
384
+ seeded * 12.9898 + 78.233,
385
+ seeded * 39.3468 + 11.135
386
+ )
387
+ ) * 43758.5453
388
+ );
389
+ }
390
+
391
+ float randomR(vec2 p) {
392
+ vec2 uv = floor(p) / 100.0 + 0.5;
393
+ return texture(uNoiseTexture, fract(uv)).r;
394
+ }
395
+
396
+ float valueNoise(vec2 st) {
397
+ vec2 i = floor(st);
398
+ vec2 f = fract(st);
399
+ float a = randomR(i);
400
+ float b = randomR(i + vec2(1.0, 0.0));
401
+ float c = randomR(i + vec2(0.0, 1.0));
402
+ float d = randomR(i + vec2(1.0, 1.0));
403
+ vec2 u = f * f * (3.0 - 2.0 * f);
404
+ float x1 = mix(a, b, u.x);
405
+ float x2 = mix(c, d, u.x);
406
+ return mix(x1, x2, u.y);
407
+ }
408
+
409
+ float fbm(vec2 n) {
410
+ float total = 0.0;
411
+ float amplitude = 0.4;
412
+ for (int i = 0; i < 3; i++) {
413
+ total += valueNoise(n) * amplitude;
414
+ n *= 1.99;
415
+ amplitude *= 0.65;
416
+ }
417
+ return total;
418
+ }
419
+
420
+ float randomG(vec2 p) {
421
+ vec2 uv = floor(p) / 50.0 + 0.5;
422
+ return texture(uNoiseTexture, fract(uv)).g;
423
+ }
424
+
425
+ float roughnessNoise(vec2 p) {
426
+ p *= 0.1;
427
+ float o = 0.0;
428
+ for (float i = 0.0; ++i < 4.0; p *= 2.1) {
429
+ vec4 w = vec4(floor(p), ceil(p));
430
+ vec2 f = fract(p);
431
+ o += mix(
432
+ mix(randomG(w.xy), randomG(w.xw), f.y),
433
+ mix(randomG(w.zy), randomG(w.zw), f.y),
434
+ f.x
435
+ );
436
+ o += 0.2 / exp(2.0 * abs(sin(0.2 * p.x + 0.5 * p.y)));
437
+ }
438
+ return o / 3.0;
439
+ }
440
+
441
+ float fiberRandom(vec2 p) {
442
+ vec2 uv = floor(p) / 100.0;
443
+ return texture(uNoiseTexture, fract(uv)).b;
444
+ }
445
+
446
+ float fiberValueNoise(vec2 st) {
447
+ vec2 i = floor(st);
448
+ vec2 f = fract(st);
449
+ float a = fiberRandom(i);
450
+ float b = fiberRandom(i + vec2(1.0, 0.0));
451
+ float c = fiberRandom(i + vec2(0.0, 1.0));
452
+ float d = fiberRandom(i + vec2(1.0, 1.0));
453
+ vec2 u = f * f * (3.0 - 2.0 * f);
454
+ float x1 = mix(a, b, u.x);
455
+ float x2 = mix(c, d, u.x);
456
+ return mix(x1, x2, u.y);
457
+ }
458
+
459
+ float fiberNoiseFbm(in vec2 n, vec2 seedOffset) {
460
+ float total = 0.0;
461
+ float amplitude = 1.0;
462
+ for (int i = 0; i < 4; i++) {
463
+ n = rotate(n, 0.7);
464
+ total += fiberValueNoise(n + seedOffset) * amplitude;
465
+ n *= 2.0;
466
+ amplitude *= 0.6;
467
+ }
468
+ return total;
469
+ }
470
+
471
+ float fiberNoise(vec2 uv, vec2 seedOffset) {
472
+ float epsilon = 0.001;
473
+ float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset);
474
+ float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset);
475
+ float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset);
476
+ float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset);
477
+ return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon);
478
+ }
479
+
480
+ vec2 randomGB(vec2 p) {
481
+ vec2 uv = floor(p) / 50.0 + 0.5;
482
+ return texture(uNoiseTexture, fract(uv)).gb;
483
+ }
484
+
485
+ float crumpledNoise(vec2 t, float pw) {
486
+ vec2 p = floor(t);
487
+ float wsum = 0.0;
488
+ float cl = 0.0;
489
+ for (int y = -1; y < 2; y += 1) {
490
+ for (int x = -1; x < 2; x += 1) {
491
+ vec2 b = vec2(float(x), float(y));
492
+ vec2 q = b + p;
493
+ vec2 q2 = q - floor(q / 8.0) * 8.0;
494
+ vec2 c = q + randomGB(q2);
495
+ vec2 r = c - t;
496
+ float w =
497
+ pow(smoothstep(0.0, 1.0, 1.0 - abs(r.x)), pw) *
498
+ pow(smoothstep(0.0, 1.0, 1.0 - abs(r.y)), pw);
499
+ cl += (0.5 + 0.5 * sin((q2.x + q2.y * 5.0) * 8.0)) * w;
500
+ wsum += w;
501
+ }
502
+ }
503
+ return pow(wsum != 0.0 ? cl / wsum : 0.0, 0.5) * 2.0;
504
+ }
505
+
506
+ float crumplesShape(vec2 uv) {
507
+ return crumpledNoise(uv * 0.25, 16.0) * crumpledNoise(uv * 0.5, 2.0);
508
+ }
509
+
510
+ vec2 folds(vec2 uv) {
511
+ vec3 pp = vec3(0.0);
512
+ float l = 9.0;
513
+ for (float i = 0.0; i < 15.0; i++) {
514
+ if (i >= uFoldCount) {
515
+ break;
516
+ }
517
+ vec2 rand = randomGB(vec2(i, i * uSeed));
518
+ float an = rand.x * TWO_PI;
519
+ vec2 p = vec2(cos(an), sin(an)) * rand.y;
520
+ float dist = distance(uv, p);
521
+ l = min(l, dist);
522
+
523
+ if (l == dist) {
524
+ pp.xy = uv - p.xy;
525
+ pp.z = dist;
526
+ }
527
+ }
528
+ return mix(pp.xy, vec2(0.0), pow(pp.z, 0.25));
529
+ }
530
+
531
+ float drops(vec2 uv) {
532
+ vec2 iDropsUV = floor(uv);
533
+ vec2 fDropsUV = fract(uv);
534
+ float dropsMinDist = 1.0;
535
+ for (int j = -1; j <= 1; j++) {
536
+ for (int i = -1; i <= 1; i++) {
537
+ vec2 neighbor = vec2(float(i), float(j));
538
+ vec2 offset = randomGB(iDropsUV + neighbor);
539
+ offset = 0.5 + 0.5 * sin(10.0 * uSeed + TWO_PI * offset);
540
+ vec2 pos = neighbor + offset - fDropsUV;
541
+ float dist = length(pos);
542
+ dropsMinDist = min(dropsMinDist, dropsMinDist * dist);
543
+ }
544
+ }
545
+ return 1.0 - smoothstep(0.05, 0.09, pow(dropsMinDist, 0.5));
546
+ }
547
+
548
+ void main() {
549
+ vec4 source = texture(uSource, vUv);
550
+ float sourceAlpha = source.a;
551
+
552
+ if (sourceAlpha <= 0.001 || uAmount <= 0.0) {
553
+ fragColor = source;
554
+ return;
555
+ }
556
+
557
+ vec3 sourceRgb = source.rgb / sourceAlpha;
558
+ vec2 imageUV = vUv;
559
+ vec2 patternUV = vUv - 0.5;
560
+ patternUV /= max(uScale, 0.001);
561
+ patternUV = 5.0 * (patternUV * vec2(uImageAspectRatio, 1.0));
562
+
563
+ vec2 roughnessUv =
564
+ 1.5 * (gl_FragCoord.xy - 0.5 * uResolution) +
565
+ 128.0 * seedOffset(1.0);
566
+ float roughness =
567
+ roughnessNoise(roughnessUv + vec2(1.0, 0.0)) -
568
+ roughnessNoise(roughnessUv - vec2(1.0, 0.0));
569
+
570
+ vec2 crumplesUV =
571
+ fract(patternUV * 0.02 / max(uCrumpleSize, 0.001) - uSeed) * 32.0;
572
+ float crumples =
573
+ uCrumples *
574
+ (crumplesShape(crumplesUV + vec2(0.05, 0.0)) -
575
+ crumplesShape(crumplesUV));
576
+
577
+ vec2 fiberUV = 2.0 / max(uFiberSize, 0.001) * patternUV;
578
+ float fiber = fiberNoise(fiberUV, 64.0 * seedOffset(2.0));
579
+ fiber = 0.5 * uFiber * (fiber - 1.0);
580
+
581
+ vec2 normal = vec2(0.0);
582
+ vec2 normalImage = vec2(0.0);
583
+
584
+ vec2 foldsUV = patternUV * 0.12;
585
+ foldsUV = rotate(foldsUV, 4.0 * uSeed);
586
+ vec2 w = folds(foldsUV);
587
+ foldsUV = rotate(foldsUV + 0.007 * cos(uSeed), 0.01 * sin(uSeed));
588
+ vec2 w2 = folds(foldsUV);
589
+
590
+ float dropPattern = uDrops * drops(patternUV * 2.0);
591
+
592
+ float fade = uFade * fbm(0.17 * patternUV + 10.0 * uSeed);
593
+ fade = clamp(8.0 * fade * fade * fade, 0.0, 1.0);
594
+
595
+ w = mix(w, vec2(0.0), fade);
596
+ w2 = mix(w2, vec2(0.0), fade);
597
+ crumples = mix(crumples, 0.0, fade);
598
+ dropPattern = mix(dropPattern, 0.0, fade);
599
+ fiber *= mix(1.0, 0.5, fade);
600
+ roughness *= mix(1.0, 0.5, fade);
601
+
602
+ normal.xy += uFolds * min(5.0 * uContrast, 1.0) * 4.0 * max(vec2(0.0), w + w2);
603
+ normalImage.xy += uFolds * 2.0 * w;
604
+ normal.xy += crumples;
605
+ normalImage.xy += 1.5 * crumples;
606
+ normal.xy += 3.0 * dropPattern;
607
+ normalImage.xy += 0.2 * dropPattern;
608
+ normal.xy += uRoughness * 1.5 * roughness;
609
+ normal.xy += fiber;
610
+ normalImage += uRoughness * 0.75 * roughness;
611
+ normalImage += 0.2 * fiber;
612
+
613
+ vec3 lightPos = vec3(1.0, 2.0, 1.0);
614
+ float res = dot(
615
+ normalize(vec3(normal, 9.5 - 9.0 * pow(uContrast, 0.1))),
616
+ normalize(lightPos)
617
+ );
618
+
619
+ imageUV += 0.02 * normalImage;
620
+ float frame = getUvFrame(imageUV);
621
+ vec4 displacedSource = texture(uSource, clamp(imageUV, vec2(0.0), vec2(1.0)));
622
+ vec3 displacedRgb = displacedSource.a > 0.001
623
+ ? displacedSource.rgb / displacedSource.a
624
+ : sourceRgb;
625
+ displacedRgb += 0.6 * pow(uContrast, 0.4) * (res - 0.7);
626
+
627
+ vec3 frontRgb = mix(vec3(1.0), uColorFront.rgb, uColorFront.a);
628
+ vec3 backRgb = mix(vec3(1.0), uColorBack.rgb, uColorBack.a);
629
+ vec3 paperTone = mix(backRgb, frontRgb, clamp(res, 0.0, 1.0));
630
+ vec3 texturedRgb = displacedRgb * (0.72 + 0.42 * res);
631
+ texturedRgb = mix(texturedRgb, texturedRgb * paperTone, 0.65);
632
+ texturedRgb -= 0.007 * dropPattern;
633
+ texturedRgb = mix(sourceRgb, texturedRgb, frame);
634
+
635
+ vec3 finalRgb = mix(sourceRgb, clamp(texturedRgb, 0.0, 1.0), uAmount);
636
+ fragColor = vec4(finalRgb * sourceAlpha, sourceAlpha);
637
+ }
638
+ `;
639
+ var compileShader = (gl, type, source) => {
640
+ const shader = gl.createShader(type);
641
+ if (!shader) {
642
+ throw new Error("Failed to create WebGL shader");
643
+ }
644
+ gl.shaderSource(shader, source);
645
+ gl.compileShader(shader);
646
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
647
+ const log = gl.getShaderInfoLog(shader);
648
+ gl.deleteShader(shader);
649
+ throw new Error(`Paper shader compile failed: ${log ?? "(no log)"}`);
650
+ }
651
+ return shader;
652
+ };
653
+ var linkProgram = (gl, vs, fs) => {
654
+ const program = gl.createProgram();
655
+ if (!program) {
656
+ throw new Error("Failed to create WebGL program");
657
+ }
658
+ gl.attachShader(program, vs);
659
+ gl.attachShader(program, fs);
660
+ gl.linkProgram(program);
661
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
662
+ const log = gl.getProgramInfoLog(program);
663
+ gl.deleteProgram(program);
664
+ throw new Error(`Paper program link failed: ${log ?? "(no log)"}`);
665
+ }
666
+ return program;
667
+ };
668
+ var createSourceTexture = (gl) => {
669
+ const texture = gl.createTexture();
670
+ if (!texture) {
671
+ throw new Error("Failed to create WebGL texture");
672
+ }
673
+ gl.bindTexture(gl.TEXTURE_2D, texture);
674
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
675
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
676
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
677
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
678
+ gl.bindTexture(gl.TEXTURE_2D, null);
679
+ return texture;
680
+ };
681
+ var initialNoiseState = (seed) => {
682
+ const scaledSeed = Math.round(seed * 1000);
683
+ const mixedState = (2654435769 ^ Math.imul(scaledSeed, 2246822507)) >>> 0;
684
+ return mixedState === 0 ? 2654435769 : mixedState;
685
+ };
686
+ var nextNoiseState = (state) => {
687
+ let next = state;
688
+ next ^= next << 13;
689
+ next ^= next >>> 17;
690
+ next ^= next << 5;
691
+ return next >>> 0;
692
+ };
693
+ var createNoiseData = (seed) => {
694
+ const data = new Uint8Array(NOISE_TEXTURE_SIZE * NOISE_TEXTURE_SIZE * 4);
695
+ let state = initialNoiseState(seed);
696
+ for (let i = 0;i < data.length; i += 4) {
697
+ state = nextNoiseState(state);
698
+ data[i] = state & 255;
699
+ state = nextNoiseState(state);
700
+ data[i + 1] = state & 255;
701
+ state = nextNoiseState(state);
702
+ data[i + 2] = state & 255;
703
+ data[i + 3] = 255;
704
+ }
705
+ return data;
706
+ };
707
+ var uploadNoiseTexture = (gl, texture, seed) => {
708
+ const data = createNoiseData(seed);
709
+ gl.bindTexture(gl.TEXTURE_2D, texture);
710
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
711
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, NOISE_TEXTURE_SIZE, NOISE_TEXTURE_SIZE, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
712
+ };
713
+ var createNoiseTexture = (gl) => {
714
+ const texture = gl.createTexture();
715
+ if (!texture) {
716
+ throw new Error("Failed to create WebGL noise texture");
717
+ }
718
+ uploadNoiseTexture(gl, texture, DEFAULT_SEED);
719
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
720
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
721
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
722
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
723
+ gl.bindTexture(gl.TEXTURE_2D, null);
724
+ return texture;
725
+ };
726
+ var setupPaper = (target) => {
727
+ const gl = target.getContext("webgl2", {
728
+ premultipliedAlpha: true,
729
+ alpha: true,
730
+ preserveDrawingBuffer: true
731
+ });
732
+ if (!gl) {
733
+ throw createWebGL2ContextError("paper effect");
734
+ }
735
+ const vs = compileShader(gl, gl.VERTEX_SHADER, PAPER_VS);
736
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, PAPER_FS);
737
+ const program = linkProgram(gl, vs, fs);
738
+ gl.deleteShader(vs);
739
+ gl.deleteShader(fs);
740
+ const vao = gl.createVertexArray();
741
+ if (!vao) {
742
+ throw new Error("Failed to create WebGL vertex array");
743
+ }
744
+ gl.bindVertexArray(vao);
745
+ const data = new Float32Array([
746
+ -1,
747
+ -1,
748
+ 0,
749
+ 0,
750
+ 1,
751
+ -1,
752
+ 1,
753
+ 0,
754
+ -1,
755
+ 1,
756
+ 0,
757
+ 1,
758
+ 1,
759
+ 1,
760
+ 1,
761
+ 1
762
+ ]);
763
+ const vbo = gl.createBuffer();
764
+ if (!vbo) {
765
+ throw new Error("Failed to create WebGL buffer");
766
+ }
767
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
768
+ gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
769
+ const aPos = gl.getAttribLocation(program, "aPos");
770
+ const aUv = gl.getAttribLocation(program, "aUv");
771
+ gl.enableVertexAttribArray(aPos);
772
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
773
+ gl.enableVertexAttribArray(aUv);
774
+ gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
775
+ gl.bindVertexArray(null);
776
+ const sourceTexture = createSourceTexture(gl);
777
+ const noiseTexture = createNoiseTexture(gl);
778
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
779
+ const colorCanvas = document.createElement("canvas");
780
+ colorCanvas.width = 1;
781
+ colorCanvas.height = 1;
782
+ const colorCtx = colorCanvas.getContext("2d", { willReadFrequently: true });
783
+ if (!colorCtx) {
784
+ throw new Error("Failed to acquire 2D context for color parsing");
785
+ }
786
+ return {
787
+ gl,
788
+ program,
789
+ vao,
790
+ vbo,
791
+ sourceTexture,
792
+ noiseTexture,
793
+ uSource: gl.getUniformLocation(program, "uSource"),
794
+ uResolution: gl.getUniformLocation(program, "uResolution"),
795
+ uImageAspectRatio: gl.getUniformLocation(program, "uImageAspectRatio"),
796
+ uColorFront: gl.getUniformLocation(program, "uColorFront"),
797
+ uColorBack: gl.getUniformLocation(program, "uColorBack"),
798
+ uAmount: gl.getUniformLocation(program, "uAmount"),
799
+ uContrast: gl.getUniformLocation(program, "uContrast"),
800
+ uRoughness: gl.getUniformLocation(program, "uRoughness"),
801
+ uFiber: gl.getUniformLocation(program, "uFiber"),
802
+ uFiberSize: gl.getUniformLocation(program, "uFiberSize"),
803
+ uCrumples: gl.getUniformLocation(program, "uCrumples"),
804
+ uCrumpleSize: gl.getUniformLocation(program, "uCrumpleSize"),
805
+ uFolds: gl.getUniformLocation(program, "uFolds"),
806
+ uFoldCount: gl.getUniformLocation(program, "uFoldCount"),
807
+ uDrops: gl.getUniformLocation(program, "uDrops"),
808
+ uFade: gl.getUniformLocation(program, "uFade"),
809
+ uSeed: gl.getUniformLocation(program, "uSeed"),
810
+ uScale: gl.getUniformLocation(program, "uScale"),
811
+ uNoiseTexture: gl.getUniformLocation(program, "uNoiseTexture"),
812
+ colorCtx,
813
+ cachedColorFront: "",
814
+ cachedColorFrontRgba: [159, 173, 188, 255],
815
+ cachedColorBack: "",
816
+ cachedColorBackRgba: [255, 255, 255, 255],
817
+ cachedNoiseSeed: DEFAULT_SEED
818
+ };
819
+ };
820
+ var normalizedRgba = (color) => {
821
+ return [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
822
+ };
823
+ var paper = createEffect({
824
+ type: "dev.remotion.effects.paper",
825
+ label: "paper()",
826
+ documentationLink: "https://www.remotion.dev/docs/effects/paper",
827
+ backend: "webgl2",
828
+ calculateKey: (params) => {
829
+ const r = resolve(params);
830
+ return `paper-${r.amount}-${r.colorFront}-${r.colorBack}-${r.contrast}-${r.roughness}-${r.fiber}-${r.fiberSize}-${r.crumples}-${r.crumpleSize}-${r.folds}-${r.foldCount}-${r.drops}-${r.fade}-${r.seed}-${r.scale}`;
831
+ },
832
+ setup: (target) => setupPaper(target),
833
+ apply: ({ source, width, height, params, state, flipSourceY }) => {
834
+ const r = resolve(params);
835
+ const { gl, program, vao, sourceTexture, noiseTexture } = state;
836
+ if (state.cachedColorFront !== r.colorFront) {
837
+ state.cachedColorFront = r.colorFront;
838
+ state.cachedColorFrontRgba = parseColorRgba(state.colorCtx, r.colorFront);
839
+ }
840
+ if (state.cachedColorBack !== r.colorBack) {
841
+ state.cachedColorBack = r.colorBack;
842
+ state.cachedColorBackRgba = parseColorRgba(state.colorCtx, r.colorBack);
843
+ }
844
+ const [frontRed, frontGreen, frontBlue, frontAlpha] = normalizedRgba(state.cachedColorFrontRgba);
845
+ const [backRed, backGreen, backBlue, backAlpha] = normalizedRgba(state.cachedColorBackRgba);
846
+ gl.viewport(0, 0, width, height);
847
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
848
+ gl.clearColor(0, 0, 0, 0);
849
+ gl.clear(gl.COLOR_BUFFER_BIT);
850
+ gl.useProgram(program);
851
+ gl.bindVertexArray(vao);
852
+ gl.activeTexture(gl.TEXTURE0);
853
+ gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
854
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
855
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipSourceY);
856
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
857
+ gl.activeTexture(gl.TEXTURE1);
858
+ gl.bindTexture(gl.TEXTURE_2D, noiseTexture);
859
+ if (state.cachedNoiseSeed !== r.seed) {
860
+ uploadNoiseTexture(gl, noiseTexture, r.seed);
861
+ state.cachedNoiseSeed = r.seed;
862
+ }
863
+ if (state.uSource)
864
+ gl.uniform1i(state.uSource, 0);
865
+ if (state.uResolution)
866
+ gl.uniform2f(state.uResolution, width, height);
867
+ if (state.uImageAspectRatio)
868
+ gl.uniform1f(state.uImageAspectRatio, width / height);
869
+ if (state.uColorFront)
870
+ gl.uniform4f(state.uColorFront, frontRed, frontGreen, frontBlue, frontAlpha);
871
+ if (state.uColorBack)
872
+ gl.uniform4f(state.uColorBack, backRed, backGreen, backBlue, backAlpha);
873
+ if (state.uAmount)
874
+ gl.uniform1f(state.uAmount, r.amount);
875
+ if (state.uContrast)
876
+ gl.uniform1f(state.uContrast, r.contrast);
877
+ if (state.uRoughness)
878
+ gl.uniform1f(state.uRoughness, r.roughness);
879
+ if (state.uFiber)
880
+ gl.uniform1f(state.uFiber, r.fiber);
881
+ if (state.uFiberSize)
882
+ gl.uniform1f(state.uFiberSize, r.fiberSize);
883
+ if (state.uCrumples)
884
+ gl.uniform1f(state.uCrumples, r.crumples);
885
+ if (state.uCrumpleSize)
886
+ gl.uniform1f(state.uCrumpleSize, r.crumpleSize);
887
+ if (state.uFolds)
888
+ gl.uniform1f(state.uFolds, r.folds);
889
+ if (state.uFoldCount)
890
+ gl.uniform1f(state.uFoldCount, r.foldCount);
891
+ if (state.uDrops)
892
+ gl.uniform1f(state.uDrops, r.drops);
893
+ if (state.uFade)
894
+ gl.uniform1f(state.uFade, r.fade);
895
+ if (state.uSeed)
896
+ gl.uniform1f(state.uSeed, r.seed);
897
+ if (state.uScale)
898
+ gl.uniform1f(state.uScale, r.scale);
899
+ if (state.uNoiseTexture)
900
+ gl.uniform1i(state.uNoiseTexture, 1);
901
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
902
+ gl.bindVertexArray(null);
903
+ gl.activeTexture(gl.TEXTURE1);
904
+ gl.bindTexture(gl.TEXTURE_2D, null);
905
+ gl.activeTexture(gl.TEXTURE0);
906
+ gl.bindTexture(gl.TEXTURE_2D, null);
907
+ gl.useProgram(null);
908
+ },
909
+ cleanup: ({ gl, program, vao, vbo, sourceTexture, noiseTexture }) => {
910
+ gl.deleteTexture(sourceTexture);
911
+ gl.deleteTexture(noiseTexture);
912
+ gl.deleteBuffer(vbo);
913
+ gl.deleteProgram(program);
914
+ gl.deleteVertexArray(vao);
915
+ },
916
+ schema: paperSchema,
917
+ validateParams: validatePaperParams
918
+ });
919
+ export {
920
+ paper
921
+ };