diff --git a/packages/docs/components/TableOfContents/transitions/presentations.tsx b/packages/docs/components/TableOfContents/transitions/presentations.tsx index b70bcb3f151..c0f6eba5d55 100644 --- a/packages/docs/components/TableOfContents/transitions/presentations.tsx +++ b/packages/docs/components/TableOfContents/transitions/presentations.tsx @@ -1,6 +1,8 @@ import { fade } from "@remotion/transitions/fade"; import { flip } from "@remotion/transitions/flip"; import { slide } from "@remotion/transitions/slide"; + +import { clockWipe } from "@remotion/transitions/clock-wipe"; import { wipe } from "@remotion/transitions/wipe"; import React from "react"; import { PresentationPreview } from "../../transitions/previews"; @@ -13,6 +15,9 @@ const row: React.CSSProperties = { justifyContent: "space-between", }; +export const presentationCompositionWidth = 540; +export const presentationCompositionHeight = 280; + export const Presentations: React.FC = () => { return ( @@ -68,6 +73,23 @@ export const Presentations: React.FC = () => { + +
+ +
+ + {"clockWipe()"} + +
Reveal the new scene in a circular movement
+
+
+
diff --git a/packages/docs/components/demos/index.tsx b/packages/docs/components/demos/index.tsx index 29f5653f87d..7bb9c1570e6 100644 --- a/packages/docs/components/demos/index.tsx +++ b/packages/docs/components/demos/index.tsx @@ -7,6 +7,7 @@ import styles from "./styles.module.css"; import type { DemoType } from "./types"; import { circleDemo, + clockWipePresentationDemo, customPresentationDemo, customTimingDemo, ellipseDemo, @@ -57,6 +58,7 @@ const demos: DemoType[] = [ flipPresentationDemo, customPresentationDemo, customTimingDemo, + clockWipePresentationDemo, ]; export const Demo: React.FC<{ diff --git a/packages/docs/components/demos/types.ts b/packages/docs/components/demos/types.ts index 30af4f1c03f..a10652085d6 100644 --- a/packages/docs/components/demos/types.ts +++ b/packages/docs/components/demos/types.ts @@ -1,4 +1,5 @@ import { + ClockWipeDemo, CustomTimingDemo, CustomTransitionDemo, FadeDemo, @@ -614,6 +615,17 @@ export const wipePresentationDemo: DemoType = { ], }; +export const clockWipePresentationDemo: DemoType = { + comp: ClockWipeDemo, + compHeight: 280, + compWidth: 540, + durationInFrames: 60, + fps: 30, + id: "clock-wipe", + autoPlay: true, + options: [], +}; + export const customPresentationDemo: DemoType = { comp: CustomTransitionDemo, compHeight: 280, diff --git a/packages/docs/components/transitions/previews.tsx b/packages/docs/components/transitions/previews.tsx index d49c1c5836b..67885e03cfa 100644 --- a/packages/docs/components/transitions/previews.tsx +++ b/packages/docs/components/transitions/previews.tsx @@ -5,6 +5,7 @@ import type { TransitionTiming, } from "@remotion/transitions"; import { springTiming, TransitionSeries } from "@remotion/transitions"; +import { clockWipe } from "@remotion/transitions/clock-wipe"; import { fade } from "@remotion/transitions/fade"; import type { FlipDirection } from "@remotion/transitions/flip"; import { flip } from "@remotion/transitions/flip"; @@ -15,6 +16,10 @@ import { wipe } from "@remotion/transitions/wipe"; import React, { useEffect, useRef } from "react"; import type { SpringConfig } from "remotion"; import { AbsoluteFill, measureSpring, spring, useVideoConfig } from "remotion"; +import { + presentationCompositionHeight, + presentationCompositionWidth, +} from "../TableOfContents/transitions/presentations"; import { customPresentation } from "./custom-transition"; const SceneA: React.FC = () => { @@ -131,6 +136,17 @@ export const WipeDemo: React.FC<{ ); }; +export const ClockWipeDemo: React.FC<{}> = () => { + const { width, height } = useVideoConfig(); + + return ( + + ); +}; + export const CustomTransitionDemo: React.FC<{}> = () => { const { width, height } = useVideoConfig(); @@ -214,8 +230,8 @@ export const PresentationPreview: React.FC<{ + +A presentation where the exiting slide is wiped out in a circular movement, revealing the next slide underneath it. + + + +## Example + +```tsx twoslash title="ClockWipeTransition.tsx" +import { AbsoluteFill } from "remotion"; + +const Letter: React.FC<{ + children: React.ReactNode; + color: string; +}> = ({ children, color }) => { + return ( + + {children} + + ); +}; +// ---cut--- +import { linearTiming, TransitionSeries } from "@remotion/transitions"; +import { clockWipe } from "@remotion/transitions/clock-wipe"; +import { useVideoConfig } from "remotion"; + +const BasicTransition = () => { + const { width, height } = useVideoConfig(); + + return ( + + + A + + + + B + + + ); +}; +``` + +## API + +Accepts an object composed of `width` and `height`, which should be set to the width and height of the video. + +## See also + +- [Source code for this presentation](https://github.com/remotion-dev/remotion/blob/main/packages/transitions/src/presentations/clock-wipe.tsx) +- [Presentations](/docs/transitions/presentations) diff --git a/packages/docs/sidebars.js b/packages/docs/sidebars.js index c19cb99ef6b..2ae94da42c0 100644 --- a/packages/docs/sidebars.js +++ b/packages/docs/sidebars.js @@ -428,6 +428,7 @@ module.exports = { "transitions/presentations/slide", "transitions/presentations/wipe", "transitions/presentations/flip", + "transitions/presentations/clock-wipe", "transitions/presentations/custom", "transitions/audio-transitions", ], diff --git a/packages/docs/src/data/articles.ts b/packages/docs/src/data/articles.ts index 985ba1d91dd..0d4da693759 100644 --- a/packages/docs/src/data/articles.ts +++ b/packages/docs/src/data/articles.ts @@ -2528,6 +2528,13 @@ export const articles = [ compId: "articles-docs-transitions-index", crumb: null, }, + { + id: "transitions/presentations/clock-wipe", + title: "clockWipe()", + relativePath: "docs/transitions/presentations/clock-wipe.mdx", + compId: "articles-docs-transitions-presentations-clock-wipe", + crumb: "@remotion/transitions - Presentations", + }, { id: "transitions/presentations/custom", title: "Custom presentations", diff --git a/packages/docs/static/generated/articles-docs-transitions-presentations-clock-wipe.png b/packages/docs/static/generated/articles-docs-transitions-presentations-clock-wipe.png new file mode 100644 index 00000000000..833ca556dc0 Binary files /dev/null and b/packages/docs/static/generated/articles-docs-transitions-presentations-clock-wipe.png differ diff --git a/packages/transitions/package.json b/packages/transitions/package.json index 7c49a59326b..1d8b96e0646 100644 --- a/packages/transitions/package.json +++ b/packages/transitions/package.json @@ -22,7 +22,9 @@ "url": "https://github.com/remotion-dev/remotion/issues" }, "dependencies": { - "remotion": "workspace:*" + "remotion": "workspace:*", + "@remotion/shapes": "workspace:*", + "@remotion/paths": "workspace:*" }, "devDependencies": { "@jonny/eslint-config": "3.0.276", @@ -82,6 +84,12 @@ "require": "./dist/cjs/presentations/flip.js", "types": "./dist/presentations/flip.d.ts" }, + "./clock-wipe": { + "module": "./dist/presentations/clock-wipe.js", + "import": "./dist/presentations/clock-wipe.js", + "require": "./dist/cjs/presentations/clock-wipe.js", + "types": "./dist/presentations/clock-wipe.d.ts" + }, "./package.json": "./package.json" }, "typesVersions": { @@ -97,6 +105,9 @@ ], "fade": [ "dist/presentations/fade.d.ts" + ], + "clock-wipe": [ + "dist/presentations/clock-wipe.d.ts" ] } } diff --git a/packages/transitions/rollup.config.js b/packages/transitions/rollup.config.js index 661c129ed80..cf0b9b918e7 100644 --- a/packages/transitions/rollup.config.js +++ b/packages/transitions/rollup.config.js @@ -1,7 +1,7 @@ // rollup.config.js import typescript from '@rollup/plugin-typescript'; -const presentations = ['slide', 'flip', 'wipe', 'fade']; +const presentations = ['slide', 'flip', 'wipe', 'fade', 'clock-wipe']; export default [ { @@ -32,7 +32,14 @@ export default [ sourcemap: false, }, ], - external: ['remotion', 'remotion/no-react', 'react', 'react/jsx-runtime'], + external: [ + 'remotion', + 'remotion/no-react', + 'react', + 'react/jsx-runtime', + '@remotion/paths', + '@remotion/shapes', + ], plugins: [ typescript({ tsconfig: 'tsconfig-cjs.json', diff --git a/packages/transitions/src/presentations/clock-wipe.tsx b/packages/transitions/src/presentations/clock-wipe.tsx new file mode 100644 index 00000000000..3a5e4b54a38 --- /dev/null +++ b/packages/transitions/src/presentations/clock-wipe.tsx @@ -0,0 +1,64 @@ +import {translatePath} from '@remotion/paths'; +import {makePie} from '@remotion/shapes'; +import React, {useMemo, useState} from 'react'; +import {AbsoluteFill, random} from 'remotion'; +import type { + TransitionPresentation, + TransitionPresentationComponentProps, +} from '../types.js'; + +export type ClockWipeProps = { + width: number; + height: number; +}; + +const ClockWipePresentation: React.FC< + TransitionPresentationComponentProps +> = ({children, presentationDirection, presentationProgress, passedProps}) => { + const finishedRadius = + Math.sqrt(passedProps.width ** 2 + passedProps.height ** 2) / 2; + + const {path} = makePie({ + radius: finishedRadius, + progress: presentationProgress, + }); + + const translatedPath = translatePath( + path, + -(finishedRadius * 2 - passedProps.width) / 2, + -(finishedRadius * 2 - passedProps.height) / 2, + ); + + const [clipId] = useState(() => String(random(null))); + const style: React.CSSProperties = useMemo(() => { + return { + width: '100%', + height: '100%', + clipPath: + presentationDirection === 'exiting' ? undefined : `url(#${clipId})`, + }; + }, [clipId, presentationDirection]); + + return ( + + {children} + {presentationDirection === 'exiting' ? null : ( + + + + + + + + + + )} + + ); +}; + +export const clockWipe = ( + props: ClockWipeProps, +): TransitionPresentation => { + return {component: ClockWipePresentation, props: props ?? {}}; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9bbbceaa62..41875683e19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1850,6 +1850,12 @@ importers: packages/transitions: dependencies: + '@remotion/paths': + specifier: workspace:* + version: link:../paths + '@remotion/shapes': + specifier: workspace:* + version: link:../shapes remotion: specifier: workspace:* version: link:../core