@remotion/effects 4.0.485 → 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.
- package/dist/esm/paper.mjs +921 -0
- package/dist/paper.d.ts +35 -0
- package/package.json +11 -3
|
@@ -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
|
+
};
|
package/dist/paper.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type PaperParams = {
|
|
2
|
+
/** Strength of the paper texture from `0` to `1`. Defaults to `1`. */
|
|
3
|
+
readonly amount?: number;
|
|
4
|
+
/** Light-facing paper color. Defaults to `#9fadbc`. */
|
|
5
|
+
readonly colorFront?: string;
|
|
6
|
+
/** Shadow-facing paper color. Defaults to `#ffffff`. */
|
|
7
|
+
readonly colorBack?: string;
|
|
8
|
+
/** Sharpness of light and color transitions from `0` to `1`. Defaults to `0.3`. */
|
|
9
|
+
readonly contrast?: number;
|
|
10
|
+
/** Fine pixel noise from `0` to `1`. Defaults to `0.4`. */
|
|
11
|
+
readonly roughness?: number;
|
|
12
|
+
/** Curly fiber intensity from `0` to `1`. Defaults to `0.3`. */
|
|
13
|
+
readonly fiber?: number;
|
|
14
|
+
/** Curly fiber scale from `0.01` to `1`. Defaults to `0.2`. */
|
|
15
|
+
readonly fiberSize?: number;
|
|
16
|
+
/** Cell-based crumple intensity from `0` to `1`. Defaults to `0.3`. */
|
|
17
|
+
readonly crumples?: number;
|
|
18
|
+
/** Cell-based crumple scale from `0.01` to `1`. Defaults to `0.35`. */
|
|
19
|
+
readonly crumpleSize?: number;
|
|
20
|
+
/** Fold lighting intensity from `0` to `1`. Defaults to `0.65`. */
|
|
21
|
+
readonly folds?: number;
|
|
22
|
+
/** Number of generated folds from `0` to `15`. Defaults to `5`. */
|
|
23
|
+
readonly foldCount?: number;
|
|
24
|
+
/** Speckle visibility from `0` to `1`. Defaults to `0.2`. */
|
|
25
|
+
readonly drops?: number;
|
|
26
|
+
/** Large-scale mask applied to the paper pattern from `0` to `1`. Defaults to `0`. */
|
|
27
|
+
readonly fade?: number;
|
|
28
|
+
/** Seed for the generated paper pattern from `0` to `1000`. Defaults to `6`. */
|
|
29
|
+
readonly seed?: number;
|
|
30
|
+
/** Scale of the generated paper texture from `0.01` to `4`. Defaults to `0.6`. */
|
|
31
|
+
readonly scale?: number;
|
|
32
|
+
};
|
|
33
|
+
export declare const paper: (params?: (PaperParams & {
|
|
34
|
+
readonly disabled?: boolean | undefined;
|
|
35
|
+
}) | undefined) => import("remotion").EffectDescriptor<unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/effects",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.486",
|
|
4
4
|
"description": "Effects that can be applied to Remotion-based canvas components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"url": "https://github.com/remotion-dev/remotion/issues"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"remotion": "4.0.
|
|
29
|
+
"remotion": "4.0.486"
|
|
30
30
|
},
|
|
31
31
|
"exports": {
|
|
32
32
|
".": {
|
|
@@ -199,6 +199,11 @@
|
|
|
199
199
|
"module": "./dist/esm/noise-displacement.mjs",
|
|
200
200
|
"import": "./dist/esm/noise-displacement.mjs"
|
|
201
201
|
},
|
|
202
|
+
"./paper": {
|
|
203
|
+
"types": "./dist/paper.d.ts",
|
|
204
|
+
"module": "./dist/esm/paper.mjs",
|
|
205
|
+
"import": "./dist/esm/paper.mjs"
|
|
206
|
+
},
|
|
202
207
|
"./pattern": {
|
|
203
208
|
"types": "./dist/pattern.d.ts",
|
|
204
209
|
"module": "./dist/esm/pattern.mjs",
|
|
@@ -402,6 +407,9 @@
|
|
|
402
407
|
"noise-displacement": [
|
|
403
408
|
"dist/noise-displacement.d.ts"
|
|
404
409
|
],
|
|
410
|
+
"paper": [
|
|
411
|
+
"dist/paper.d.ts"
|
|
412
|
+
],
|
|
405
413
|
"pattern": [
|
|
406
414
|
"dist/pattern.d.ts"
|
|
407
415
|
],
|
|
@@ -466,7 +474,7 @@
|
|
|
466
474
|
},
|
|
467
475
|
"homepage": "https://www.remotion.dev/docs/effects/api",
|
|
468
476
|
"devDependencies": {
|
|
469
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
477
|
+
"@remotion/eslint-config-internal": "4.0.486",
|
|
470
478
|
"@vitest/browser-playwright": "4.0.9",
|
|
471
479
|
"eslint": "9.19.0",
|
|
472
480
|
"vitest": "4.0.9",
|