@revideo/create 0.5.11-alpha.1102 → 0.5.11-alpha.1104

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.
Files changed (185) hide show
  1. package/examples/README.md +43 -0
  2. package/examples/avatar-with-background/package.json +27 -0
  3. package/examples/avatar-with-background/src/project.meta +31 -0
  4. package/examples/avatar-with-background/src/project.ts +6 -0
  5. package/examples/avatar-with-background/src/render.ts +14 -0
  6. package/examples/avatar-with-background/src/revideo.d.ts +1 -0
  7. package/examples/avatar-with-background/src/scenes/example.meta +5 -0
  8. package/examples/avatar-with-background/src/scenes/example.tsx +28 -0
  9. package/examples/avatar-with-background/tsconfig.json +9 -0
  10. package/examples/avatar-with-background/vite.config.ts +8 -0
  11. package/examples/default/README.md +19 -0
  12. package/examples/default/package.json +20 -0
  13. package/examples/default/src/project.tsx +56 -0
  14. package/examples/default/src/render.ts +15 -0
  15. package/examples/default/tsconfig.json +10 -0
  16. package/examples/github-stars-celebration/package-lock.json +3833 -0
  17. package/examples/github-stars-celebration/package.json +24 -0
  18. package/examples/github-stars-celebration/src/global.css +1 -0
  19. package/examples/github-stars-celebration/src/project.meta +28 -0
  20. package/examples/github-stars-celebration/src/project.ts +8 -0
  21. package/examples/github-stars-celebration/src/render.ts +15 -0
  22. package/examples/github-stars-celebration/src/revideo.d.ts +1 -0
  23. package/examples/github-stars-celebration/src/scenes/example.meta +5 -0
  24. package/examples/github-stars-celebration/src/scenes/example.tsx +51 -0
  25. package/examples/github-stars-celebration/tsconfig.json +9 -0
  26. package/examples/github-stars-celebration/vite.config.ts +8 -0
  27. package/examples/google-cloud-run-parallelized/README.md +127 -0
  28. package/examples/google-cloud-run-parallelized/render-orchestrator/Dockerfile +56 -0
  29. package/examples/google-cloud-run-parallelized/render-orchestrator/package.json +22 -0
  30. package/examples/google-cloud-run-parallelized/render-orchestrator/src/index.ts +72 -0
  31. package/examples/google-cloud-run-parallelized/render-orchestrator/src/revideo.d.ts +1 -0
  32. package/examples/google-cloud-run-parallelized/render-orchestrator/tsconfig.json +10 -0
  33. package/examples/google-cloud-run-parallelized/render-worker/.gcloudignore +17 -0
  34. package/examples/google-cloud-run-parallelized/render-worker/.puppeteerrc.cjs +9 -0
  35. package/examples/google-cloud-run-parallelized/render-worker/package.json +30 -0
  36. package/examples/google-cloud-run-parallelized/render-worker/src/index.ts +45 -0
  37. package/examples/google-cloud-run-parallelized/render-worker/src/project.meta +31 -0
  38. package/examples/google-cloud-run-parallelized/render-worker/src/project.ts +6 -0
  39. package/examples/google-cloud-run-parallelized/render-worker/src/render.ts +14 -0
  40. package/examples/google-cloud-run-parallelized/render-worker/src/revideo.d.ts +1 -0
  41. package/examples/google-cloud-run-parallelized/render-worker/src/scenes/example.tsx +30 -0
  42. package/examples/google-cloud-run-parallelized/render-worker/tsconfig.json +13 -0
  43. package/examples/google-cloud-run-parallelized/render-worker/vite.config.ts +9 -0
  44. package/examples/logo.svg +6 -0
  45. package/examples/logo_dark.svg +6 -0
  46. package/examples/marketing-templates/README.md +10 -0
  47. package/examples/marketing-templates/marketing-template/package.json +24 -0
  48. package/examples/marketing-templates/marketing-template/src/globals.css +0 -0
  49. package/examples/marketing-templates/marketing-template/src/project.meta +28 -0
  50. package/examples/marketing-templates/marketing-template/src/project.ts +9 -0
  51. package/examples/marketing-templates/marketing-template/src/render.ts +15 -0
  52. package/examples/marketing-templates/marketing-template/src/revideo.d.ts +1 -0
  53. package/examples/marketing-templates/marketing-template/src/scenes/example.meta +5 -0
  54. package/examples/marketing-templates/marketing-template/src/scenes/example.tsx +67 -0
  55. package/examples/marketing-templates/marketing-template/tsconfig.json +9 -0
  56. package/examples/marketing-templates/marketing-template/vite.config.ts +9 -0
  57. package/examples/marketing-templates/multiple-videos-in-one/package.json +24 -0
  58. package/examples/marketing-templates/multiple-videos-in-one/src/project.meta +28 -0
  59. package/examples/marketing-templates/multiple-videos-in-one/src/project.ts +9 -0
  60. package/examples/marketing-templates/multiple-videos-in-one/src/render.ts +15 -0
  61. package/examples/marketing-templates/multiple-videos-in-one/src/revideo.d.ts +1 -0
  62. package/examples/marketing-templates/multiple-videos-in-one/src/scenes/example.meta +5 -0
  63. package/examples/marketing-templates/multiple-videos-in-one/src/scenes/example.tsx +122 -0
  64. package/examples/marketing-templates/multiple-videos-in-one/tsconfig.json +9 -0
  65. package/examples/marketing-templates/multiple-videos-in-one/vite.config.ts +9 -0
  66. package/examples/minimal-drag-drop/README.md +29 -0
  67. package/examples/minimal-drag-drop/next/app/api/render/route.ts +22 -0
  68. package/examples/minimal-drag-drop/next/app/globals.css +3 -0
  69. package/examples/minimal-drag-drop/next/app/layout.tsx +25 -0
  70. package/examples/minimal-drag-drop/next/app/page.tsx +277 -0
  71. package/examples/minimal-drag-drop/next/next-env.d.ts +5 -0
  72. package/examples/minimal-drag-drop/next/next.config.mjs +4 -0
  73. package/examples/minimal-drag-drop/next/package-lock.json +5577 -0
  74. package/examples/minimal-drag-drop/next/package.json +35 -0
  75. package/examples/minimal-drag-drop/next/postcss.config.js +6 -0
  76. package/examples/minimal-drag-drop/next/public/favicon.ico +0 -0
  77. package/examples/minimal-drag-drop/next/public/next.svg +1 -0
  78. package/examples/minimal-drag-drop/next/public/vercel.svg +1 -0
  79. package/examples/minimal-drag-drop/next/tailwind.config.ts +30 -0
  80. package/examples/minimal-drag-drop/next/tsconfig.json +26 -0
  81. package/examples/minimal-drag-drop/next/utils/parse.ts +35 -0
  82. package/examples/minimal-drag-drop/revideo/package-lock.json +3771 -0
  83. package/examples/minimal-drag-drop/revideo/package.json +24 -0
  84. package/examples/minimal-drag-drop/revideo/src/global.css +1 -0
  85. package/examples/minimal-drag-drop/revideo/src/project.meta +28 -0
  86. package/examples/minimal-drag-drop/revideo/src/project.ts +9 -0
  87. package/examples/minimal-drag-drop/revideo/src/render.ts +15 -0
  88. package/examples/minimal-drag-drop/revideo/src/revideo.d.ts +1 -0
  89. package/examples/minimal-drag-drop/revideo/src/scenes/example.meta +5 -0
  90. package/examples/minimal-drag-drop/revideo/src/scenes/example.tsx +44 -0
  91. package/examples/minimal-drag-drop/revideo/tsconfig.json +9 -0
  92. package/examples/minimal-drag-drop/revideo/vite.config.ts +6 -0
  93. package/examples/parallelized-aws-lambda/.dockerignore +3 -0
  94. package/examples/parallelized-aws-lambda/Dockerfile +21 -0
  95. package/examples/parallelized-aws-lambda/Dockerfile.base +64 -0
  96. package/examples/parallelized-aws-lambda/README.md +197 -0
  97. package/examples/parallelized-aws-lambda/revideo-project/.puppeteerrc.cjs +9 -0
  98. package/examples/parallelized-aws-lambda/revideo-project/package-lock.json +4133 -0
  99. package/examples/parallelized-aws-lambda/revideo-project/package.json +28 -0
  100. package/examples/parallelized-aws-lambda/revideo-project/src/lambda.ts +157 -0
  101. package/examples/parallelized-aws-lambda/revideo-project/src/project.meta +28 -0
  102. package/examples/parallelized-aws-lambda/revideo-project/src/project.ts +7 -0
  103. package/examples/parallelized-aws-lambda/revideo-project/src/render.ts +17 -0
  104. package/examples/parallelized-aws-lambda/revideo-project/src/revideo.d.ts +1 -0
  105. package/examples/parallelized-aws-lambda/revideo-project/src/scenes/example.meta +5 -0
  106. package/examples/parallelized-aws-lambda/revideo-project/src/scenes/example.tsx +30 -0
  107. package/examples/parallelized-aws-lambda/revideo-project/tsconfig.json +10 -0
  108. package/examples/parallelized-aws-lambda/revideo-project/vite.config.ts +9 -0
  109. package/examples/reddit-post-video/README.md +84 -0
  110. package/examples/reddit-post-video/package-lock.json +2941 -0
  111. package/examples/reddit-post-video/package.json +27 -0
  112. package/examples/reddit-post-video/src/global.css +1 -0
  113. package/examples/reddit-post-video/src/metadata.json +576 -0
  114. package/examples/reddit-post-video/src/project.meta +31 -0
  115. package/examples/reddit-post-video/src/project.ts +9 -0
  116. package/examples/reddit-post-video/src/render.ts +157 -0
  117. package/examples/reddit-post-video/src/revideo.d.ts +1 -0
  118. package/examples/reddit-post-video/src/scenes/example.meta +5 -0
  119. package/examples/reddit-post-video/src/scenes/example.tsx +74 -0
  120. package/examples/reddit-post-video/tsconfig.json +9 -0
  121. package/examples/reddit-post-video/vite.config.ts +6 -0
  122. package/examples/rive-explanation-video/README.md +9 -0
  123. package/examples/rive-explanation-video/package.json +25 -0
  124. package/examples/rive-explanation-video/src/global.css +1 -0
  125. package/examples/rive-explanation-video/src/project.meta +31 -0
  126. package/examples/rive-explanation-video/src/project.ts +8 -0
  127. package/examples/rive-explanation-video/src/render.ts +15 -0
  128. package/examples/rive-explanation-video/src/revideo.d.ts +1 -0
  129. package/examples/rive-explanation-video/src/scenes/example.meta +5 -0
  130. package/examples/rive-explanation-video/src/scenes/example.tsx +218 -0
  131. package/examples/rive-explanation-video/tsconfig.json +9 -0
  132. package/examples/rive-explanation-video/vite.config.ts +8 -0
  133. package/examples/saas-template/.prettierrc +9 -0
  134. package/examples/saas-template/README.md +26 -0
  135. package/examples/saas-template/app/actions.tsx +114 -0
  136. package/examples/saas-template/app/api/render/route.ts +23 -0
  137. package/examples/saas-template/app/globals.css +3 -0
  138. package/examples/saas-template/app/layout.tsx +25 -0
  139. package/examples/saas-template/app/page.tsx +204 -0
  140. package/examples/saas-template/next.config.mjs +4 -0
  141. package/examples/saas-template/package.json +40 -0
  142. package/examples/saas-template/postcss.config.js +6 -0
  143. package/examples/saas-template/revideo/global.css +1 -0
  144. package/examples/saas-template/revideo/project.ts +9 -0
  145. package/examples/saas-template/revideo/scene.tsx +179 -0
  146. package/examples/saas-template/tailwind.config.ts +30 -0
  147. package/examples/saas-template/tsconfig.json +27 -0
  148. package/examples/saas-template/utils/parse.ts +35 -0
  149. package/examples/stitching-videos/README.md +7 -0
  150. package/examples/stitching-videos/package.json +23 -0
  151. package/examples/stitching-videos/src/project.meta +28 -0
  152. package/examples/stitching-videos/src/project.ts +20 -0
  153. package/examples/stitching-videos/src/render.ts +27 -0
  154. package/examples/stitching-videos/src/revideo.d.ts +1 -0
  155. package/examples/stitching-videos/src/scenes/example.tsx +30 -0
  156. package/examples/stitching-videos/tsconfig.json +9 -0
  157. package/examples/stitching-videos/vite.config.ts +8 -0
  158. package/examples/three-js-example/README.md +8 -0
  159. package/examples/three-js-example/package-lock.json +2753 -0
  160. package/examples/three-js-example/package.json +25 -0
  161. package/examples/three-js-example/src/components/Three.ts +166 -0
  162. package/examples/three-js-example/src/global.css +1 -0
  163. package/examples/three-js-example/src/project.meta +31 -0
  164. package/examples/three-js-example/src/project.ts +8 -0
  165. package/examples/three-js-example/src/render.ts +15 -0
  166. package/examples/three-js-example/src/revideo.d.ts +1 -0
  167. package/examples/three-js-example/src/scenes/basic3D.meta +5 -0
  168. package/examples/three-js-example/src/scenes/basic3D.tsx +89 -0
  169. package/examples/three-js-example/tsconfig.json +9 -0
  170. package/examples/three-js-example/vite.config.ts +6 -0
  171. package/examples/youtube-shorts/README.md +65 -0
  172. package/examples/youtube-shorts/package-lock.json +3881 -0
  173. package/examples/youtube-shorts/package.json +30 -0
  174. package/examples/youtube-shorts/src/get-assets.ts +34 -0
  175. package/examples/youtube-shorts/src/global.css +3 -0
  176. package/examples/youtube-shorts/src/metadata.json +635 -0
  177. package/examples/youtube-shorts/src/project.meta +28 -0
  178. package/examples/youtube-shorts/src/project.ts +9 -0
  179. package/examples/youtube-shorts/src/render.ts +12 -0
  180. package/examples/youtube-shorts/src/revideo.d.ts +1 -0
  181. package/examples/youtube-shorts/src/scenes/example.tsx +224 -0
  182. package/examples/youtube-shorts/src/utils.ts +123 -0
  183. package/examples/youtube-shorts/tsconfig.json +9 -0
  184. package/examples/youtube-shorts/vite.config.ts +8 -0
  185. package/package.json +9 -9
