@remotion/effects 4.0.535 → 4.0.537
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/THIRD_PARTY_LICENSES.md +30 -0
- package/dist/bevel-alpha/index.d.ts +13 -0
- package/dist/bevel-alpha/shaders.d.ts +3 -0
- package/dist/bevel-alpha.d.ts +1 -0
- package/dist/cylinder/index.d.ts +20 -0
- package/dist/cylinder/shader.d.ts +1 -0
- package/dist/cylinder.d.ts +1 -0
- package/dist/esm/bevel-alpha.mjs +474 -0
- package/dist/esm/cylinder.mjs +390 -0
- package/dist/esm/fractal-noise.mjs +688 -0
- package/dist/esm/lens-blur.mjs +550 -0
- package/dist/esm/page-turn.mjs +405 -0
- package/dist/esm/sphere.mjs +376 -0
- package/dist/esm/turbulent-displace.mjs +652 -0
- package/dist/fractal-noise/index.d.ts +40 -0
- package/dist/fractal-noise/shader.d.ts +1 -0
- package/dist/fractal-noise.d.ts +1 -0
- package/dist/lens-blur/index.d.ts +30 -0
- package/dist/lens-blur/shader.d.ts +1 -0
- package/dist/lens-blur.d.ts +1 -0
- package/dist/page-turn/index.d.ts +20 -0
- package/dist/page-turn/shader.d.ts +1 -0
- package/dist/page-turn.d.ts +1 -0
- package/dist/sphere/index.d.ts +18 -0
- package/dist/sphere/shader.d.ts +1 -0
- package/dist/sphere.d.ts +1 -0
- package/dist/turbulent-displace/index.d.ts +28 -0
- package/dist/turbulent-displace/shader.d.ts +1 -0
- package/dist/turbulent-displace.d.ts +1 -0
- package/dist/value-noise-shader.d.ts +1 -0
- package/dist/webgpu-projection-runtime.d.ts +24 -0
- package/package.json +62 -5
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
// src/page-turn/index.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/webgpu-projection-runtime.ts
|
|
110
|
+
var cleanupWebGpuProjection = (state) => {
|
|
111
|
+
state.resources?.texture.destroy();
|
|
112
|
+
state.resources?.uniforms.destroy();
|
|
113
|
+
state.resources = null;
|
|
114
|
+
state.context.unconfigure();
|
|
115
|
+
};
|
|
116
|
+
var setupWebGpuProjection = (target, label) => {
|
|
117
|
+
const context = target.getContext("webgpu");
|
|
118
|
+
if (!context) {
|
|
119
|
+
throw new Error(`WebGPU is not available for the ${label} effect`);
|
|
120
|
+
}
|
|
121
|
+
return { context, resources: null };
|
|
122
|
+
};
|
|
123
|
+
var applyWebGpuProjection = ({
|
|
124
|
+
state,
|
|
125
|
+
source,
|
|
126
|
+
width,
|
|
127
|
+
height,
|
|
128
|
+
device,
|
|
129
|
+
shader,
|
|
130
|
+
uniformData
|
|
131
|
+
}) => {
|
|
132
|
+
if (state.resources && (state.resources.device !== device || state.resources.width !== width || state.resources.height !== height)) {
|
|
133
|
+
cleanupWebGpuProjection(state);
|
|
134
|
+
}
|
|
135
|
+
if (!state.resources) {
|
|
136
|
+
const format = navigator.gpu.getPreferredCanvasFormat();
|
|
137
|
+
state.context.configure({ device, format, alphaMode: "premultiplied" });
|
|
138
|
+
const module = device.createShaderModule({ code: shader });
|
|
139
|
+
const pipeline = device.createRenderPipeline({
|
|
140
|
+
layout: "auto",
|
|
141
|
+
vertex: { module, entryPoint: "vertex" },
|
|
142
|
+
fragment: { module, entryPoint: "fragment", targets: [{ format }] },
|
|
143
|
+
primitive: { topology: "triangle-list" }
|
|
144
|
+
});
|
|
145
|
+
const uniforms = device.createBuffer({
|
|
146
|
+
size: uniformData.byteLength,
|
|
147
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
148
|
+
});
|
|
149
|
+
const sampler = device.createSampler({
|
|
150
|
+
addressModeU: "repeat",
|
|
151
|
+
magFilter: "linear",
|
|
152
|
+
minFilter: "linear"
|
|
153
|
+
});
|
|
154
|
+
const texture = device.createTexture({
|
|
155
|
+
size: [width, height],
|
|
156
|
+
format: "rgba8unorm",
|
|
157
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
|
|
158
|
+
});
|
|
159
|
+
const bindGroup = device.createBindGroup({
|
|
160
|
+
layout: pipeline.getBindGroupLayout(0),
|
|
161
|
+
entries: [
|
|
162
|
+
{ binding: 0, resource: texture.createView() },
|
|
163
|
+
{ binding: 1, resource: sampler },
|
|
164
|
+
{ binding: 2, resource: { buffer: uniforms } }
|
|
165
|
+
]
|
|
166
|
+
});
|
|
167
|
+
state.resources = {
|
|
168
|
+
device,
|
|
169
|
+
pipeline,
|
|
170
|
+
uniforms,
|
|
171
|
+
sampler,
|
|
172
|
+
texture,
|
|
173
|
+
bindGroup,
|
|
174
|
+
width,
|
|
175
|
+
height
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const { resources } = state;
|
|
179
|
+
device.queue.copyExternalImageToTexture({ source }, { texture: resources.texture, premultipliedAlpha: true }, [width, height]);
|
|
180
|
+
device.queue.writeBuffer(resources.uniforms, 0, uniformData);
|
|
181
|
+
const encoder = device.createCommandEncoder();
|
|
182
|
+
const pass = encoder.beginRenderPass({
|
|
183
|
+
colorAttachments: [
|
|
184
|
+
{
|
|
185
|
+
view: state.context.getCurrentTexture().createView(),
|
|
186
|
+
clearValue: { r: 0, g: 0, b: 0, a: 0 },
|
|
187
|
+
loadOp: "clear",
|
|
188
|
+
storeOp: "store"
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
});
|
|
192
|
+
pass.setPipeline(resources.pipeline);
|
|
193
|
+
pass.setBindGroup(0, resources.bindGroup);
|
|
194
|
+
pass.draw(3);
|
|
195
|
+
pass.end();
|
|
196
|
+
device.queue.submit([encoder.finish()]);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// src/page-turn/shader.ts
|
|
200
|
+
var PAGE_TURN_SHADER = `
|
|
201
|
+
struct Params {
|
|
202
|
+
resolution: vec2f,
|
|
203
|
+
foldPosition: vec2f,
|
|
204
|
+
geometry: vec4f,
|
|
205
|
+
paperColor: vec4f,
|
|
206
|
+
back: vec4f,
|
|
207
|
+
}
|
|
208
|
+
@group(0) @binding(0) var source: texture_2d<f32>;
|
|
209
|
+
@group(0) @binding(1) var sourceSampler: sampler;
|
|
210
|
+
@group(0) @binding(2) var<uniform> params: Params;
|
|
211
|
+
|
|
212
|
+
@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
|
|
213
|
+
let positions = array<vec2f, 3>(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3));
|
|
214
|
+
return vec4f(positions[index], 0, 1);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
fn samplePage(pixel: vec2f) -> vec4f {
|
|
218
|
+
if (any(pixel < vec2f(0)) || any(pixel >= params.resolution)) { return vec4f(0); }
|
|
219
|
+
// The shared projection sampler wraps horizontally; pages must not wrap at the edges.
|
|
220
|
+
let uv = clamp(pixel, vec2f(0.5), params.resolution - vec2f(0.5)) / params.resolution;
|
|
221
|
+
return textureSampleLevel(source, sourceSampler, uv, 0);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
225
|
+
let radius = params.geometry.x;
|
|
226
|
+
let direction = params.geometry.y;
|
|
227
|
+
let normal = vec2f(-sin(direction), cos(direction));
|
|
228
|
+
let distance = dot(position.xy - params.foldPosition, normal);
|
|
229
|
+
let coverage = 1.0 - smoothstep(radius - max(fwidth(distance), 0.001), radius, distance);
|
|
230
|
+
if (distance >= radius) { return vec4f(0); }
|
|
231
|
+
|
|
232
|
+
var front = vec4f(0);
|
|
233
|
+
var back = vec4f(0);
|
|
234
|
+
var backDistance = 3.14159265359 * radius - distance;
|
|
235
|
+
var backShade = 0.9;
|
|
236
|
+
if (distance <= 0.0) {
|
|
237
|
+
front = samplePage(position.xy);
|
|
238
|
+
} else {
|
|
239
|
+
let angle = asin(clamp(distance / radius, 0.0, 1.0));
|
|
240
|
+
let frontDistance = radius * angle;
|
|
241
|
+
backDistance = 3.14159265359 * radius - frontDistance;
|
|
242
|
+
let light = params.geometry.z;
|
|
243
|
+
let lightDot = normal.x * sin(light) - normal.y * cos(light);
|
|
244
|
+
let shade = 1.0 - 0.4 * (angle / 1.57079632679) * (0.5 + 0.5 * lightDot);
|
|
245
|
+
let color = samplePage(position.xy + normal * (frontDistance - distance));
|
|
246
|
+
front = vec4f(color.rgb * shade, color.a);
|
|
247
|
+
backShade = 0.6 + 0.4 * cos(angle);
|
|
248
|
+
}
|
|
249
|
+
let color = samplePage(position.xy + normal * (backDistance - distance));
|
|
250
|
+
let tint = (1.0 - params.back.x) * params.paperColor.a;
|
|
251
|
+
back = vec4f(mix(color.rgb, params.paperColor.rgb * color.a, tint) * backShade, color.a);
|
|
252
|
+
if (params.geometry.w == 1.0) { return front * coverage; }
|
|
253
|
+
if (params.geometry.w == 2.0) { return back * coverage; }
|
|
254
|
+
// Premultiplied source-over: the curled back covers the front, which shows through its alpha.
|
|
255
|
+
return (back + front * (1.0 - back.a)) * coverage;
|
|
256
|
+
}
|
|
257
|
+
`;
|
|
258
|
+
|
|
259
|
+
// src/page-turn/index.ts
|
|
260
|
+
var DEFAULT_FOLD_POSITION = [0.7, 0.7];
|
|
261
|
+
var DEFAULT_FOLD_DIRECTION = 315;
|
|
262
|
+
var DEFAULT_FOLD_RADIUS = 60;
|
|
263
|
+
var DEFAULT_LIGHT_DIRECTION = -45;
|
|
264
|
+
var DEFAULT_RENDER = "both";
|
|
265
|
+
var DEFAULT_BACK_PAGE_OPACITY = 0.25;
|
|
266
|
+
var DEFAULT_PAPER_COLOR = "#ffffff";
|
|
267
|
+
var pageTurnSchema = {
|
|
268
|
+
foldPosition: {
|
|
269
|
+
type: "uv-coordinate",
|
|
270
|
+
default: DEFAULT_FOLD_POSITION,
|
|
271
|
+
description: "Fold position"
|
|
272
|
+
},
|
|
273
|
+
foldDirection: {
|
|
274
|
+
type: "rotation-degrees",
|
|
275
|
+
default: DEFAULT_FOLD_DIRECTION,
|
|
276
|
+
description: "Fold direction"
|
|
277
|
+
},
|
|
278
|
+
foldRadius: {
|
|
279
|
+
type: "number",
|
|
280
|
+
min: 1,
|
|
281
|
+
max: 500,
|
|
282
|
+
step: 1,
|
|
283
|
+
default: DEFAULT_FOLD_RADIUS,
|
|
284
|
+
description: "Fold radius",
|
|
285
|
+
hiddenFromList: false
|
|
286
|
+
},
|
|
287
|
+
lightDirection: {
|
|
288
|
+
type: "rotation-degrees",
|
|
289
|
+
default: DEFAULT_LIGHT_DIRECTION,
|
|
290
|
+
description: "Light direction"
|
|
291
|
+
},
|
|
292
|
+
render: {
|
|
293
|
+
type: "enum",
|
|
294
|
+
variants: { both: {}, front: {}, back: {} },
|
|
295
|
+
default: DEFAULT_RENDER,
|
|
296
|
+
description: "Faces"
|
|
297
|
+
},
|
|
298
|
+
backPageOpacity: {
|
|
299
|
+
type: "number",
|
|
300
|
+
min: 0,
|
|
301
|
+
max: 1,
|
|
302
|
+
step: 0.01,
|
|
303
|
+
default: DEFAULT_BACK_PAGE_OPACITY,
|
|
304
|
+
description: "Back image opacity",
|
|
305
|
+
hiddenFromList: false
|
|
306
|
+
},
|
|
307
|
+
paperColor: {
|
|
308
|
+
type: "color",
|
|
309
|
+
default: DEFAULT_PAPER_COLOR,
|
|
310
|
+
description: "Paper color"
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
var resolve = (params) => ({
|
|
314
|
+
foldPosition: params.foldPosition ?? DEFAULT_FOLD_POSITION,
|
|
315
|
+
foldDirection: params.foldDirection ?? DEFAULT_FOLD_DIRECTION,
|
|
316
|
+
foldRadius: params.foldRadius ?? DEFAULT_FOLD_RADIUS,
|
|
317
|
+
lightDirection: params.lightDirection ?? DEFAULT_LIGHT_DIRECTION,
|
|
318
|
+
render: params.render ?? DEFAULT_RENDER,
|
|
319
|
+
backPageOpacity: params.backPageOpacity ?? DEFAULT_BACK_PAGE_OPACITY,
|
|
320
|
+
paperColor: params.paperColor ?? DEFAULT_PAPER_COLOR
|
|
321
|
+
});
|
|
322
|
+
var pageTurn = Internals.createEffect({
|
|
323
|
+
type: "remotion/page-turn",
|
|
324
|
+
label: "pageTurn()",
|
|
325
|
+
documentationLink: "https://www.remotion.dev/docs/effects/page-turn",
|
|
326
|
+
backend: "webgpu",
|
|
327
|
+
schema: pageTurnSchema,
|
|
328
|
+
validateParams: (params) => {
|
|
329
|
+
assertEffectParamsObject(params, "Page turn");
|
|
330
|
+
for (const key of [
|
|
331
|
+
"foldDirection",
|
|
332
|
+
"foldRadius",
|
|
333
|
+
"lightDirection",
|
|
334
|
+
"backPageOpacity"
|
|
335
|
+
]) {
|
|
336
|
+
assertOptionalFiniteNumber(params[key], key);
|
|
337
|
+
}
|
|
338
|
+
assertOptionalColor(params.paperColor, "paperColor");
|
|
339
|
+
const r = resolve(params);
|
|
340
|
+
if (r.foldRadius <= 0)
|
|
341
|
+
throw new TypeError('"foldRadius" must be greater than 0');
|
|
342
|
+
validateUnitInterval(r.backPageOpacity, "backPageOpacity");
|
|
343
|
+
if (params.foldPosition !== undefined && (!Array.isArray(params.foldPosition) || params.foldPosition.length !== 2 || !Number.isFinite(params.foldPosition[0]) || !Number.isFinite(params.foldPosition[1]))) {
|
|
344
|
+
throw new TypeError('"foldPosition" must contain two finite numbers');
|
|
345
|
+
}
|
|
346
|
+
if (params.render !== undefined && params.render !== "both" && params.render !== "front" && params.render !== "back") {
|
|
347
|
+
throw new TypeError('"render" must be "both", "front", or "back"');
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
calculateKey: (params) => {
|
|
351
|
+
const r = resolve(params);
|
|
352
|
+
return `page-turn-${r.foldPosition.join(",")}-${r.foldDirection}-${r.foldRadius}-${r.lightDirection}-${r.render}-${r.backPageOpacity}-${r.paperColor}`;
|
|
353
|
+
},
|
|
354
|
+
setup: (target) => {
|
|
355
|
+
const colorCanvas = document.createElement("canvas");
|
|
356
|
+
colorCanvas.width = 1;
|
|
357
|
+
colorCanvas.height = 1;
|
|
358
|
+
const colorCtx = colorCanvas.getContext("2d", { willReadFrequently: true });
|
|
359
|
+
if (!colorCtx)
|
|
360
|
+
throw new Error("Could not create the page turn color context");
|
|
361
|
+
return {
|
|
362
|
+
...setupWebGpuProjection(target, "page turn"),
|
|
363
|
+
colorCtx,
|
|
364
|
+
cachedColor: null,
|
|
365
|
+
cachedRgba: [255, 255, 255, 255]
|
|
366
|
+
};
|
|
367
|
+
},
|
|
368
|
+
apply: ({ source, width, height, params, state, gpuDevice }) => {
|
|
369
|
+
if (!gpuDevice)
|
|
370
|
+
throw new Error("A WebGPU device is required for the page turn effect");
|
|
371
|
+
const r = resolve(params);
|
|
372
|
+
if (state.cachedColor !== r.paperColor) {
|
|
373
|
+
state.cachedColor = r.paperColor;
|
|
374
|
+
state.cachedRgba = parseColorRgba(state.colorCtx, r.paperColor);
|
|
375
|
+
}
|
|
376
|
+
const radians = Math.PI / 180;
|
|
377
|
+
applyWebGpuProjection({
|
|
378
|
+
source,
|
|
379
|
+
width,
|
|
380
|
+
height,
|
|
381
|
+
state,
|
|
382
|
+
device: gpuDevice,
|
|
383
|
+
shader: PAGE_TURN_SHADER,
|
|
384
|
+
uniformData: new Float32Array([
|
|
385
|
+
width,
|
|
386
|
+
height,
|
|
387
|
+
r.foldPosition[0] * width,
|
|
388
|
+
r.foldPosition[1] * height,
|
|
389
|
+
r.foldRadius,
|
|
390
|
+
r.foldDirection % 360 * radians,
|
|
391
|
+
r.lightDirection % 360 * radians,
|
|
392
|
+
r.render === "front" ? 1 : r.render === "back" ? 2 : 0,
|
|
393
|
+
...state.cachedRgba.map((channel) => channel / 255),
|
|
394
|
+
r.backPageOpacity,
|
|
395
|
+
0,
|
|
396
|
+
0,
|
|
397
|
+
0
|
|
398
|
+
])
|
|
399
|
+
});
|
|
400
|
+
},
|
|
401
|
+
cleanup: cleanupWebGpuProjection
|
|
402
|
+
});
|
|
403
|
+
export {
|
|
404
|
+
pageTurn
|
|
405
|
+
};
|