@remotion/promo-pages 4.0.315 → 4.0.318

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 (43) hide show
  1. package/.turbo/turbo-make.log +2 -2
  2. package/dist/Homepage.js +11852 -12156
  3. package/dist/components/Homepage.js +4 -4
  4. package/dist/components/homepage/CommunityStats.js +1 -1
  5. package/dist/components/homepage/Counter.d.ts +1 -0
  6. package/dist/components/homepage/Counter.js +15 -7
  7. package/dist/components/homepage/Demo/DemoRender.d.ts +16 -16
  8. package/dist/components/homepage/Demo/DisplayedEmoji.js +17 -3
  9. package/dist/components/homepage/Demo/math.d.ts +1 -1
  10. package/dist/components/homepage/FreePricing.js +20 -25
  11. package/dist/components/homepage/IconForTemplate.js +4 -0
  12. package/dist/components/homepage/IfYouKnowReact.js +5 -2
  13. package/dist/components/homepage/NewsletterButton.js +3 -2
  14. package/dist/components/homepage/ParameterizeAndEdit.d.ts +2 -0
  15. package/dist/components/homepage/ParameterizeAndEdit.js +22 -0
  16. package/dist/components/homepage/RealMp4Videos.js +10 -1
  17. package/dist/components/homepage/VideoAppsShowcase.js +6 -3
  18. package/dist/components/homepage/VideoAppsTitle.d.ts +0 -1
  19. package/dist/components/homepage/VideoAppsTitle.js +1 -4
  20. package/dist/components/icons/recorder.d.ts +3 -0
  21. package/dist/components/icons/recorder.js +4 -0
  22. package/dist/homepage/Pricing.js +131 -90
  23. package/dist/tailwind.css +74 -61
  24. package/package.json +10 -10
  25. package/public/img/editing-safari.mp4 +0 -0
  26. package/public/img/editing-vp9-chrome.webm +0 -0
  27. package/src/components/Homepage.tsx +7 -13
  28. package/src/components/homepage/CommunityStats.tsx +1 -1
  29. package/src/components/homepage/Counter.tsx +17 -7
  30. package/src/components/homepage/Demo/DisplayedEmoji.tsx +22 -4
  31. package/src/components/homepage/FreePricing.tsx +88 -65
  32. package/src/components/homepage/IconForTemplate.tsx +5 -0
  33. package/src/components/homepage/IfYouKnowReact.tsx +26 -14
  34. package/src/components/homepage/NewsletterButton.tsx +5 -4
  35. package/src/components/homepage/ParameterizeAndEdit.tsx +89 -0
  36. package/src/components/homepage/RealMp4Videos.tsx +55 -13
  37. package/src/components/homepage/VideoAppsShowcase.tsx +21 -10
  38. package/src/components/homepage/VideoAppsTitle.tsx +0 -13
  39. package/src/components/icons/recorder.tsx +23 -0
  40. package/dist/components/homepage/Editor.d.ts +0 -2
  41. package/dist/components/homepage/Editor.js +0 -37
  42. package/public/img/player-demo.mp4 +0 -0
  43. package/src/components/homepage/Editor.tsx +0 -67
@@ -4,19 +4,18 @@ import React from 'react';
4
4
  import {BackgroundAnimation} from './homepage/BackgroundAnimation';
5
5
  import CommunityStats from './homepage/CommunityStats';
6
6
  import {Demo} from './homepage/Demo';
7
- import {LightningFastEditor} from './homepage/Editor';
8
7
  import EvaluateRemotionSection from './homepage/EvaluateRemotion';
9
8
  import {IfYouKnowReact} from './homepage/IfYouKnowReact';
10
9
  import type {ColorMode} from './homepage/layout/use-color-mode';
11
10
  import {ColorModeProvider} from './homepage/layout/use-color-mode';
12
11
  import {MoreVideoPowerSection} from './homepage/MoreVideoPowerSection';
13
12
  import {NewsletterButton} from './homepage/NewsletterButton';
13
+ import {ParameterizeAndEdit} from './homepage/ParameterizeAndEdit';
14
14
  import {Pricing} from './homepage/Pricing';
15
15
  import {RealMP4Videos} from './homepage/RealMp4Videos';
16
16
  import TrustedByBanner from './homepage/TrustedByBanner';