@@ -0,0 +1,114 @@
1
+ 'use server';
2
+
3
+ import pLimit from 'p-limit';
4
+
5
+ const PER_PAGE = 30;
6
+
7
+ interface ReturnType {
8
+ stargazerTimes: number[];
9
+ status: 'success' | 'rate-limit' | 'error';
10
+ }
11
+
12
+ async function getStargazerTimesForPage(
13
+ repo: `${string}/${string}`,
14
+ page: number,
15
+ headers: HeadersInit,
16
+ ): Promise<ReturnType> {
17
+ const response = await fetch(
18
+ `https://api.github.com/repos/${repo}/stargazers?page=${page}&per_page=${PER_PAGE}`,
19
+ {
20
+ headers: {
21
+ // eslint-disable-next-line @typescript-eslint/naming-convention
22
+ Accept: 'application/vnd.github.v3.star+json',
23
+ ...headers,
24
+ },
25
+ },
26
+ );
27
+
28
+ if (response.status === 403) {
29
+ return {stargazerTimes: [], status: 'rate-limit'};
30
+ }
31
+
32
+ if (!response.ok) {
33
+ return {stargazerTimes: [], status: 'error'};
34
+ }
35
+
36
+ const data = await response.json();
37
+ const dates: Date[] = data.map((stargazer: any) => new Date(stargazer.starred_at));
38
+ const msTimes = dates.map((date) => date.getTime());
39
+
40
+ return {
41
+ stargazerTimes: msTimes,
42
+ status: 'success',
43
+ };
44
+ }
45
+
46
+ const limit = pLimit(10);
47
+
48
+ async function getTimes(
49
+ repo: `${string}/${string}`,
50
+ totalPages: number,
51
+ headers: HeadersInit,
52
+ ): Promise<ReturnType> {
53
+ const stargazerPromises: Promise<ReturnType>[] = [];
54
+
55
+ // Fetch all pages in parallel
56
+ for (let page = 1; page <= totalPages; page++) {
57
+ stargazerPromises.push(limit(() => getStargazerTimesForPage(repo, page, headers)));
58
+ }
59
+
60
+ const stargazerTimes = await Promise.all(stargazerPromises);
61
+
62
+ // In case of failure, return the first error
63
+ const objectsThatFailed = stargazerTimes.filter(({status}) => status !== 'success');
64
+ if (stargazerTimes.some(({status}) => status !== 'success')) {
65
+ return {
66
+ stargazerTimes: [],
67
+ status: objectsThatFailed[0].status,
68
+ };
69
+ }
70
+
71
+ const stargazerMs = stargazerTimes.map(({stargazerTimes}) => stargazerTimes).flat();
72
+ const sortedMs = stargazerMs.sort((a, b) => a - b);
73
+
74
+ const firstMs = sortedMs[0];
75
+ const relativeMs = sortedMs.map((ms) => ms - firstMs);
76
+
77
+ return {
78
+ stargazerTimes: relativeMs,
79
+ status: 'success',
80
+ };
81
+ }
82
+
83
+ export async function getGithubRepositoryInfo(
84
+ repoName: `${string}/${string}`,
85
+ key?: string,
86
+ ): Promise<ReturnType & {repoImage: string}> {
87
+ const headers: HeadersInit = {};
88
+
89
+ if (key) {
90
+ headers.Authorization = `token ${key}`;
91
+ }
92
+
93
+ const response = await fetch(`https://api.github.com/repos/${repoName}`, {
94
+ headers,
95
+ });
96
+
97
+ if (response.status === 403) {
98
+ return {stargazerTimes: [], repoImage: '', status: 'rate-limit'};
99
+ }
100
+
101
+ if (!response.ok) {
102
+ return {stargazerTimes: [], repoImage: '', status: 'error'};
103
+ }
104
+
105
+ const responseParsed = await response.json();
106
+ const pages = Math.ceil(responseParsed.stargazers_count / PER_PAGE);
107
+ const info = await getTimes(repoName, pages, headers);
108
+
109
+ return {
110
+ stargazerTimes: info.stargazerTimes,
111
+ repoImage: responseParsed.owner.avatar_url,
112
+ status: info.status,
113
+ };
114
+ }
@@ -0,0 +1,23 @@
1
+ const RENDER_URL = 'http://localhost:4000/render';
2
+
3
+ async function getResponse(body: string) {
4
+ return await fetch(RENDER_URL, {
5
+ method: 'POST',
6
+ headers: {
7
+ // eslint-disable-next-line @typescript-eslint/naming-convention
8
+ 'Content-Type': 'application/json',
9
+ },
10
+ body,
11
+ });
12
+ }
13
+
14
+ export async function POST(request: Request) {
15
+ const body = await request.json();
16
+
17
+ const response = await getResponse(JSON.stringify(body));
18
+ if (!response.ok) {
19
+ return new Response('Failed to render', {status: 500});
20
+ }
21
+
22
+ return new Response(response.body, {status: 200});
23
+ }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,25 @@
1
+ import type {Metadata} from 'next';
2
+ import {Inter} from 'next/font/google';
3
+ import './globals.css';
4
+
5
+ const inter = Inter({subsets: ['latin']});
6
+
7
+ export const metadata: Metadata = {
8
+ title: 'Create Next App',
9
+ description: 'Generated by create next app',
10
+ };
11
+
12
+ export default function RootLayout({
13
+ children,
14
+ }: Readonly<{
15
+ children: React.ReactNode;
16
+ }>) {
17
+ return (
18
+ <html lang="en">
19
+ <head>
20
+ <link rel="stylesheet" href="http://localhost:4000/player/project.css" />
21
+ </head>
22
+ <body className={inter.className}>{children}</body>
23
+ </html>
24
+ );
25
+ }
@@ -0,0 +1,204 @@
1
+ 'use client';
2
+
3
+ import {Player} from '@revideo/player-react';
4
+ import {getGithubRepositoryInfo} from './actions';
5
+ import {useState} from 'react';
6
+ import {LoaderCircle} from 'lucide-react';
7
+ import {parseStream} from '../utils/parse';
8
+ import project from '@/revideo/project';
9
+
10
+ function Button({
11
+ children,
12
+ loading,
13
+ onClick,
14
+ }: {
15
+ children: React.ReactNode;
16
+ loading: boolean;
17
+ onClick: () => void;
18
+ }) {
19
+ return (
20
+ <button
21
+ className="text-sm flex items-center gap-x-2 rounded-md p-2 bg-gray-200 text-gray-700 hover:bg-gray-300"
22
+ onClick={() => onClick()}
23
+ disabled={loading}
24
+ >
25
+ {loading && <LoaderCircle className="animate-spin h-4 w-4 text-gray-700" />}
26
+ {children}
27
+ </button>
28
+ );
29
+ }
30
+
31
+ function RenderComponent({
32
+ stargazerTimes,
33
+ repoName,
34
+ repoImage,
35
+ }: {
36
+ stargazerTimes: number[];
37
+ repoName: string;
38
+ repoImage: string | null | undefined;
39
+ }) {
40
+ const [renderLoading, setRenderLoading] = useState(false);
41
+ const [progress, setProgress] = useState(0);
42
+ const [downloadUrl, setDownloadUrl] = useState<string | null>(null);
43
+
44
+ /**
45
+ * Render the video.
46
+ */
47
+ async function render() {
48
+ setRenderLoading(true);
49
+ const res = await fetch('/api/render', {
50
+ method: 'POST',
51
+ headers: {
52
+ // eslint-disable-next-line @typescript-eslint/naming-convention
53
+ 'Content-Type': 'application/json',
54
+ },
55
+ body: JSON.stringify({
56
+ variables: {
57
+ data: stargazerTimes.length ? stargazerTimes : undefined,
58
+ repoName: repoName || undefined,
59
+ repoImage: repoImage || undefined,
60
+ },
61
+ streamProgress: true,
62
+ }),
63
+ }).catch((e) => console.log(e));
64
+
65
+ if (!res) {
66
+ alert('Failed to render video.');
67
+ return;
68
+ }
69
+
70
+ const downloadUrl = await parseStream(res.body!.getReader(), (p) => setProgress(p));
71
+ setRenderLoading(false);
72
+ setDownloadUrl(downloadUrl);
73
+ }
74
+
75
+ return (
76
+ <div className="flex gap-x-4">
77
+ {/* Progress bar */}
78
+ <div className="text-sm flex-1 bg-gray-100 rounded-md overflow-hidden">
79
+ <div
80
+ className="text-gray-600 bg-gray-400 h-full flex items-center px-4 transition-all transition-200"
81
+ style={{
82
+ width: `${Math.round(progress * 100)}%`,
83
+ }}
84
+ >
85
+ {Math.round(progress * 100)}%
86
+ </div>
87
+ </div>
88
+ {downloadUrl ? (
89
+ <a
90
+ href={downloadUrl}
91
+ download
92
+ className="text-sm flex items-center gap-x-2 rounded-md p-2 bg-green-200 text-gray-700 hover:bg-gray-300"
93
+ >
94
+ Download video
95
+ </a>
96
+ ) : (
97
+ <Button onClick={() => render()} loading={renderLoading}>
98
+ Render video
99
+ </Button>
100
+ )}
101
+ </div>
102
+ );
103
+ }
104
+
105
+ export default function Home() {
106
+ const [repoName, setRepoName] = useState<string>('');
107
+ const [repoImage, setRepoImage] = useState<string | null>();
108
+ const [stargazerTimes, setStargazerTimes] = useState<number[]>([]);
109
+
110
+ const [githubLoading, setGithubLoading] = useState(false);
111
+ const [needsKey, setNeedsKey] = useState(false);
112
+ const [key, setKey] = useState('');
113
+ const [error, setError] = useState<string | null>();
114
+
115
+ /**
116
+ * Get information about the repository from Github.
117
+ */
118
+ async function fetchInformation(repoName: `${string}/${string}`, key: string) {
119
+ setGithubLoading(true);
120
+ const response = await getGithubRepositoryInfo(repoName, key ?? undefined);
121
+ setGithubLoading(false);
122
+
123
+ if (response.status === 'rate-limit') {
124
+ setNeedsKey(true);
125
+ return;
126
+ }
127
+
128
+ if (response.status === 'error') {
129
+ setError('Failed to fetch repository information from Github.');
130
+ return;
131
+ }
132
+
133
+ setStargazerTimes(response.stargazerTimes);
134
+ setRepoImage(response.repoImage);
135
+ }
136
+
137
+ return (
138
+ <>
139
+ <div className="m-auto p-12 max-w-7xl flex flex-col gap-y-4">
140
+ <div>
141
+ <div className="text-sm text-gray-700 mb-2">Repository</div>
142
+ <div className="flex gap-x-4 text-sm">
143
+ <input
144
+ className="flex-1 rounded-md p-2 bg-gray-200 focus:outline-none placeholder:text-gray-400"
145
+ placeholder="redotvideo/revideo"
146
+ value={repoName}
147
+ onChange={(e) => setRepoName(e.target.value)}
148
+ />
149
+ {!needsKey && (
150
+ <Button
151
+ loading={githubLoading}
152
+ onClick={() => fetchInformation(repoName as `${string}/${string}`, key)}
153
+ >
154
+ Fetch information
155
+ </Button>
156
+ )}
157
+ </div>
158
+ </div>
159
+ {needsKey && (
160
+ <div>
161
+ <div className="text-sm text-blue-600 mb-2">
162
+ You hit the Github API rate-limit. Please provide your own key. Requests to Github are
163
+ made directly and the key stays on your device.
164
+ </div>
165
+ <div className="flex gap-x-4 text-sm">
166
+ <input
167
+ className="flex-1 rounded-md p-2 bg-gray-200 focus:outline-none placeholder:text-gray-400"
168
+ placeholder="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
169
+ value={key}
170
+ onChange={(e) => setKey(e.target.value)}
171
+ />
172
+ <Button
173
+ loading={githubLoading}
174
+ onClick={() => fetchInformation(repoName as `${string}/${string}`, key)}
175
+ >
176
+ Fetch information
177
+ </Button>
178
+ </div>
179
+ </div>
180
+ )}
181
+ {error && <div className="text-sm text-red-600">{error}</div>}
182
+ <div>
183
+ <div className="rounded-lg overflow-hidden">
184
+ {/* You can find the scene code inside revideo/src/scenes/example.tsx */}
185
+ <Player
186
+ project={project}
187
+ controls={true}
188
+ variables={{
189
+ data: stargazerTimes.length > 0 ? stargazerTimes : undefined,
190
+ repoName: repoName ? repoName : undefined,
191
+ repoImage: repoImage ? repoImage : undefined,
192
+ }}
193
+ />
194
+ </div>
195
+ </div>
196
+ <RenderComponent
197
+ stargazerTimes={stargazerTimes}
198
+ repoName={repoName}
199
+ repoImage={repoImage}
200
+ />
201
+ </div>
202
+ </>
203
+ );
204
+ }
@@ -0,0 +1,4 @@
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {};
3
+
4
+ export default nextConfig;
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "next",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint",
10
+ "revideo:serve": "revideo serve --projectFile ./revideo/project.ts",
11
+ "revideo:editor": "revideo editor --projectFile ./revideo/project.ts"
12
+ },
13
+ "dependencies": {
14
+ "@radix-ui/react-navigation-menu": "^1.1.4",
15
+ "@revideo/2d": "^0.6.0",
16
+ "@revideo/core": "^0.6.0",
17
+ "@revideo/player-react": "^0.6.0",
18
+ "class-variance-authority": "^0.7.0",
19
+ "lucide-react": "^0.378.0",
20
+ "next": "^14.2.13",
21
+ "p-limit": "^3",
22
+ "react": "^18",
23
+ "react-dom": "^18",
24
+ "tailwind-merge": "^2.3.0",
25
+ "tailwindcss-animate": "^1.0.7"
26
+ },
27
+ "devDependencies": {
28
+ "@revideo/cli": "^0.6.0",
29
+ "@revideo/ui": "^0.6.0",
30
+ "@types/node": "^20",
31
+ "@types/react": "^18",
32
+ "@types/react-dom": "^18",
33
+ "autoprefixer": "^10.4.19",
34
+ "eslint": "^8",
35
+ "eslint-config-next": "14.2.3",
36
+ "postcss": "^8",
37
+ "tailwindcss": "^3.4.3",
38
+ "typescript": "^5"
39
+ }
40
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
@@ -0,0 +1,9 @@
1
+ import {makeProject} from '@revideo/core';
2
+
3
+ import './global.css';
4
+
5
+ import example from './scene';
6
+
7
+ export default makeProject({
8
+ scenes: [example],
9
+ });
@@ -0,0 +1,179 @@
1
+ /** @jsxImportSource @revideo/2d/lib */
2
+ import {Gradient, Img, Layout, Line, Rect, Spline, Txt, makeScene2D} from '@revideo/2d';
3
+ import {all, createRef, useScene, Vector2, waitFor} from '@revideo/core';
4
+
5
+ /**
6
+ * Some example data to use in the scene when no data is provided
7
+ */
8
+ const exampleData = [
9
+ 0, 105826000, 265664000, 265671000, 265684000, 265689000, 265694000, 335596000, 414108000,
10
+ 416767000, 425249000, 674375000, 964912000, 1177339000, 1186686000, 1213498000, 1214781000,
11
+ 1214895000, 1219921000, 1221668000, 1222281000, 1222410000, 1222433000, 1227527000, 1228300000,
12
+ 1230497000, 1230501000, 1231234000, 1231239000, 1231314000, 1232727000, 1233520000, 1234669000,
13
+ 1236349000, 1236806000, 1237795000, 1245092000, 1251533000, 1254263000, 1262147000, 1262899000,
14
+ 1264370000, 1267519000, 1268870000, 1271198000, 1271847000, 1274347000, 1276515000, 1276671000,
15
+ 1279966000, 1280551000, 1283338000, 1283777000, 1285088000, 1286336000, 1286728000, 1293071000,
16
+ 1293863000, 1294963000, 1295005000, 1301398000, 1303551000, 1312541000, 1317615000, 1321096000,
17
+ 1323718000, 1337789000, 1343521000, 1344711000, 1346543000, 1371003000, 1389862000, 1494428000,
18
+ 1525657000, 1533978000, 1591597000, 1654009000, 1738062000, 1817754000, 1860276000, 1883450000,
19
+ 1883998000, 1891635000, 1930667000, 2055652000, 2201181000, 2216214000, 2246708000, 2324529000,
20
+ 2366960000, 2366996000, 2391904000, 2479357000, 2596772000, 2601046000, 2615944000, 2637502000,
21
+ 2689660000, 2733368000, 2737046000, 2812890000, 2863564000, 2955232000, 2955857000, 2961163000,
22
+ 2983003000, 2984020000, 2987437000, 2990281000, 2996230000, 3007072000, 3007175000, 3013062000,
23
+ 3016417000, 3018616000, 3019154000, 3026357000, 3029804000, 3036897000, 3037202000, 3037298000,
24
+ 3037737000, 3038639000, 3039016000, 3039322000, 3042145000, 3042529000, 3043490000, 3044558000,
25
+ 3046472000, 3047534000, 3048199000, 3048524000, 3048862000, 3051935000, 3058895000, 3065009000,
26
+ 3072790000, 3074109000, 3075041000, 3079153000, 3079875000, 3080083000, 3099026000, 3099874000,
27
+ 3103039000, 3109664000, 3112885000, 3127743000, 3134934000, 3140075000, 3173641000, 3173788000,
28
+ 3176205000, 3176720000, 3178996000, 3183882000, 3184287000, 3186716000, 3191153000, 3196320000,
29
+ 3196620000, 3198638000, 3213076000, 3234269000, 3263068000, 3270668000, 3278896000, 3284646000,
30
+ 3290556000, 3294331000, 3297742000, 3332896000, 3344044000, 3368767000, 3378844000, 3398863000,
31
+ 3434188000, 3435264000, 3435696000, 3435803000, 3442071000, 3517995000, 3519849000, 3554474000,
32
+ 3558289000, 3611948000, 3616675000, 3618144000, 3622775000, 3635577000, 3640600000, 3669592000,
33
+ 3679346000, 3698749000, 3715355000, 3729047000, 3759434000, 3787838000, 3801028000, 3817911000,
34
+ 3878742000, 3983973000, 4006119000, 4067980000, 4087451000, 4101992000, 4200703000, 4212009000,
35
+ 4212143000, 4212882000, 4213748000, 4213977000, 4214180000, 4214445000, 4220193000, 4220422000,
36
+ 4222468000, 4236874000, 4258899000, 4326288000, 4334389000, 4401276000, 4416803000, 4421444000,
37
+ 4437462000, 4501703000, 4556531000, 4598409000, 4690540000, 4736772000, 4742561000, 4803793000,
38
+ 4834054000, 4866127000, 4868886000, 4873958000, 4891455000, 4921352000, 4941837000, 4953890000,
39
+ 4956018000, 4979428000, 4985123000, 5062420000, 5108308000, 5333539000, 5459835000, 5461002000,
40
+ 5521826000, 5584695000, 5586217000, 5598497000, 5604962000, 5625413000, 5636146000, 5637453000,
41
+ 5682023000, 5718405000, 5722303000, 5760543000, 5769209000, 5772790000, 5880569000, 6110458000,
42
+ 6135651000, 6185575000, 6202790000, 6232205000, 6284650000, 6297771000, 6392835000, 6401789000,
43
+ 6480914000, 6566872000, 6643031000, 6695443000, 6696088000, 6710689000, 6712966000, 6727715000,
44
+ 6733098000, 6783253000, 6805478000, 6875821000, 6904033000, 6971558000, 6972735000,
45
+ ];
46
+
47
+ const exampleRepoName = 'redotvideo/revideo';
48
+ const exampleRepoImage = 'https://avatars.githubusercontent.com/u/133898679';
49
+
50
+ export default makeScene2D('main', function* (view) {
51
+ // Get variables
52
+ const repoName = useScene().variables.get('repoName', exampleRepoName);
53
+ const repoImage = useScene().variables.get('repoImage', exampleRepoImage);
54
+ const data = useScene().variables.get('data', exampleData);
55
+
56
+ const max = Math.max(...data());
57
+ const videoLength = 5; // seconds
58
+ const totalValues = data().length;
59
+
60
+ // Black background
61
+ view.fill('#000000');
62
+
63
+ // Calculate coordinates for each timestamp
64
+ const linePoints = data().map((ms, i) => {
65
+ const x = (ms / max) * view.width();
66
+ const xShifted = x - view.width() / 2;
67
+
68
+ const y = ((-i / totalValues) * view.height()) / 2;
69
+ const yShifted = y + view.height() / 4;
70
+
71
+ return new Vector2(xShifted, yShifted);
72
+ });
73
+
74
+ // Coordinates of the bottom corners
75
+ const bottomCorners = [
76
+ new Vector2(view.width() / 2, view.height() / 2),
77
+ new Vector2(-view.width() / 2, view.height() / 2),
78
+ ];
79
+
80
+ // Background gradient
81
+ const gradient = new Gradient({
82
+ type: 'linear',
83
+ from: [0, 0],
84
+ to: [0, view.height()],
85
+ stops: [
86
+ {offset: 0, color: '#000000'},
87
+ {offset: 1, color: 'green'},
88
+ ],
89
+ });
90
+
91
+ // Refs, used to animate elements
92
+ const outerLayoutRef = createRef<Layout>();
93
+ const innerLayoutRef = createRef<Layout>();
94
+ const rectRef = createRef<Rect>();
95
+
96
+ // Add elements to the view
97
+ yield view.add(
98
+ <>
99
+ <>
100
+ <Line points={linePoints} lineWidth={30} stroke={'#3EAC45'} />
101
+ <Spline points={[...linePoints, ...bottomCorners]} fill={gradient} />
102
+ <Rect
103
+ ref={rectRef}
104
+ x={view.width() / 2}
105
+ y={0}
106
+ width={view.width() * 2}
107
+ height={view.height()}
108
+ fill={'#000000'}
109
+ />
110
+ </>
111
+ <Layout
112
+ ref={outerLayoutRef}
113
+ layout
114
+ alignItems={'center'}
115
+ gap={40}
116
+ x={-870}
117
+ y={-400}
118
+ offset={[-1, 0]}
119
+ >
120
+ <Img
121
+ src={repoImage()}
122
+ width={100}
123
+ height={100}
124
+ stroke={'#555555'}
125
+ lineWidth={8}
126
+ strokeFirst={true}
127
+ radius={10}
128
+ />
129
+ <Layout ref={innerLayoutRef} direction={'column'}>
130
+ <Txt
131
+ fontFamily={'Roboto'}
132
+ text={repoName()}
133
+ fill={'#ffffff'}
134
+ x={-520}
135
+ y={-395}
136
+ fontSize={50}
137
+ fontWeight={600}
138
+ />
139
+ </Layout>
140
+ </Layout>
141
+ </>,
142
+ );
143
+
144
+ // Resize the rectangle to reveal the scene
145
+ yield* rectRef().width(0, videoLength);
146
+
147
+ // Make rectangle transparent and cover the scene again
148
+ rectRef().fill('#00000000');
149
+ rectRef().width(view.width() * 2);
150
+
151
+ // Cover the scene while the Layout block
152
+ // is centered
153
+ yield* all(
154
+ rectRef().fill('#000000', 2),
155
+ outerLayoutRef().x(0, 2),
156
+ outerLayoutRef().y(-50, 2),
157
+ outerLayoutRef().offset([0, 0], 2),
158
+ );
159
+
160
+ // Add text with the total number of stars
161
+ const starTextRef = createRef<Txt>();
162
+ innerLayoutRef().add(
163
+ <Txt
164
+ fontFamily={'Roboto'}
165
+ ref={starTextRef}
166
+ text={`${totalValues} stars`}
167
+ fill={'#000000'}
168
+ x={0}
169
+ y={0}
170
+ fontSize={40}
171
+ fontWeight={500}
172
+ marginBottom={-45}
173
+ />,
174
+ );
175
+ yield* all(starTextRef().fill('#ffffff', 2), starTextRef().margin(0, 2));
176
+
177
+ // Wait for 2 seconds
178
+ yield* waitFor(2);
179
+ });
@@ -0,0 +1,30 @@
1
+ /* eslint-disable naming-convention */
2
+ import type {Config} from 'tailwindcss';
3
+
4
+ const config: Config = {
5
+ content: [
6
+ './pages/**/*.{js,ts,jsx,tsx,mdx}',
7
+ './components/**/*.{js,ts,jsx,tsx,mdx}',
8
+ './app/**/*.{js,ts,jsx,tsx,mdx}',
9
+ ],
10
+ theme: {
11
+ extend: {
12
+ colors: {
13
+ gray: {
14
+ 50: '#FAFAFA',
15
+ 100: '#F3F3F3',
16
+ 200: '#E5E5E5',
17
+ 300: '#C7C7C7',
18
+ 400: '#ACACAC',
19
+ 500: '#808080',
20
+ 600: '#5F5F5F',
21
+ 700: '#4E4E4E',
22
+ 800: '#373737',
23
+ 900: '#2A2A2A',
24
+ 950: '#151515',
25
+ },
26
+ },
27
+ },
28
+ },
29
+ };
30
+ export default config;
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["dom", "dom.iterable", "esnext"],
4
+ "allowJs": true,
5
+ "skipLibCheck": true,
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "esModuleInterop": true,
9
+ "module": "esnext",
10
+ "moduleResolution": "bundler",
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "target": "es2015",
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26
+ "exclude": ["node_modules"]
27
+ }