@kolbo/kolbo-code-linux-arm64-musl 1.0.3

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 (47) hide show
  1. package/bin/kolbo +0 -0
  2. package/package.json +14 -0
  3. package/skills/frontend-design/SKILL.md +42 -0
  4. package/skills/kolbo/SKILL.md +216 -0
  5. package/skills/remotion-best-practices/SKILL.md +61 -0
  6. package/skills/remotion-best-practices/rules/3d.md +86 -0
  7. package/skills/remotion-best-practices/rules/animations.md +27 -0
  8. package/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  9. package/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  10. package/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +103 -0
  11. package/skills/remotion-best-practices/rules/assets.md +78 -0
  12. package/skills/remotion-best-practices/rules/audio-visualization.md +198 -0
  13. package/skills/remotion-best-practices/rules/audio.md +169 -0
  14. package/skills/remotion-best-practices/rules/calculate-metadata.md +134 -0
  15. package/skills/remotion-best-practices/rules/can-decode.md +81 -0
  16. package/skills/remotion-best-practices/rules/charts.md +120 -0
  17. package/skills/remotion-best-practices/rules/compositions.md +154 -0
  18. package/skills/remotion-best-practices/rules/display-captions.md +184 -0
  19. package/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  20. package/skills/remotion-best-practices/rules/ffmpeg.md +38 -0
  21. package/skills/remotion-best-practices/rules/fonts.md +152 -0
  22. package/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  23. package/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  24. package/skills/remotion-best-practices/rules/get-video-duration.md +60 -0
  25. package/skills/remotion-best-practices/rules/gifs.md +141 -0
  26. package/skills/remotion-best-practices/rules/images.md +134 -0
  27. package/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
  28. package/skills/remotion-best-practices/rules/light-leaks.md +73 -0
  29. package/skills/remotion-best-practices/rules/lottie.md +70 -0
  30. package/skills/remotion-best-practices/rules/maps.md +412 -0
  31. package/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
  32. package/skills/remotion-best-practices/rules/measuring-text.md +140 -0
  33. package/skills/remotion-best-practices/rules/parameters.md +109 -0
  34. package/skills/remotion-best-practices/rules/sequencing.md +118 -0
  35. package/skills/remotion-best-practices/rules/sfx.md +30 -0
  36. package/skills/remotion-best-practices/rules/subtitles.md +36 -0
  37. package/skills/remotion-best-practices/rules/tailwind.md +11 -0
  38. package/skills/remotion-best-practices/rules/text-animations.md +20 -0
  39. package/skills/remotion-best-practices/rules/timing.md +179 -0
  40. package/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
  41. package/skills/remotion-best-practices/rules/transitions.md +197 -0
  42. package/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
  43. package/skills/remotion-best-practices/rules/trimming.md +51 -0
  44. package/skills/remotion-best-practices/rules/videos.md +171 -0
  45. package/skills/remotion-best-practices/rules/voiceover.md +99 -0
  46. package/skills/video-production/SKILL.md +152 -0
  47. package/skills/youtube-clipper/SKILL.md +187 -0