17
- import {VideoApps} from './homepage/VideoApps';
18
17
  import VideoAppsShowcase from './homepage/VideoAppsShowcase';
19
- import {SectionTitle, VideoAppsTitle} from './homepage/VideoAppsTitle';
18
+ import {SectionTitle} from './homepage/VideoAppsTitle';
20
19
  import {WriteInReact} from './homepage/WriteInReact';
21
20
 
22
21
  export const NewLanding: React.FC<{
@@ -38,19 +37,11 @@ export const NewLanding: React.FC<{
38
37
  <WriteInReact />
39
38
  <br />
40
39
  <IfYouKnowReact />
40
+ <ParameterizeAndEdit />
41
41
  <RealMP4Videos />
42
42
  <br />
43
43
  <br />
44
44
  <br />
45
- <br />
46
- <LightningFastEditor />
47
- <br />
48
- <br />
49
- <br />
50
- <VideoAppsTitle />
51
- <VideoApps active="remotion" />
52
- <br />
53
- <br />
54
45
  <VideoAppsShowcase />
55
46
  <br />
56
47
  <br />
@@ -70,7 +61,10 @@ export const NewLanding: React.FC<{
70
61
  <br />
71
62
  <br />
72
63
  <br />
73
- <SectionTitle>Even more video power to developers</SectionTitle>
64
+ <SectionTitle>Even more power to developers</SectionTitle>
65
+ <div className={'fontbrand text-center mb-10 -mt-4'}>
66
+ Innovative video products that you might enjoy.
67
+ </div>
74
68
  <MoreVideoPowerSection />
75
69
  <br />
76
70
  <br />
@@ -25,7 +25,7 @@ const SectionLink: React.FC<{
25
25
  const CommunityStats: React.FC = () => (
26
26
  <div className={'m-auto max-w-[700px] text-center'}>
27
27
  <SectionTitle>Never build alone</SectionTitle>
28
- <div className={'fontbrand text-center mb-10'}>
28
+ <div className={'fontbrand text-center mb-10 -mt-4'}>
29
29
  Join a thriving community of developers.
30
30
  </div>
31
31
  <div className={'flex flex-wrap justify-between gap-4 w-full items-center'}>
@@ -47,40 +47,50 @@ interface CounterProps {
47
47
  readonly count: number;
48
48
  readonly setCount: (count: number) => void;
49
49
  readonly minCount?: number;
50
+ readonly step?: number;
50
51
  }
51
52
 
52
53
  export const Counter: React.FC<CounterProps> = ({
53
54
  count,
54
55
  setCount,
55
56
  minCount = 0,
57
+ step = 1,
56
58
  }) => {
57
59
  const decrement = () => {
58
60
  if (count > minCount) {
59
- setCount(count - 1);
61
+ setCount(Math.max(minCount, count - step));
60
62
  }
61
63
  };
62
64
 
63
65
  const increment = () => {
64
- setCount(count + 1);
66
+ setCount(count + step);
65
67
  };
66
68
 
67
69
  return (
68
- <div style={container} className={cn('border-effect w-[110px] text-text')}>
70
+ <div style={container} className={cn('border-effect w-[140px] text-text')}>
69
71
  <input
70
72
  className={
71
- 'fontbrand text-2xl font-medium min-w-[60px] border-0 text-end bg-transparent outline-0 text-text'
73
+ 'fontbrand text-2xl font-medium min-w-[80px] border-0 text-end bg-transparent outline-0 text-text'
72
74
  }
73
75
  type="number"
74
76
  onClick={(e) => e.currentTarget.select()}
75
77
  value={count}
76
78
  onChange={(e: ChangeEvent<HTMLInputElement>) => {
77
79
  if (e.target.value.trim() === '') {
78
- setCount(1);
80
+ setCount(step === 1 ? 1 : minCount);
79
81
  return;
80
82
  }
81
83
 
82
- const max = Math.max(parseInt(e.target.value, 10), 1);
83
- setCount(max);
84
+ const inputValue = parseInt(e.target.value, 10);
85
+ const validValue = Math.max(inputValue, minCount);
86
+
87
+ // For steps > 1, round to the nearest valid step
88
+ if (step > 1) {
89
+ const roundedValue = Math.round(validValue / step) * step;
90
+ setCount(Math.max(roundedValue, minCount));
91
+ } else {
92
+ setCount(validValue);
93
+ }
84
94
  }}
85
95
  />
86
96
  <div className="flex flex-col ml-3 h-full">
@@ -1,6 +1,5 @@
1
1
  import type {EmojiName} from '@remotion/animated-emoji';
2
- import type {LottieAnimationData} from '@remotion/lottie';
3
- import {Lottie, getLottieMetadata} from '@remotion/lottie';
2
+ import type {Lottie, LottieAnimationData} from '@remotion/lottie';
4
3
  import React, {useEffect, useMemo, useState} from 'react';
5
4
  import {
6
5
  cancelRender,
@@ -20,6 +19,9 @@ export const DisplayedEmoji: React.FC<{
20
19
  }> = ({emoji}) => {
21
20
  const [data, setData] = useState<Data | null>(null);
22
21
  const {durationInFrames, fps} = useVideoConfig();
22
+ const [browser, setBrowser] = useState<boolean>(
23
+ typeof document !== 'undefined',
24
+ );
23
25
 
24
26
  const src = useMemo(() => {
25
27
  if (emoji === 'melting') {
@@ -40,8 +42,14 @@ export const DisplayedEmoji: React.FC<{
40
42
  const [handle] = useState(() => delayRender());
41
43
 
42
44
  useEffect(() => {
43
- Promise.all([fetch(src).then((res) => res.json())])
44
- .then(([json]) => {
45
+ Promise.all([
46
+ fetch(src).then((res) => res.json()),
47
+ import('@remotion/lottie').then(({Lottie, getLottieMetadata}) => ({
48
+ Lottie,
49
+ getLottieMetadata,
50
+ })),
51
+ ])
52
+ .then(([json, {Lottie, getLottieMetadata}]) => {
45
53
  setData({
46
54
  Lottie,
47
55
  duration: getLottieMetadata(json)?.durationInSeconds as number,
@@ -54,6 +62,16 @@ export const DisplayedEmoji: React.FC<{
54
62
  });
55
63
  }, [handle, src]);
56
64
 
65
+ useEffect(() => {
66
+ if (typeof document !== 'undefined') {
67
+ setBrowser(true);
68
+ }
69
+ }, []);
70
+
71
+ if (!browser) {
72
+ return null;
73
+ }
74
+
57
75
  if (!data) {
58
76
  return null;
59
77
  }
@@ -65,7 +65,7 @@ const SmallPriceTag: React.FC<{
65
65
  return (
66
66
  <div
67
67
  className={
68
- 'fontbrand text-2xl font-medium w-auto min-w-[80px] text-right shrink-0 ml-4'
68
+ 'fontbrand text-2xl font-medium w-auto min-w-[80px] text-right shrink-0'
69
69
  }
70
70
  >
71
71
  {children}
@@ -137,10 +137,15 @@ const SEAT_PRICE = 25;
137
137
  const RENDER_UNIT_PRICE = 10;
138
138
  const WEBCODECS_UNIT_PRICE = 10;
139
139
 
140
+ const icon: React.CSSProperties = {
141
+ height: 16,
142
+ marginLeft: 4,
143
+ };
144
+
140
145
  export const CompanyPricing: React.FC = () => {
141
146
  const [devSeatCount, setDevSeatCount] = React.useState(1);
142
- const [cloudUnitCount, setCloudUnitCount] = React.useState(1);
143
- const [webcodecsUnits, setWebcodecsUnits] = React.useState(1);
147
+ const [cloudRenders, setCloudRenders] = React.useState(1000);
148
+ const [creations, setCreations] = React.useState(1000);
144
149
 
145
150
  const formatPrice = useCallback((price: number) => {
146
151
  const formatter = new Intl.NumberFormat('en-US', {
@@ -155,29 +160,15 @@ export const CompanyPricing: React.FC = () => {
155
160
  return Math.max(
156
161
  100,
157
162
  devSeatCount * SEAT_PRICE +
158
- cloudUnitCount * RENDER_UNIT_PRICE +
159
- webcodecsUnits * WEBCODECS_UNIT_PRICE,
163
+ (cloudRenders / 1000) * RENDER_UNIT_PRICE +
164
+ (creations / 1000) * WEBCODECS_UNIT_PRICE,
160
165
  );
161
- }, [cloudUnitCount, devSeatCount, webcodecsUnits]);
166
+ }, [cloudRenders, devSeatCount, creations]);
162
167
 
163
168
  const totalPriceString = useMemo(() => {
164
169
  return formatPrice(totalPrice);
165
170
  }, [formatPrice, totalPrice]);
166
171
 
167
- const rendersPerMonth = useMemo(() => {
168
- const formatter = new Intl.NumberFormat('en-US', {
169
- maximumFractionDigits: 0,
170
- });
171
- return formatter.format(cloudUnitCount * 1000);
172
- }, [cloudUnitCount]);
173
-
174
- const conversionsPerMonth = useMemo(() => {
175
- const formatter = new Intl.NumberFormat('en-US', {
176
- maximumFractionDigits: 0,
177
- });
178
- return formatter.format(webcodecsUnits * 1000);
179
- }, [webcodecsUnits]);
180
-
181
172
  return (
182
173
  <Container>
183
174
  <Audience>For collaborations and companies of 4+ people</Audience>
@@ -189,80 +180,87 @@ export const CompanyPricing: React.FC = () => {
189
180
  <InfoTooltip text="Credits for Mux.com. Applies only to new Mux customers." />
190
181
  </PricingBulletPoint>
191
182
  <div style={{height: 30}} />
192
- <div className={'flex flex-row items-center'}>
183
+ <div className={'flex flex-col md:flex-row md:items-center'}>
193
184
  <div style={textUnitWrapper}>
194
185
  <div className={'fontbrand font-bold text-lg'}>Developer Seats</div>
195
186
  <div className={'text-muted fontbrand text-sm'}>
196
187
  Number of developers working with Remotion
197
188
  </div>
198
189
  </div>
199
- <div style={{flex: 3}} />
200
- <Counter count={devSeatCount} setCount={setDevSeatCount} minCount={1} />
201
- <SmallPriceTag>
202
- $
203
- {new Intl.NumberFormat('en-US', {
204
- maximumFractionDigits: 0,
205
- }).format(SEAT_PRICE * devSeatCount)}
206
- </SmallPriceTag>
190
+ <div style={{flex: 3}} className="hidden md:block" />
191
+ <div className="flex flex-row items-center justify-between mt-3 md:mt-0">
192
+ <Counter
193
+ count={devSeatCount}
194
+ setCount={setDevSeatCount}
195
+ minCount={1}
196
+ />
197
+ <SmallPriceTag>
198
+ $
199
+ {new Intl.NumberFormat('en-US', {
200
+ maximumFractionDigits: 0,
201
+ }).format(SEAT_PRICE * devSeatCount)}
202
+ </SmallPriceTag>
203
+ </div>
207
204
  </div>
208
205
  <div style={{height: 14}} />
209
- <div className={'flex flex-row items-center'}>
206
+ <div className={'flex flex-col md:flex-row md:items-center'}>
210
207
  <div style={textUnitWrapper}>
211
- <div className={'fontbrand font-bold text-lg'}>
212
- Cloud Rendering Units
213
- </div>
208
+ <div className={'fontbrand font-bold text-lg'}>Server renders</div>
214
209
  <div className={'text-muted fontbrand text-sm'}>
215
- Allows for {rendersPerMonth}{' '}
216
210
  <a
217
211
  href="https://www.remotion.dev/docs/compare-ssr"
218
212
  className="underline underline-offset-4 text-inherit"
219
213
  >
220
- self-hosted renders per month
221
- </a>{' '}
222
- each
214
+ Renders per month (self-hosted)
215
+ </a>
223
216
  </div>
224
217
  </div>
225
- <div style={{flex: 3}} />
226
- <Counter
227
- count={cloudUnitCount}
228
- setCount={setCloudUnitCount}
229
- minCount={0}
230
- />
231
- <SmallPriceTag>
232
- $
233
- {new Intl.NumberFormat('en-US', {
234
- maximumFractionDigits: 0,
235
- }).format(RENDER_UNIT_PRICE * cloudUnitCount)}
236
- </SmallPriceTag>
218
+ <div style={{flex: 3}} className="hidden md:block" />
219
+ <div className="flex flex-row items-center justify-between mt-3 md:mt-0">
220
+ <Counter
221
+ count={cloudRenders}
222
+ setCount={setCloudRenders}
223
+ minCount={0}
224
+ step={1000}
225
+ />
226
+ <SmallPriceTag>
227
+ $
228
+ {new Intl.NumberFormat('en-US', {
229
+ maximumFractionDigits: 0,
230
+ }).format((cloudRenders / 1000) * RENDER_UNIT_PRICE)}
231
+ </SmallPriceTag>
232
+ </div>
237
233
  </div>
238
234
  <div style={{height: 14}} />
239
- <div className={'flex flex-row items-center'}>
235
+ <div className={'flex flex-col md:flex-row md:items-center'}>
240
236
  <div style={textUnitWrapper}>
241
237
  <div className={'fontbrand font-bold text-lg'}>
242
- WebCodecs Creation Units
238
+ WebCodecs video creations
243
239
  </div>
244
240
  <div className={'text-muted fontbrand text-sm'}>
245
- Allows for{' '}
246
241
  <a
247
242
  className="underline underline-offset-4 text-inherit"
248
243
  href="https://remotion.dev/webcodecs"
249
244
  >
250
- {conversionsPerMonth} client-side video creations{' '}
245
+ Client-side video creations per month
251
246
  </a>
252
247
  </div>
253
248
  </div>
254
- <div style={{flex: 3}} />
255
- <Counter
256
- count={webcodecsUnits}
257
- setCount={setWebcodecsUnits}
258
- minCount={0}
259
- />
260
- <SmallPriceTag>
261
- $
262
- {new Intl.NumberFormat('en-US', {
263
- maximumFractionDigits: 0,
264
- }).format(RENDER_UNIT_PRICE * webcodecsUnits)}
265
- </SmallPriceTag>
249
+ <div style={{flex: 3}} className="hidden md:block" />
250
+ <div className="flex flex-row items-center justify-between mt-3 md:mt-0">
251
+ <Counter
252
+ count={creations}
253
+ setCount={setCreations}
254
+ minCount={0}
255
+ step={1000}
256
+ />
257
+ <SmallPriceTag>
258
+ $
259
+ {new Intl.NumberFormat('en-US', {
260
+ maximumFractionDigits: 0,
261
+ }).format((creations / 1000) * WEBCODECS_UNIT_PRICE)}
262
+ </SmallPriceTag>
263
+ </div>
266
264
  </div>
267
265
  <div style={{height: 20}} />
268
266
  <div className={'flex flex-row justify-end'}>
@@ -276,6 +274,31 @@ export const CompanyPricing: React.FC = () => {
276
274
  </BottomInfo>
277
275
  </div>
278
276
  </div>
277
+ <div className={'flex flex-row justify-end mt-4'}>
278
+ <div
279
+ style={{
280
+ ...textUnitWrapper,
281
+ alignItems: 'flex-end',
282
+ }}
283
+ >
284
+ <a
285
+ href="https://remotion.pro/dashboard"
286
+ className="font-brand text-brand flex flex-row items-center gap-1 no-underline"
287
+ >
288
+ Buy now{' '}
289
+ <svg
290
+ style={icon}
291
+ xmlns="http://www.w3.org/2000/svg"
292
+ viewBox="0 0 448 512"
293
+ >
294
+ <path
295
+ fill="currentColor"
296
+ d="M438.6 278.6l-160 160C272.4 444.9 264.2 448 256 448s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L338.8 288H32C14.33 288 .0016 273.7 .0016 256S14.33 224 32 224h306.8l-105.4-105.4c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l160 160C451.1 245.9 451.1 266.1 438.6 278.6z"
297
+ />
298
+ </svg>
299
+ </a>
300
+ </div>
301
+ </div>
279
302
  </Container>
280
303
  );
281
304
  };
@@ -7,6 +7,7 @@ import {JSIcon} from '../icons/js';
7
7
  import {MusicIcon} from '../icons/music';
8
8
  import {NextIcon} from '../icons/next';
9
9
  import {OverlayIcon} from '../icons/overlay';
10
+ import {Recorder} from '../icons/recorder';
10
11
  import {ReactRouterIcon} from '../icons/remix';
11
12
  import {SkiaIcon} from '../icons/skia';
12
13
  import {Stargazer} from '../icons/stargazer';
@@ -135,6 +136,10 @@ export const IconForTemplate: React.FC<{
135
136
  return <OverlayIcon style={{height: scale * 42}} />;
136
137
  }
137
138
 
139
+ if (template.cliId === 'recorder') {
140
+ return <Recorder style={{height: scale * 36}} />;
141
+ }
142
+
138
143
  if (
139
144
  template.cliId === 'next' ||
140
145
  template.cliId === 'next-tailwind' ||
@@ -1,5 +1,4 @@
1
1
  import React, {useEffect, useState} from 'react';
2
- import {BlueButton} from './layout/Button';
3
2
 
4
3
  export const isWebkit = () => {
5
4
  if (typeof window === 'undefined') {
@@ -14,6 +13,11 @@ export const isWebkit = () => {
14
13
  return isSafariUserAgent || isChrome;
15
14
  };
16
15
 
16
+ const icon: React.CSSProperties = {
17
+ height: 16,
18
+ marginLeft: 10,
19
+ };
20
+
17
21
  export const IfYouKnowReact: React.FC = () => {
18
22
  const [vid, setVid] = useState('/img/compose.webm');
19
23
 
@@ -24,31 +28,39 @@ export const IfYouKnowReact: React.FC = () => {
24
28
  }, []);
25
29
 
26
30
  return (
27
- <div className="flex flex-col lg:flex-row text-left lg:text-right justify-start lg:justify-end items-start lg:mb-0">
31
+ <div className="flex flex-col lg:flex-row text-left justify-start lg:justify-end items-start lg:mb-0 gap-6 mt-8">
28
32
  <video
29
33
  src={vid}
30
34
  muted
31
35
  autoPlay
32
36
  playsInline
33
37
  loop
34
- className="w-[600px] h-[600px] cursor-default! relative lg:-translate-x-8 -mb-50 -mt-10 lg:mt-0 lg:mb-0"
38
+ className="w-[500px] cursor-default! relative lg:-translate-x-8 -mb-40 lg:mt-0 lg:mb-0"
35
39
  />
36
- <div className="h-10 lg:flex-1" />
37
- <div className="lg:text-right">
40
+ <div>
38
41
  <h2 className="text-4xl fontbrand pt-20">
39
- <span className="text-brand">Compose</span> your
40
- <br />
41
- video with code.
42
+ <span className="text-brand">Compose</span> with code
42
43
  </h2>
43
- <p className="leading-relaxed">
44
+ <p className="leading-relaxed font-brand">
44
45
  Use React, a powerful frontend technology, to create sophisticated
45
46
  videos with code.
46
47
  </p>
47
- <div className="h-7" />
48
- <a className="no-underline inline-block" href="/docs/the-fundamentals">
49
- <BlueButton size="sm" loading={false}>
50
- Learn Remotion
51
- </BlueButton>
48
+ <div className="h-4" />
49
+ <a
50
+ className="no-underline text-brand font-brand font-bold inline-flex flex-row items-center"
51
+ href="/docs/the-fundamentals"
52
+ >
53
+ Learn Remotion{' '}
54
+ <svg
55
+ style={icon}
56
+ xmlns="http://www.w3.org/2000/svg"
57
+ viewBox="0 0 448 512"
58
+ >
59
+ <path
60
+ fill="currentColor"
61
+ d="M438.6 278.6l-160 160C272.4 444.9 264.2 448 256 448s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L338.8 288H32C14.33 288 .0016 273.7 .0016 256S14.33 224 32 224h306.8l-105.4-105.4c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l160 160C451.1 245.9 451.1 266.1 438.6 278.6z"
62
+ />
63
+ </svg>
52
64
  </a>
53
65
  </div>
54
66
  </div>
@@ -1,6 +1,7 @@
1
1
  import React, {useCallback, useState} from 'react';
2
2
  import {BlueButton} from './layout/Button';
3
3
  import {Spacer} from './Spacer';
4
+ import {SectionTitle} from './VideoAppsTitle';
4
5
 
5
6
  export const NewsletterButton: React.FC<{}> = () => {
6
7
  const [email, setEmail] = useState('');
@@ -45,17 +46,17 @@ export const NewsletterButton: React.FC<{}> = () => {
45
46
  <div className="flex flex-col">
46
47
  <div className={'w-full'}>
47
48
  <div className={'flex flex-col flex-1'}>
48
- <div className={'text-2xl font-bold fontbrand'}>Newsletter</div>
49
+ <SectionTitle>Newsletter</SectionTitle>
49
50
  <form
50
51
  onSubmit={handleSubmit}
51
52
  style={{
52
53
  width: '100%',
53
54
  }}
54
55
  >
55
- <p className="leading-snug mt-1 text-muted fontbrand">
56
+ <div className={'fontbrand text-center mb-10 -mt-4'}>
56
57
  Read about new features and noteworthy updates we have made on
57
- Remotion once in a while.
58
- </p>
58
+ Remotion once in a while.{' '}
59
+ </div>
59
60
 
60
61
  <input
61
62
  className="w-full dark:bg-[#121212] rounded-lg border-effect border-black outline-none px-3 py-3 fontbrand text-lg box-border focus:border-brand"
@@ -0,0 +1,89 @@
1
+ import React, {useEffect, useRef, useState} from 'react';
2
+ import {isWebkit} from './IfYouKnowReact';
3
+
4
+ const icon: React.CSSProperties = {
5
+ height: 16,
6
+ marginLeft: 10,
7
+ };
8
+
9
+ export const ParameterizeAndEdit: React.FC = () => {
10
+ const ref = useRef<HTMLDivElement>(null);
11
+ const [vid, setVid] = useState('/img/editing-vp9-chrome.webm');
12
+
13
+ useEffect(() => {
14
+ if (isWebkit()) {
15
+ setVid('/img/editing-safari.mp4');
16
+ }
17
+ }, []);
18
+
19
+ return (
20
+ <div
21
+ ref={ref}
22
+ className={
23
+ 'flex flex-col lg:flex-row justify-start lg:justify-end items-start gap-6 mt-20 lg:mt-0'
24
+ }
25
+ >
26
+ <div>
27
+ <video
28
+ src={vid}
29
+ autoPlay
30
+ muted
31
+ playsInline
32
+ loop
33
+ style={{
34
+ width: 500,
35
+ maxWidth: '100%',
36
+ borderRadius: 7,
37
+ overflow: 'hidden',
38
+ }}
39
+ />
40
+ </div>
41
+ <div style={{flex: 1}} className="font-brand pt-4">
42
+ <h2 className={'fontbrand text-4xl'}>
43
+ Edit <span className="text-brand">dynamically</span>
44
+ </h2>
45
+ <p className="leading-relaxed">
46
+ Parameterize your video by passing data.
47
+ <br />
48
+ Or embed it into your app and build an interface around it.
49
+ </p>
50
+ <div className="h-4" />
51
+ <div className="leading-6">
52
+ <a
53
+ className="no-underline text-brand font-brand font-bold inline-flex flex-row items-center"
54
+ href="/docs/studio"
55
+ >
56
+ Remotion Studio{' '}
57
+ <svg
58
+ style={icon}
59
+ xmlns="http://www.w3.org/2000/svg"
60
+ viewBox="0 0 448 512"
61
+ >
62
+ <path
63
+ fill="currentColor"
64
+ d="M438.6 278.6l-160 160C272.4 444.9 264.2 448 256 448s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L338.8 288H32C14.33 288 .0016 273.7 .0016 256S14.33 224 32 224h306.8l-105.4-105.4c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l160 160C451.1 245.9 451.1 266.1 438.6 278.6z"
65
+ />
66
+ </svg>
67
+ </a>
68
+ <br />
69
+ <a
70
+ className="no-underline text-brand font-brand font-bold inline-flex flex-row items-center"
71
+ href="/player"
72
+ >
73
+ Remotion Player{' '}
74
+ <svg
75
+ style={icon}
76
+ xmlns="http://www.w3.org/2000/svg"
77
+ viewBox="0 0 448 512"
78
+ >
79
+ <path
80
+ fill="currentColor"
81
+ d="M438.6 278.6l-160 160C272.4 444.9 264.2 448 256 448s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L338.8 288H32C14.33 288 .0016 273.7 .0016 256S14.33 224 32 224h306.8l-105.4-105.4c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l160 160C451.1 245.9 451.1 266.1 438.6 278.6z"
82
+ />
83
+ </svg>
84
+ </a>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ );
89
+ };