@remotion/transitions 4.0.465 → 4.0.467
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/book-flip.js +2 -0
- package/cross-zoom.js +2 -0
- package/crosswarp.js +2 -0
- package/dist/TransitionSeries.js +16 -6
- package/dist/esm/book-flip.mjs +434 -0
- package/dist/esm/cross-zoom.mjs +377 -0
- package/dist/esm/crosswarp.mjs +331 -0
- package/dist/esm/dissolve.mjs +4 -3
- package/dist/esm/dreamy-zoom.mjs +348 -0
- package/dist/esm/film-burn.mjs +443 -0
- package/dist/esm/index.mjs +1020 -209
- package/dist/esm/linear-blur.mjs +343 -0
- package/dist/esm/ripple.mjs +342 -0
- package/dist/esm/swap.mjs +394 -0
- package/dist/esm/zoom-blur.mjs +4 -3
- package/dist/esm/zoom-in-out.mjs +4 -3
- package/dist/html-in-canvas-presentation.js +4 -5
- package/dist/index.d.ts +13 -3
- package/dist/index.js +9 -1
- package/dist/presentations/book-flip.d.ts +14 -0
- package/dist/presentations/book-flip.js +255 -0
- package/dist/presentations/cross-zoom.d.ts +13 -0
- package/dist/presentations/cross-zoom.js +199 -0
- package/dist/presentations/crosswarp.d.ts +11 -0
- package/dist/presentations/crosswarp.js +154 -0
- package/dist/presentations/dreamy-zoom.d.ts +14 -0
- package/dist/presentations/dreamy-zoom.js +169 -0
- package/dist/presentations/film-burn.d.ts +13 -0
- package/dist/presentations/film-burn.js +265 -0
- package/dist/presentations/linear-blur.d.ts +13 -0
- package/dist/presentations/linear-blur.js +164 -0
- package/dist/presentations/ripple.d.ts +14 -0
- package/dist/presentations/ripple.js +164 -0
- package/dist/presentations/swap.d.ts +15 -0
- package/dist/presentations/swap.js +212 -0
- package/dist/types.d.ts +1 -1
- package/dreamy-zoom.js +2 -0
- package/film-burn.js +2 -0
- package/linear-blur.js +2 -0
- package/package.json +80 -8
- package/ripple.js +2 -0
- package/swap.js +2 -0
package/book-flip.js
ADDED
package/cross-zoom.js
ADDED
package/crosswarp.js
ADDED
package/dist/TransitionSeries.js
CHANGED
|
@@ -240,7 +240,9 @@ const TransitionSeriesChildren = ({ children, }) => {
|
|
|
240
240
|
const UppercasePrevPresentation = prevPresentation.component;
|
|
241
241
|
return (jsx_runtime_1.jsx(remotion_1.Sequence
|
|
242
242
|
// eslint-disable-next-line react/no-array-index-key
|
|
243
|
-
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>',
|
|
243
|
+
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>', _remotionInternalDocumentationLink: passedProps.name
|
|
244
|
+
? undefined
|
|
245
|
+
: 'https://www.remotion.dev/docs/transitions/transitionseries', children: jsx_runtime_1.jsx(UppercaseNextPresentation, { passedProps: (_e = nextPresentation.props) !== null && _e !== void 0 ? _e : {}, presentationDirection: "exiting", presentationProgress: nextProgress, presentationDurationInFrames: next.props.timing.getDurationInFrames({ fps }), onElementImage: () => {
|
|
244
246
|
throw new Error('Should not call when exiting');
|
|
245
247
|
}, onUnmount: () => {
|
|
246
248
|
throw new Error('Should not call when exiting');
|
|
@@ -257,7 +259,9 @@ const TransitionSeriesChildren = ({ children, }) => {
|
|
|
257
259
|
const UppercasePrevPresentation = prevPresentation.component;
|
|
258
260
|
return (jsx_runtime_1.jsx(remotion_1.Sequence
|
|
259
261
|
// eslint-disable-next-line react/no-array-index-key
|
|
260
|
-
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>',
|
|
262
|
+
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>', _remotionInternalDocumentationLink: passedProps.name
|
|
263
|
+
? undefined
|
|
264
|
+
: 'https://www.remotion.dev/docs/transitions/transitionseries', children: jsx_runtime_1.jsx(UppercasePrevPresentation, { passedProps: (_h = prevPresentation.props) !== null && _h !== void 0 ? _h : {}, presentationDirection: "entering", presentationProgress: prevProgress, presentationDurationInFrames: prev.props.timing.getDurationInFrames({ fps }), onElementImage: (elementImage, draw) => onNextElementImage(elementImage, prevProgress, draw, i - 1), onUnmount: () => {
|
|
261
265
|
onNextElementImage(null, null, null, i - 1);
|
|
262
266
|
}, bothEnteringAndExiting: false, children: jsx_runtime_1.jsx(context_js_1.WrapInEnteringProgressContext, { presentationProgress: prevProgress, children: child }) }) }, i));
|
|
263
267
|
}
|
|
@@ -266,18 +270,22 @@ const TransitionSeriesChildren = ({ children, }) => {
|
|
|
266
270
|
const UppercaseNextPresentation = nextPresentation.component;
|
|
267
271
|
return (jsx_runtime_1.jsx(remotion_1.Sequence
|
|
268
272
|
// eslint-disable-next-line react/no-array-index-key
|
|
269
|
-
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>',
|
|
273
|
+
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>', _remotionInternalDocumentationLink: passedProps.name
|
|
274
|
+
? undefined
|
|
275
|
+
: 'https://www.remotion.dev/docs/transitions/transitionseries', children: jsx_runtime_1.jsx(UppercaseNextPresentation, { passedProps: (_k = nextPresentation.props) !== null && _k !== void 0 ? _k : {}, presentationDirection: "exiting", presentationProgress: nextProgress, presentationDurationInFrames: next.props.timing.getDurationInFrames({ fps }), onElementImage: (elementImage, draw) => onPrevElementImage(elementImage, nextProgress, draw, i + 1), onUnmount: () => {
|
|
270
276
|
onPrevElementImage(null, null, null, i + 1);
|
|
271
277
|
}, bothEnteringAndExiting: false, children: jsx_runtime_1.jsx(context_js_1.WrapInExitingProgressContext, { presentationProgress: nextProgress, children: child }) }) }, i));
|
|
272
278
|
}
|
|
273
279
|
return (jsx_runtime_1.jsx(remotion_1.Sequence
|
|
274
280
|
// eslint-disable-next-line react/no-array-index-key
|
|
275
|
-
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>',
|
|
281
|
+
, { from: actualStartFrame, durationInFrames: durationInFramesProp, ...passedProps, name: passedProps.name || '<TS.Sequence>', _remotionInternalDocumentationLink: passedProps.name
|
|
282
|
+
? undefined
|
|
283
|
+
: 'https://www.remotion.dev/docs/transitions/transitionseries', children: child }, i));
|
|
276
284
|
});
|
|
277
285
|
// Now render overlay sequences
|
|
278
286
|
const overlayElements = overlayRenders.map((overlayInfo) => {
|
|
279
287
|
const info = overlayInfo;
|
|
280
|
-
return (jsx_runtime_1.jsx(remotion_1.Sequence, { from: Math.round(info.overlayFrom), durationInFrames: info.durationInFrames, name: "<TS.Overlay>", layout: "absolute-fill", ...(info.stack ? { stack: info.stack } : {}), children: info.children }, `overlay-${info.index}`));
|
|
288
|
+
return (jsx_runtime_1.jsx(remotion_1.Sequence, { from: Math.round(info.overlayFrom), durationInFrames: info.durationInFrames, name: "<TS.Overlay>", _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/transitions/transitionseries", layout: "absolute-fill", ...(info.stack ? { stack: info.stack } : {}), children: info.children }, `overlay-${info.index}`));
|
|
281
289
|
});
|
|
282
290
|
return [...(mainChildren || []), ...overlayElements];
|
|
283
291
|
}, [flattedChildren, fps, frame, onPrevElementImage, onNextElementImage]);
|
|
@@ -295,7 +303,9 @@ const TransitionSeries = ({ children, name, layout: passedLayout, ...otherProps
|
|
|
295
303
|
layout !== 'absolute-fill') {
|
|
296
304
|
throw new TypeError(`The "layout" prop of <TransitionSeries /> is not supported anymore in v5. TransitionSeries' must be absolutely positioned.`);
|
|
297
305
|
}
|
|
298
|
-
return (jsx_runtime_1.jsx(remotion_1.Sequence, { name: displayName, layout: layout,
|
|
306
|
+
return (jsx_runtime_1.jsx(remotion_1.Sequence, { name: displayName, layout: layout, _remotionInternalDocumentationLink: name === undefined
|
|
307
|
+
? 'https://www.remotion.dev/docs/transitions/transitionseries'
|
|
308
|
+
: undefined, ...otherProps, children: jsx_runtime_1.jsx(TransitionSeriesChildren, { children: children }) }));
|
|
299
309
|
};
|
|
300
310
|
exports.TransitionSeries = TransitionSeries;
|
|
301
311
|
TransitionSeries.Sequence = SeriesSequence;
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// src/html-in-canvas-presentation.tsx
|
|
2
|
+
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
AbsoluteFill,
|
|
5
|
+
HTML_IN_CANVAS_UNSUPPORTED_MESSAGE,
|
|
6
|
+
HtmlInCanvas,
|
|
7
|
+
Internals,
|
|
8
|
+
useDelayRender
|
|
9
|
+
} from "remotion";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
var HtmlInCanvasPresentation = ({
|
|
12
|
+
children,
|
|
13
|
+
onElementImage,
|
|
14
|
+
onUnmount,
|
|
15
|
+
presentationProgress,
|
|
16
|
+
presentationDirection,
|
|
17
|
+
shader,
|
|
18
|
+
effects,
|
|
19
|
+
passedProps,
|
|
20
|
+
bothEnteringAndExiting
|
|
21
|
+
}) => {
|
|
22
|
+
if (!HtmlInCanvas.isSupported()) {
|
|
23
|
+
throw new Error(HTML_IN_CANVAS_UNSUPPORTED_MESSAGE);
|
|
24
|
+
}
|
|
25
|
+
const canvasRef = useRef(null);
|
|
26
|
+
const canvasSubtreeStyle = useMemo(() => {
|
|
27
|
+
return {
|
|
28
|
+
width: "100%",
|
|
29
|
+
height: "100%",
|
|
30
|
+
position: "absolute",
|
|
31
|
+
top: 0,
|
|
32
|
+
left: 0,
|
|
33
|
+
right: 0,
|
|
34
|
+
bottom: 0
|
|
35
|
+
};
|
|
36
|
+
}, []);
|
|
37
|
+
const [offscreenCanvas] = useState(() => new OffscreenCanvas(1, 1));
|
|
38
|
+
const passedPropsRef = useRef(passedProps);
|
|
39
|
+
passedPropsRef.current = passedProps;
|
|
40
|
+
const memoizedEffects = Internals.useMemoizedEffects({
|
|
41
|
+
effects: effects ?? [],
|
|
42
|
+
overrideId: null
|
|
43
|
+
});
|
|
44
|
+
const effectsRef = useRef(memoizedEffects);
|
|
45
|
+
effectsRef.current = memoizedEffects;
|
|
46
|
+
const [instance] = useState(() => shader(offscreenCanvas));
|
|
47
|
+
useLayoutEffect(() => {
|
|
48
|
+
return () => {
|
|
49
|
+
instance.cleanup();
|
|
50
|
+
};
|
|
51
|
+
}, [offscreenCanvas, instance]);
|
|
52
|
+
const chainState = Internals.useEffectChainState();
|
|
53
|
+
const { delayRender, continueRender } = useDelayRender();
|
|
54
|
+
const draw = useCallback(async (prevImage, nextImage, progress) => {
|
|
55
|
+
if (!canvasRef.current) {
|
|
56
|
+
throw new Error("Canvas not found");
|
|
57
|
+
}
|
|
58
|
+
const handle = delayRender("onPaint");
|
|
59
|
+
if (!prevImage && !nextImage) {
|
|
60
|
+
continueRender(handle);
|
|
61
|
+
instance.clear();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const width = prevImage?.width ?? nextImage?.width ?? 0;
|
|
65
|
+
const height = prevImage?.height ?? nextImage?.height ?? 0;
|
|
66
|
+
if (width === 0 || height === 0) {
|
|
67
|
+
continueRender(handle);
|
|
68
|
+
instance.clear();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
offscreenCanvas.width = width;
|
|
72
|
+
offscreenCanvas.height = height;
|
|
73
|
+
instance.draw({
|
|
74
|
+
prevImage,
|
|
75
|
+
nextImage,
|
|
76
|
+
width,
|
|
77
|
+
height,
|
|
78
|
+
time: progress,
|
|
79
|
+
passedProps: passedPropsRef.current
|
|
80
|
+
});
|
|
81
|
+
await Internals.runEffectChain({
|
|
82
|
+
state: chainState.get(width, height),
|
|
83
|
+
source: offscreenCanvas,
|
|
84
|
+
effects: effectsRef.current ?? [],
|
|
85
|
+
width,
|
|
86
|
+
height,
|
|
87
|
+
output: canvasRef.current
|
|
88
|
+
});
|
|
89
|
+
continueRender(handle);
|
|
90
|
+
}, [chainState, instance, offscreenCanvas, continueRender, delayRender]);
|
|
91
|
+
const passThrough = bothEnteringAndExiting && presentationDirection === "exiting";
|
|
92
|
+
useLayoutEffect(() => {
|
|
93
|
+
if (passThrough) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const canvas = canvasRef.current;
|
|
97
|
+
if (!canvas) {
|
|
98
|
+
throw new Error("Canvas not found");
|
|
99
|
+
}
|
|
100
|
+
canvas.layoutSubtree = true;
|
|
101
|
+
const onPaint = () => {
|
|
102
|
+
const firstChild = canvas.firstChild;
|
|
103
|
+
if (!firstChild) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const elementImage = canvas.captureElementImage(firstChild);
|
|
107
|
+
onElementImage(elementImage, draw);
|
|
108
|
+
};
|
|
109
|
+
canvas.addEventListener("paint", onPaint);
|
|
110
|
+
return () => {
|
|
111
|
+
canvas.removeEventListener("paint", onPaint);
|
|
112
|
+
};
|
|
113
|
+
}, [onElementImage, presentationDirection, draw, passThrough]);
|
|
114
|
+
useLayoutEffect(() => {
|
|
115
|
+
if (passThrough) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const canvas = canvasRef.current;
|
|
119
|
+
if (!canvas) {
|
|
120
|
+
throw new Error("Canvas not found");
|
|
121
|
+
}
|
|
122
|
+
canvas.requestPaint?.();
|
|
123
|
+
}, [presentationProgress, passThrough, memoizedEffects]);
|
|
124
|
+
useLayoutEffect(() => {
|
|
125
|
+
if (passThrough) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
return () => {
|
|
129
|
+
onUnmount();
|
|
130
|
+
};
|
|
131
|
+
}, [onUnmount, passThrough]);
|
|
132
|
+
useLayoutEffect(() => {
|
|
133
|
+
if (passThrough) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const canvas = canvasRef.current;
|
|
137
|
+
if (!canvas) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
141
|
+
canvas.width = entry.devicePixelContentBoxSize[0].inlineSize;
|
|
142
|
+
canvas.height = entry.devicePixelContentBoxSize[0].blockSize;
|
|
143
|
+
});
|
|
144
|
+
observer.observe(canvas, { box: "device-pixel-content-box" });
|
|
145
|
+
}, [passThrough]);
|
|
146
|
+
if (passThrough) {
|
|
147
|
+
return children;
|
|
148
|
+
}
|
|
149
|
+
return /* @__PURE__ */ jsx(AbsoluteFill, {
|
|
150
|
+
children: /* @__PURE__ */ jsx("canvas", {
|
|
151
|
+
ref: canvasRef,
|
|
152
|
+
style: canvasSubtreeStyle,
|
|
153
|
+
children
|
|
154
|
+
})
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
var makeHtmlInCanvasPresentation = (shader) => {
|
|
158
|
+
const CompWithShader = (props) => {
|
|
159
|
+
const { passedProps, ...otherProps } = props;
|
|
160
|
+
const { effects, ...restPassedProps } = props.passedProps;
|
|
161
|
+
return /* @__PURE__ */ jsx(HtmlInCanvasPresentation, {
|
|
162
|
+
shader,
|
|
163
|
+
passedProps: restPassedProps,
|
|
164
|
+
effects,
|
|
165
|
+
...otherProps
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
return (props) => {
|
|
169
|
+
return {
|
|
170
|
+
component: CompWithShader,
|
|
171
|
+
props
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/presentations/book-flip.tsx
|
|
177
|
+
var DIRECTION_FROM_LEFT = 0;
|
|
178
|
+
var DIRECTION_FROM_RIGHT = 1;
|
|
179
|
+
var DIRECTION_FROM_TOP = 2;
|
|
180
|
+
var DIRECTION_FROM_BOTTOM = 3;
|
|
181
|
+
var DEFAULT_DIRECTION = "from-right";
|
|
182
|
+
var VERTEX_SHADER = `#version 300 es
|
|
183
|
+
in vec2 a_pos;
|
|
184
|
+
out vec2 v_uv;
|
|
185
|
+
void main() {
|
|
186
|
+
v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5);
|
|
187
|
+
gl_Position = vec4(a_pos, 0.0, 1.0);
|
|
188
|
+
}`;
|
|
189
|
+
var FRAGMENT_SHADER = `#version 300 es
|
|
190
|
+
precision highp float;
|
|
191
|
+
|
|
192
|
+
uniform sampler2D u_prev;
|
|
193
|
+
uniform sampler2D u_next;
|
|
194
|
+
uniform float u_time;
|
|
195
|
+
uniform float u_direction;
|
|
196
|
+
|
|
197
|
+
in vec2 v_uv;
|
|
198
|
+
out vec4 outColor;
|
|
199
|
+
|
|
200
|
+
const float EPSILON = 0.0001;
|
|
201
|
+
|
|
202
|
+
float avoidZero(float value) {
|
|
203
|
+
if (abs(value) < EPSILON) {
|
|
204
|
+
return value < 0.0 ? -EPSILON : EPSILON;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
vec2 skewRight(vec2 p, float progress) {
|
|
211
|
+
float skewX = (p.x - progress) / avoidZero(0.5 - progress) * 0.5;
|
|
212
|
+
float skewY =
|
|
213
|
+
(p.y - 0.5) /
|
|
214
|
+
avoidZero(0.5 + progress * (p.x - 0.5) / 0.5) *
|
|
215
|
+
0.5 +
|
|
216
|
+
0.5;
|
|
217
|
+
return vec2(skewX, skewY);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
vec2 skewLeft(vec2 p, float progress) {
|
|
221
|
+
float skewX = (p.x - 0.5) / avoidZero(progress - 0.5) * 0.5 + 0.5;
|
|
222
|
+
float skewY =
|
|
223
|
+
(p.y - 0.5) /
|
|
224
|
+
avoidZero(0.5 + (1.0 - progress) * (0.5 - p.x) / 0.5) *
|
|
225
|
+
0.5 +
|
|
226
|
+
0.5;
|
|
227
|
+
return vec2(skewX, skewY);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
vec4 addShade(float progress) {
|
|
231
|
+
float shadeVal = max(0.7, abs(progress - 0.5) * 2.0);
|
|
232
|
+
return vec4(vec3(shadeVal), 1.0);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
vec2 toCanonicalUv(vec2 p) {
|
|
236
|
+
if (u_direction < 0.5) {
|
|
237
|
+
return p;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (u_direction < 1.5) {
|
|
241
|
+
return vec2(1.0 - p.x, p.y);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (u_direction < 2.5) {
|
|
245
|
+
return vec2(p.y, 1.0 - p.x);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return vec2(1.0 - p.y, p.x);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
vec2 fromCanonicalUv(vec2 p) {
|
|
252
|
+
if (u_direction < 0.5) {
|
|
253
|
+
return p;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (u_direction < 1.5) {
|
|
257
|
+
return vec2(1.0 - p.x, p.y);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (u_direction < 2.5) {
|
|
261
|
+
return vec2(1.0 - p.y, p.x);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return vec2(p.y, 1.0 - p.x);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
vec4 samplePrev(vec2 p) {
|
|
268
|
+
return texture(u_prev, fromCanonicalUv(p));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
vec4 sampleNext(vec2 p) {
|
|
272
|
+
return texture(u_next, fromCanonicalUv(p));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
vec4 transition(vec2 p, float progress) {
|
|
276
|
+
float pr = step(1.0 - progress, p.x);
|
|
277
|
+
|
|
278
|
+
if (p.x < 0.5) {
|
|
279
|
+
return mix(
|
|
280
|
+
samplePrev(p),
|
|
281
|
+
sampleNext(skewLeft(p, progress)) * addShade(progress),
|
|
282
|
+
pr
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return mix(
|
|
287
|
+
samplePrev(skewRight(p, progress)) * addShade(progress),
|
|
288
|
+
sampleNext(p),
|
|
289
|
+
pr
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
void main() {
|
|
294
|
+
vec2 p = toCanonicalUv(v_uv);
|
|
295
|
+
float progress = 1.0 - u_time;
|
|
296
|
+
outColor = transition(p, progress);
|
|
297
|
+
}`;
|
|
298
|
+
var compileShader = (gl, source, type) => {
|
|
299
|
+
const shader = gl.createShader(type);
|
|
300
|
+
if (!shader) {
|
|
301
|
+
throw new Error("Failed to create shader");
|
|
302
|
+
}
|
|
303
|
+
gl.shaderSource(shader, source);
|
|
304
|
+
gl.compileShader(shader);
|
|
305
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
306
|
+
const log = gl.getShaderInfoLog(shader);
|
|
307
|
+
gl.deleteShader(shader);
|
|
308
|
+
throw new Error(`Failed to compile shader: ${log}`);
|
|
309
|
+
}
|
|
310
|
+
return shader;
|
|
311
|
+
};
|
|
312
|
+
var createProgram = (gl) => {
|
|
313
|
+
const program = gl.createProgram();
|
|
314
|
+
if (!program) {
|
|
315
|
+
throw new Error("Failed to create WebGL program");
|
|
316
|
+
}
|
|
317
|
+
const vs = compileShader(gl, VERTEX_SHADER, gl.VERTEX_SHADER);
|
|
318
|
+
const fs = compileShader(gl, FRAGMENT_SHADER, gl.FRAGMENT_SHADER);
|
|
319
|
+
gl.attachShader(program, vs);
|
|
320
|
+
gl.attachShader(program, fs);
|
|
321
|
+
gl.linkProgram(program);
|
|
322
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
323
|
+
const log = gl.getProgramInfoLog(program);
|
|
324
|
+
gl.deleteProgram(program);
|
|
325
|
+
throw new Error(`Failed to link program: ${log}`);
|
|
326
|
+
}
|
|
327
|
+
return program;
|
|
328
|
+
};
|
|
329
|
+
var createTexture = (gl) => {
|
|
330
|
+
const tex = gl.createTexture();
|
|
331
|
+
if (!tex) {
|
|
332
|
+
throw new Error("Failed to create texture");
|
|
333
|
+
}
|
|
334
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
335
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
336
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
337
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
338
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
339
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));
|
|
340
|
+
return tex;
|
|
341
|
+
};
|
|
342
|
+
var getDirectionConstant = (direction) => {
|
|
343
|
+
switch (direction) {
|
|
344
|
+
case "from-left":
|
|
345
|
+
return DIRECTION_FROM_LEFT;
|
|
346
|
+
case "from-right":
|
|
347
|
+
return DIRECTION_FROM_RIGHT;
|
|
348
|
+
case "from-top":
|
|
349
|
+
return DIRECTION_FROM_TOP;
|
|
350
|
+
case "from-bottom":
|
|
351
|
+
return DIRECTION_FROM_BOTTOM;
|
|
352
|
+
default:
|
|
353
|
+
return DIRECTION_FROM_RIGHT;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
var bookFlipShader = (canvas) => {
|
|
357
|
+
const gl = canvas.getContext("webgl2", { premultipliedAlpha: true });
|
|
358
|
+
if (!gl) {
|
|
359
|
+
throw new Error("Failed to create WebGL2 context");
|
|
360
|
+
}
|
|
361
|
+
const program = createProgram(gl);
|
|
362
|
+
const prevTex = createTexture(gl);
|
|
363
|
+
const nextTex = createTexture(gl);
|
|
364
|
+
const vao = gl.createVertexArray();
|
|
365
|
+
gl.bindVertexArray(vao);
|
|
366
|
+
const buffer = gl.createBuffer();
|
|
367
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
368
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
|
369
|
+
const aPos = gl.getAttribLocation(program, "a_pos");
|
|
370
|
+
gl.enableVertexAttribArray(aPos);
|
|
371
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
|
|
372
|
+
const uTime = gl.getUniformLocation(program, "u_time");
|
|
373
|
+
const uPrev = gl.getUniformLocation(program, "u_prev");
|
|
374
|
+
const uNext = gl.getUniformLocation(program, "u_next");
|
|
375
|
+
const uDirection = gl.getUniformLocation(program, "u_direction");
|
|
376
|
+
const cleanup = () => {
|
|
377
|
+
gl.deleteProgram(program);
|
|
378
|
+
gl.deleteTexture(prevTex);
|
|
379
|
+
gl.deleteTexture(nextTex);
|
|
380
|
+
};
|
|
381
|
+
const clear = () => {
|
|
382
|
+
gl.clearColor(0, 0, 0, 0);
|
|
383
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
384
|
+
};
|
|
385
|
+
const draw = ({
|
|
386
|
+
prevImage,
|
|
387
|
+
nextImage,
|
|
388
|
+
width,
|
|
389
|
+
height,
|
|
390
|
+
time,
|
|
391
|
+
passedProps
|
|
392
|
+
}) => {
|
|
393
|
+
const { direction = DEFAULT_DIRECTION } = passedProps;
|
|
394
|
+
if (!prevImage && !nextImage) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (prevImage && (prevImage.width === 0 || prevImage.height === 0)) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (nextImage && (nextImage.width === 0 || nextImage.height === 0)) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const effectiveTime = !prevImage ? 0 : !nextImage ? 1 : time;
|
|
404
|
+
gl.viewport(0, 0, width, height);
|
|
405
|
+
gl.clearColor(0, 0, 0, 0);
|
|
406
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
407
|
+
gl.useProgram(program);
|
|
408
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
409
|
+
gl.bindTexture(gl.TEXTURE_2D, prevTex);
|
|
410
|
+
if (prevImage) {
|
|
411
|
+
gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
|
|
412
|
+
}
|
|
413
|
+
gl.uniform1i(uPrev, 0);
|
|
414
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
415
|
+
gl.bindTexture(gl.TEXTURE_2D, nextTex);
|
|
416
|
+
if (nextImage) {
|
|
417
|
+
gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
|
|
418
|
+
}
|
|
419
|
+
gl.uniform1i(uNext, 1);
|
|
420
|
+
gl.uniform1f(uTime, effectiveTime);
|
|
421
|
+
gl.uniform1f(uDirection, getDirectionConstant(direction));
|
|
422
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
423
|
+
};
|
|
424
|
+
return {
|
|
425
|
+
clear,
|
|
426
|
+
cleanup,
|
|
427
|
+
draw
|
|
428
|
+
};
|
|
429
|
+
};
|
|
430
|
+
var bookFlip = makeHtmlInCanvasPresentation(bookFlipShader);
|
|
431
|
+
export {
|
|
432
|
+
bookFlipShader,
|
|
433
|
+
bookFlip
|
|
434
|
+
};
|