@@ -0,0 +1,412 @@
1
+ ---
2
+ name: maps
3
+ description: Make map animations with Mapbox
4
+ metadata:
5
+ tags: map, map animation, mapbox
6
+ ---
7
+
8
+ Maps can be added to a Remotion video with Mapbox.
9
+ The [Mapbox documentation](https://docs.mapbox.com/mapbox-gl-js/api/) has the API reference.
10
+
11
+ ## Prerequisites
12
+
13
+ Mapbox and `@turf/turf` need to be installed.
14
+
15
+ Search the project for lockfiles and run the correct command depending on the package manager:
16
+
17
+ If `package-lock.json` is found, use the following command:
18
+
19
+ ```bash
20
+ npm i mapbox-gl @turf/turf @types/mapbox-gl
21
+ ```
22
+
23
+ If `bun.lock` is found, use the following command:
24
+
25
+ ```bash
26
+ bun i mapbox-gl @turf/turf @types/mapbox-gl
27
+ ```
28
+
29
+ If `yarn.lock` is found, use the following command:
30
+
31
+ ```bash
32
+ yarn add mapbox-gl @turf/turf @types/mapbox-gl
33
+ ```
34
+
35
+ If `pnpm-lock.yaml` is found, use the following command:
36
+
37
+ ```bash
38
+ pnpm i mapbox-gl @turf/turf @types/mapbox-gl
39
+ ```
40
+
41
+ The user needs to create a free Mapbox account and create an access token by visiting https://console.mapbox.com/account/access-tokens/.
42
+
43
+ The mapbox token needs to be added to the `.env` file:
44
+
45
+ ```txt title=".env"
46
+ REMOTION_MAPBOX_TOKEN==pk.your-mapbox-access-token
47
+ ```
48
+
49
+ ## Adding a map
50
+
51
+ Here is a basic example of a map in Remotion.
52
+
53
+ ```tsx
54
+ import { useEffect, useMemo, useRef, useState } from "react";
55
+ import { AbsoluteFill, useDelayRender, useVideoConfig } from "remotion";
56
+ import mapboxgl, { Map } from "mapbox-gl";
57
+
58
+ export const lineCoordinates = [
59
+ [6.56158447265625, 46.059891147620725],
60
+ [6.5691375732421875, 46.05679376154153],
61
+ [6.5842437744140625, 46.05059898938315],
62
+ [6.594886779785156, 46.04702502069337],
63
+ [6.601066589355469, 46.0460718554722],
64
+ [6.6089630126953125, 46.0365370783104],
65
+ [6.6185760498046875, 46.018420689207964],
66
+ ];
67
+
68
+ mapboxgl.accessToken = process.env.REMOTION_MAPBOX_TOKEN as string;
69
+
70
+ export const MyComposition = () => {
71
+ const ref = useRef<HTMLDivElement>(null);
72
+ const { delayRender, continueRender } = useDelayRender();
73
+
74
+ const { width, height } = useVideoConfig();
75
+ const [handle] = useState(() => delayRender("Loading map..."));
76
+ const [map, setMap] = useState<Map | null>(null);
77
+
78
+ useEffect(() => {
79
+ const _map = new Map({
80
+ container: ref.current!,
81
+ zoom: 11.53,
82
+ center: [6.5615, 46.0598],
83
+ pitch: 65,
84
+ bearing: 0,
85
+ style: "⁠mapbox://styles/mapbox/standard",
86
+ interactive: false,
87
+ fadeDuration: 0,
88
+ });
89
+
90
+ _map.on("style.load", () => {
91
+ // Hide all features from the Mapbox Standard style
92
+ const hideFeatures = [
93
+ "showRoadsAndTransit",
94
+ "showRoads",
95
+ "showTransit",
96
+ "showPedestrianRoads",
97
+ "showRoadLabels",
98
+ "showTransitLabels",
99
+ "showPlaceLabels",
100
+ "showPointOfInterestLabels",
101
+ "showPointsOfInterest",
102
+ "showAdminBoundaries",
103
+ "showLandmarkIcons",
104
+ "showLandmarkIconLabels",
105
+ "show3dObjects",
106
+ "show3dBuildings",
107
+ "show3dTrees",
108
+ "show3dLandmarks",
109
+ "show3dFacades",
110
+ ];
111
+ for (const feature of hideFeatures) {
112
+ _map.setConfigProperty("basemap", feature, false);
113
+ }
114
+
115
+ _map.setConfigProperty("basemap", "colorTrunks", "rgba(0, 0, 0, 0)");
116
+
117
+ _map.addSource("trace", {
118
+ type: "geojson",
119
+ data: {
120
+ type: "Feature",
121
+ properties: {},
122
+ geometry: {
123
+ type: "LineString",
124
+ coordinates: lineCoordinates,
125
+ },
126
+ },
127
+ });
128
+ _map.addLayer({
129
+ type: "line",
130
+ source: "trace",
131
+ id: "line",
132
+ paint: {
133
+ "line-color": "black",
134
+ "line-width": 5,
135
+ },
136
+ layout: {
137
+ "line-cap": "round",
138
+ "line-join": "round",
139
+ },
140
+ });
141
+ });
142
+
143
+ _map.on("load", () => {
144
+ continueRender(handle);
145
+ setMap(_map);
146
+ });
147
+ }, [handle, lineCoordinates]);
148
+
149
+ const style: React.CSSProperties = useMemo(
150
+ () => ({ width, height, position: "absolute" }),
151
+ [width, height],
152
+ );
153
+
154
+ return <AbsoluteFill ref={ref} style={style} />;
155
+ };
156
+ ```
157
+
158
+ The following is important in Remotion:
159
+
160
+ - Animations must be driven by `useCurrentFrame()` and animations that Mapbox brings itself should be disabled. For example, the `fadeDuration` prop should be set to `0`, `interactive` should be set to `false`, etc.
161
+ - Loading the map should be delayed using `useDelayRender()` and the map should be set to `null` until it is loaded.
162
+ - The element containing the ref MUST have an explicit width and height and `position: "absolute"`.
163
+ - Do not add a `_map.remove();` cleanup function.
164
+
165
+ ## Drawing lines
166
+
167
+ Unless I request it, do not add a glow effect to the lines.
168
+ Unless I request it, do not add additional points to the lines.
169
+
170
+ ## Map style
171
+
172
+ By default, use the `mapbox://styles/mapbox/standard` style.
173
+ Hide the labels from the base map style.
174
+
175
+ Unless I request otherwise, remove all features from the Mapbox Standard style.
176
+
177
+ ```tsx
178
+ // Hide all features from the Mapbox Standard style
179
+ const hideFeatures = [
180
+ "showRoadsAndTransit",
181
+ "showRoads",
182
+ "showTransit",
183
+ "showPedestrianRoads",
184
+ "showRoadLabels",
185
+ "showTransitLabels",
186
+ "showPlaceLabels",
187
+ "showPointOfInterestLabels",
188
+ "showPointsOfInterest",
189
+ "showAdminBoundaries",
190
+ "showLandmarkIcons",
191
+ "showLandmarkIconLabels",
192
+ "show3dObjects",
193
+ "show3dBuildings",
194
+ "show3dTrees",
195
+ "show3dLandmarks",
196
+ "show3dFacades",
197
+ ];
198
+ for (const feature of hideFeatures) {
199
+ _map.setConfigProperty("basemap", feature, false);
200
+ }
201
+
202
+ _map.setConfigProperty("basemap", "colorMotorways", "transparent");
203
+ _map.setConfigProperty("basemap", "colorRoads", "transparent");
204
+ _map.setConfigProperty("basemap", "colorTrunks", "transparent");
205
+ ```
206
+
207
+ ## Animating the camera
208
+
209
+ You can animate the camera along the line by adding a `useEffect` hook that updates the camera position based on the current frame.
210
+
211
+ Unless I ask for it, do not jump between camera angles.
212
+
213
+ ```tsx
214
+ import * as turf from "@turf/turf";
215
+ import { interpolate } from "remotion";
216
+ import { Easing } from "remotion";
217
+ import { useCurrentFrame, useVideoConfig, useDelayRender } from "remotion";
218
+
219
+ const animationDuration = 20;
220
+ const cameraAltitude = 4000;
221
+ ```
222
+
223
+ ```tsx
224
+ const frame = useCurrentFrame();
225
+ const { fps } = useVideoConfig();
226
+ const { delayRender, continueRender } = useDelayRender();
227
+
228
+ useEffect(() => {
229
+ if (!map) {
230
+ return;
231
+ }
232
+ const handle = delayRender("Moving point...");
233
+
234
+ const routeDistance = turf.length(turf.lineString(lineCoordinates));
235
+
236
+ const progress = interpolate(
237
+ frame / fps,
238
+ [0.00001, animationDuration],
239
+ [0, 1],
240
+ {
241
+ easing: Easing.inOut(Easing.sin),
242
+ extrapolateLeft: "clamp",
243
+ extrapolateRight: "clamp",
244
+ },
245
+ );
246
+
247
+ const camera = map.getFreeCameraOptions();
248
+
249
+ const alongRoute = turf.along(
250
+ turf.lineString(lineCoordinates),
251
+ routeDistance * progress,
252
+ ).geometry.coordinates;
253
+
254
+ camera.lookAtPoint({
255
+ lng: alongRoute[0],
256
+ lat: alongRoute[1],
257
+ });
258
+
259
+ map.setFreeCameraOptions(camera);
260
+ map.once("idle", () => continueRender(handle));
261
+ }, [lineCoordinates, fps, frame, handle, map]);
262
+ ```
263
+
264
+ Notes:
265
+
266
+ IMPORTANT: Keep the camera by default so north is up.
267
+ IMPORTANT: For multi-step animations, set all properties at all stages (zoom, position, line progress) to prevent jumps. Override initial values.
268
+
269
+ - The progress is clamped to a minimum value to avoid the line being empty, which can lead to turf errors
270
+ - See [Timing](./timing.md) for more options for timing.
271
+ - Consider the dimensions of the composition and make the lines thick enough and the label font size large enough to be legible for when the composition is scaled down.
272
+
273
+ ## Animating lines
274
+
275
+ ### Straight lines (linear interpolation)
276
+
277
+ To animate a line that appears straight on the map, use linear interpolation between coordinates. Do NOT use turf's `lineSliceAlong` or `along` functions, as they use geodesic (great circle) calculations which appear curved on a Mercator projection.
278
+
279
+ ```tsx
280
+ const frame = useCurrentFrame();
281
+ const { durationInFrames } = useVideoConfig();
282
+
283
+ useEffect(() => {
284
+ if (!map) return;
285
+
286
+ const animationHandle = delayRender("Animating line...");
287
+
288
+ const progress = interpolate(frame, [0, durationInFrames - 1], [0, 1], {
289
+ extrapolateLeft: "clamp",
290
+ extrapolateRight: "clamp",
291
+ easing: Easing.inOut(Easing.cubic),
292
+ });
293
+
294
+ // Linear interpolation for a straight line on the map
295
+ const start = lineCoordinates[0];
296
+ const end = lineCoordinates[1];
297
+ const currentLng = start[0] + (end[0] - start[0]) * progress;
298
+ const currentLat = start[1] + (end[1] - start[1]) * progress;
299
+
300
+ const lineData: GeoJSON.Feature<GeoJSON.LineString> = {
301
+ type: "Feature",
302
+ properties: {},
303
+ geometry: {
304
+ type: "LineString",
305
+ coordinates: [start, [currentLng, currentLat]],
306
+ },
307
+ };
308
+
309
+ const source = map.getSource("trace") as mapboxgl.GeoJSONSource;
310
+ if (source) {
311
+ source.setData(lineData);
312
+ }
313
+
314
+ map.once("idle", () => continueRender(animationHandle));
315
+ }, [frame, map, durationInFrames]);
316
+ ```
317
+
318
+ ### Curved lines (geodesic/great circle)
319
+
320
+ To animate a line that follows the geodesic (great circle) path between two points, use turf's `lineSliceAlong`. This is useful for showing flight paths or the actual shortest distance on Earth.
321
+
322
+ ```tsx
323
+ import * as turf from "@turf/turf";
324
+
325
+ const routeLine = turf.lineString(lineCoordinates);
326
+ const routeDistance = turf.length(routeLine);
327
+
328
+ const currentDistance = Math.max(0.001, routeDistance * progress);
329
+ const slicedLine = turf.lineSliceAlong(routeLine, 0, currentDistance);
330
+
331
+ const source = map.getSource("route") as mapboxgl.GeoJSONSource;
332
+ if (source) {
333
+ source.setData(slicedLine);
334
+ }
335
+ ```
336
+
337
+ ## Markers
338
+
339
+ Add labels, and markers where appropriate.
340
+
341
+ ```tsx
342
+ _map.addSource("markers", {
343
+ type: "geojson",
344
+ data: {
345
+ type: "FeatureCollection",
346
+ features: [
347
+ {
348
+ type: "Feature",
349
+ properties: { name: "Point 1" },
350
+ geometry: { type: "Point", coordinates: [-118.2437, 34.0522] },
351
+ },
352
+ ],
353
+ },
354
+ });
355
+
356
+ _map.addLayer({
357
+ id: "city-markers",
358
+ type: "circle",
359
+ source: "markers",
360
+ paint: {
361
+ "circle-radius": 40,
362
+ "circle-color": "#FF4444",
363
+ "circle-stroke-width": 4,
364
+ "circle-stroke-color": "#FFFFFF",
365
+ },
366
+ });
367
+
368
+ _map.addLayer({
369
+ id: "labels",
370
+ type: "symbol",
371
+ source: "markers",
372
+ layout: {
373
+ "text-field": ["get", "name"],
374
+ "text-font": ["DIN Pro Bold", "Arial Unicode MS Bold"],
375
+ "text-size": 50,
376
+ "text-offset": [0, 0.5],
377
+ "text-anchor": "top",
378
+ },
379
+ paint: {
380
+ "text-color": "#FFFFFF",
381
+ "text-halo-color": "#000000",
382
+ "text-halo-width": 2,
383
+ },
384
+ });
385
+ ```
386
+
387
+ Make sure they are big enough. Check the composition dimensions and scale the labels accordingly.
388
+ For a composition size of 1920x1080, the label font size should be at least 40px.
389
+
390
+ IMPORTANT: Keep the `text-offset` small enough so it is close to the marker. Consider the marker circle radius. For a circle radius of 40, this is a good offset:
391
+
392
+ ```tsx
393
+ "text-offset": [0, 0.5],
394
+ ```
395
+
396
+ ## 3D buildings
397
+
398
+ To enable 3D buildings, use the following code:
399
+
400
+ ```tsx
401
+ _map.setConfigProperty("basemap", "show3dObjects", true);
402
+ _map.setConfigProperty("basemap", "show3dLandmarks", true);
403
+ _map.setConfigProperty("basemap", "show3dBuildings", true);
404
+ ```
405
+
406
+ ## Rendering
407
+
408
+ When rendering a map animation, make sure to render with the following flags:
409
+
410
+ ```
411
+ npx remotion render --gl=angle --concurrency=1
412
+ ```
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: measuring-dom-nodes
3
+ description: Measuring DOM element dimensions in Remotion
4
+ metadata:
5
+ tags: measure, layout, dimensions, getBoundingClientRect, scale
6
+ ---
7
+
8
+ # Measuring DOM nodes in Remotion
9
+
10
+ Remotion applies a `scale()` transform to the video container, which affects values from `getBoundingClientRect()`. Use `useCurrentScale()` to get correct measurements.
11
+
12
+ ## Measuring element dimensions
13
+
14
+ ```tsx
15
+ import { useCurrentScale } from "remotion";
16
+ import { useRef, useEffect, useState } from "react";
17
+
18
+ export const MyComponent = () => {
19
+ const ref = useRef<HTMLDivElement>(null);
20
+ const scale = useCurrentScale();
21
+ const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
22
+
23
+ useEffect(() => {
24
+ if (!ref.current) return;
25
+ const rect = ref.current.getBoundingClientRect();
26
+ setDimensions({
27
+ width: rect.width / scale,
28
+ height: rect.height / scale,
29
+ });
30
+ }, [scale]);
31
+
32
+ return <div ref={ref}>Content to measure</div>;
33
+ };
34
+ ```
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: measuring-text
3
+ description: Measuring text dimensions, fitting text to containers, and checking overflow
4
+ metadata:
5
+ tags: measure, text, layout, dimensions, fitText, fillTextBox
6
+ ---
7
+
8
+ # Measuring text in Remotion
9
+
10
+ ## Prerequisites
11
+
12
+ Install @remotion/layout-utils if it is not already installed:
13
+
14
+ ```bash
15
+ npx remotion add @remotion/layout-utils
16
+ ```
17
+
18
+ ## Measuring text dimensions
19
+
20
+ Use `measureText()` to calculate the width and height of text:
21
+
22
+ ```tsx
23
+ import { measureText } from "@remotion/layout-utils";
24
+
25
+ const { width, height } = measureText({
26
+ text: "Hello World",
27
+ fontFamily: "Arial",
28
+ fontSize: 32,
29
+ fontWeight: "bold",
30
+ });
31
+ ```
32
+
33
+ Results are cached - duplicate calls return the cached result.
34
+
35
+ ## Fitting text to a width
36
+
37
+ Use `fitText()` to find the optimal font size for a container:
38
+
39
+ ```tsx
40
+ import { fitText } from "@remotion/layout-utils";
41
+
42
+ const { fontSize } = fitText({
43
+ text: "Hello World",
44
+ withinWidth: 600,
45
+ fontFamily: "Inter",
46
+ fontWeight: "bold",
47
+ });
48
+
49
+ return (
50
+ <div
51
+ style={{
52
+ fontSize: Math.min(fontSize, 80), // Cap at 80px
53
+ fontFamily: "Inter",
54
+ fontWeight: "bold",
55
+ }}
56
+ >
57
+ Hello World
58
+ </div>
59
+ );
60
+ ```
61
+
62
+ ## Checking text overflow
63
+
64
+ Use `fillTextBox()` to check if text exceeds a box:
65
+
66
+ ```tsx
67
+ import { fillTextBox } from "@remotion/layout-utils";
68
+
69
+ const box = fillTextBox({ maxBoxWidth: 400, maxLines: 3 });
70
+
71
+ const words = ["Hello", "World", "This", "is", "a", "test"];
72
+ for (const word of words) {
73
+ const { exceedsBox } = box.add({
74
+ text: word + " ",
75
+ fontFamily: "Arial",
76
+ fontSize: 24,
77
+ });
78
+ if (exceedsBox) {
79
+ // Text would overflow, handle accordingly
80
+ break;
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## Best practices
86
+
87
+ **Load fonts first:** Only call measurement functions after fonts are loaded.
88
+
89
+ ```tsx
90
+ import { loadFont } from "@remotion/google-fonts/Inter";
91
+
92
+ const { fontFamily, waitUntilDone } = loadFont("normal", {
93
+ weights: ["400"],
94
+ subsets: ["latin"],
95
+ });
96
+
97
+ waitUntilDone().then(() => {
98
+ // Now safe to measure
99
+ const { width } = measureText({
100
+ text: "Hello",
101
+ fontFamily,
102
+ fontSize: 32,
103
+ });
104
+ });
105
+ ```
106
+
107
+ **Use validateFontIsLoaded:** Catch font loading issues early:
108
+
109
+ ```tsx
110
+ measureText({
111
+ text: "Hello",
112
+ fontFamily: "MyCustomFont",
113
+ fontSize: 32,
114
+ validateFontIsLoaded: true, // Throws if font not loaded
115
+ });
116
+ ```
117
+
118
+ **Match font properties:** Use the same properties for measurement and rendering:
119
+
120
+ ```tsx
121
+ const fontStyle = {
122
+ fontFamily: "Inter",
123
+ fontSize: 32,
124
+ fontWeight: "bold" as const,
125
+ letterSpacing: "0.5px",
126
+ };
127
+
128
+ const { width } = measureText({
129
+ text: "Hello",
130
+ ...fontStyle,
131
+ });
132
+
133
+ return <div style={fontStyle}>Hello</div>;
134
+ ```
135
+
136
+ **Avoid padding and border:** Use `outline` instead of `border` to prevent layout differences:
137
+
138
+ ```tsx
139
+ <div style={{ outline: "2px solid red" }}>Text</div>
140
+ ```
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: parameters
3
+ description: Make a video parametrizable by adding a Zod schema
4
+ metadata:
5
+ tags: parameters, zod, schema
6
+ ---
7
+
8
+ To make a video parametrizable, a Zod schema can be added to a composition.
9
+
10
+ First, `zod` must be installed .
11
+
12
+ Search the project for lockfiles and run the correct command depending on the package manager:
13
+
14
+ If `package-lock.json` is found, use the following command:
15
+
16
+ ```bash
17
+ npm i zod
18
+ ```
19
+
20
+ If `bun.lockb` is found, use the following command:
21
+
22
+ ```bash
23
+ bun i zod
24
+ ```
25
+
26
+ If `yarn.lock` is found, use the following command:
27
+
28
+ ```bash
29
+ yarn add zod
30
+ ```
31
+
32
+ If `pnpm-lock.yaml` is found, use the following command:
33
+
34
+ ```bash
35
+ pnpm i zod
36
+ ```
37
+
38
+ Then, a Zod schema can be defined alongside the component:
39
+
40
+ ```tsx title="src/MyComposition.tsx"
41
+ import { z } from "zod";
42
+
43
+ export const MyCompositionSchema = z.object({
44
+ title: z.string(),
45
+ });
46
+
47
+ const MyComponent: React.FC<z.infer<typeof MyCompositionSchema>> = () => {
48
+ return (
49
+ <div>
50
+ <h1>{props.title}</h1>
51
+ </div>
52
+ );
53
+ };
54
+ ```
55
+
56
+ In the root file, the schema can be passed to the composition:
57
+
58
+ ```tsx title="src/Root.tsx"
59
+ import { Composition } from "remotion";
60
+ import { MycComponent, MyCompositionSchema } from "./MyComposition";
61
+
62
+ export const RemotionRoot = () => {
63
+ return (
64
+ <Composition
65
+ id="MyComposition"
66
+ component={MyComponent}
67
+ durationInFrames={100}
68
+ fps={30}
69
+ width={1080}
70
+ height={1080}
71
+ defaultProps={{ title: "Hello World" }}
72
+ schema={MyCompositionSchema}
73
+ />
74
+ );
75
+ };
76
+ ```
77
+
78
+ Now, the user can edit the parameter visually in the sidebar.
79
+
80
+ All schemas that are supported by Zod are supported by Remotion.
81
+
82
+ Remotion requires that the top-level type is a z.object(), because the collection of props of a React component is always an object.
83
+
84
+ ## Color picker
85
+
86
+ For adding a color picker, use `zColor()` from `@remotion/zod-types`.
87
+
88
+ If it is not installed, use the following command:
89
+
90
+ ```bash
91
+ npx remotion add @remotion/zod-types # If project uses npm
92
+ bunx remotion add @remotion/zod-types # If project uses bun
93
+ yarn remotion add @remotion/zod-types # If project uses yarn
94
+ pnpm exec remotion add @remotion/zod-types # If project uses pnpm
95
+ ```
96
+
97
+ Then import `zColor` from `@remotion/zod-types`:
98
+
99
+ ```tsx
100
+ import { zColor } from "@remotion/zod-types";
101
+ ```
102
+
103
+ Then use it in the schema:
104
+
105
+ ```tsx
106
+ export const MyCompositionSchema = z.object({
107
+ color: zColor(),
108
+ });
109
+ ```