Add remotion best practices skill bundle#648
Add remotion best practices skill bundle#648shaunak99 wants to merge 1 commit intotruffle-ai:mainfrom
Conversation
|
Someone is attempting to deploy a commit to the Shaunak's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughIntroduces comprehensive Remotion best-practices skill documentation, including a skill definition file, metadata, and 30+ guides covering core concepts, media handling, text animations, captions, advanced features, and measurement utilities, plus three example components demonstrating bar charts and text animations. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 19
🧹 Nitpick comments (5)
.agents/skills/remotion-best-practices/rules/charts.md (1)
14-14: Minor: Hyphenate "third-party".📝 Suggested fix
-Disable all animations by third party libraries. +Disable all animations by third-party libraries.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/remotion-best-practices/rules/charts.md at line 14, Update the rule text that currently reads "Disable all animations by third party libraries." to hyphenate "third-party" so it reads "Disable all animations by third-party libraries."; locate the exact sentence in the charts.md content block and replace the non-hyphenated phrase to ensure grammar consistency across the rules..agents/skills/remotion-best-practices/rules/tailwind.md (1)
4-5: Consider adding metadata tags for consistency.Other rule files in this PR include
tagsin the metadata section (e.g.,tags: measure, layout, dimensionsin measuring-dom-nodes.md). Adding relevant tags here would improve discoverability and maintain consistency across the skill bundle.📝 Suggested fix
metadata: + tags: tailwind, css, styling, classes ---🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/remotion-best-practices/rules/tailwind.md around lines 4 - 5, The metadata block currently only contains "metadata:" with no tags; add a tags field to that metadata (e.g., tags: tailwind, css, styling, best-practices) so the rule file matches other rule files' metadata structure; update the metadata section in .agents/skills/remotion-best-practices/rules/tailwind.md by adding a tags entry alongside the existing metadata key so the file is discoverable and consistent with files like measuring-dom-nodes.md..agents/skills/remotion-best-practices/rules/lottie.md (1)
4-5: Metadata inconsistency with other rule files.This file uses
category: Animationin the metadata section, while all other rule files in this PR usetags:instead. Consider usingtags:for consistency across the skill bundle.🔄 Proposed fix for consistency
metadata: - category: Animation + tags: lottie, animation, json, after-effects🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/remotion-best-practices/rules/lottie.md around lines 4 - 5, The front-matter in this rule uses the key "category: Animation" which is inconsistent with the rest of the bundle that uses "tags:". Replace the "category: Animation" entry in the file's metadata block with a "tags:" key (e.g., tags: ["Animation"]) so the YAML front-matter matches other rule files; ensure quotes/array formatting follows the existing files' style and keep the rest of the metadata unchanged..agents/skills/remotion-best-practices/rules/images.md (1)
36-44: Optional: Add language identifier to fenced code block.The fenced code block showing the directory structure doesn't specify a language. While this is flagged by markdownlint, it's intentional since this is a directory tree visualization rather than code.
📝 Optional fix to satisfy linter
-``` +```text my-video/ ├─ public/ │ ├─ logo.png │ ├─ avatar.jpg │ └─ icon.svg ├─ src/ ├─ package.json</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/images.md around lines 36 - 44,
The fenced code block that displays the directory tree (starting with
"my-video/" and the nested "public/" entries) lacks a language identifier which
triggers markdownlint; update that fenced block in images.md to include a
language tag such as "text" (i.e., change the openingtotext) so the
tree is treated as plain text and the linter warning is resolved while
preserving the directory layout.</details> </blockquote></details> <details> <summary>.agents/skills/remotion-best-practices/rules/fonts.md (1)</summary><blockquote> `127-130`: **Prefer module-scope font loading over component-body calls.** This wording is looser than Remotion’s own guidance, which recommends loading fonts in one module and reusing the exports. Suggest removing “at the top level of your component” here; otherwise the doc nudges readers toward repeated `loadFont()` calls on rerenders. ([remotion.dev](https://www.remotion.dev/docs/google-fonts)) <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/remotion-best-practices/rules/fonts.md around lines 127 - 130, The phrasing in the "Using in components" section currently encourages calling loadFont() "at the top level of your component", which can nudge readers to call loadFont() on every render; update the text to align with Remotion guidance by removing the "at the top level of your component" clause and instead recommend loading fonts once in a dedicated module and reusing exported font objects (referencing loadFont() and the pattern of exporting imports), so the doc explicitly advises module-scope font loading and reuse rather than component-body calls. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.agents/skills/remotion-best-practices/_meta.json:
- Around line 1-11: Delete the unused metadata file named _meta.json (the JSON
object containing owner, slug, displayName, latest, history) from the
remotion-best-practices skill directory since the skill discovery only uses
SKILL.md and no code reads this metadata; remove the file and any imports or
references to _meta.json if present (search for "_meta.json" or
"remotion-best-practices" references) to ensure there are no dangling
references.In @.agents/skills/remotion-best-practices/rules/animations.md:
- Around line 11-26: The example FadeIn component imports useCurrentFrame but
omits useVideoConfig and interpolate, causing runtime errors; update the import
statement for the component (the top of the snippet using useCurrentFrame and
FadeIn) to also import useVideoConfig and interpolate from "remotion" so all
referenced symbols (useCurrentFrame, useVideoConfig, interpolate, FadeIn) are
declared.In @.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx:
- Around line 156-166: The spring() call used to animate bar heights can exceed
1, causing bars to overshoot; update the spring config in the block that creates
progress (the spring(...) call) to include overshootClamping: true or clamp the
returned progress value before using it (e.g., bound progress to [0,1]) and then
use that clamped value when computing barHeight and passing progress into the
Bar component so bars never render taller than the dataset-implied height.In @.agents/skills/remotion-best-practices/rules/audio.md:
- Around line 157-172: The docs for toneFrequency on the component omit
that the prop must be a static value while the element is mounted;
update the text to state that toneFrequency cannot be animated or changed after
mount (it is SSR-only) and add the suggested workaround: to change pitch over
time split the audio into multiple instances each with a different
static toneFrequency. Mention the exact symbol toneFrequency and the
component so readers can find the guidance easily.In @.agents/skills/remotion-best-practices/rules/can-decode.md:
- Around line 67-74: The example for canDecodeBlob is incomplete—replace the
placeholder comment with the same validation logic used in the earlier example
(e.g., create the Input with ALL_FORMATS and new BlobSource(blob), then attempt
the validation/decode call and return a boolean based on success), handling
errors and returning false on failure; specifically update the canDecodeBlob
implementation (which uses Input, ALL_FORMATS, and BlobSource) to perform the
actual validation/try-decode flow and return true/false rather than leaving it
as a skeleton.In @.agents/skills/remotion-best-practices/rules/charts.md:
- Line 20: Update the broken asset reference and fix the typo: replace the
incorrect path string "assets/charts/bar-chart.tsx" with the actual asset
filename "assets/charts-bar-chart.tsx" and correct the misspelled word
"implmentation" to "implementation" in the charts.md content so the link and
wording are accurate.In @.agents/skills/remotion-best-practices/rules/compositions.md:
- Line 146: Update the documentation for calculateMetadata to clarify that while
it runs once before a standard render, Remotion Studio will re-run
calculateMetadata whenever props change; mention the abortSignal parameter
should be used to cancel stale async work (e.g., fetches) when props update or
the run is aborted. Reference the calculateMetadata function and the abortSignal
parameter in the text so readers know where to implement cancellation logic.- Line 57: The guidance sentence "Use
typedeclarations for props rather than
interfaceto ensuredefaultPropstype safety." is incorrect; update the
wording in compositions.md to state that bothtypealiases andinterfaces
are fine and that the key is validating thedefaultPropsobject with
satisfies(mentiondefaultPropsandsatisfiesexplicitly) so readers know
to usesatisfiesto check the object literal instead of preferringtypeover
interface.In @.agents/skills/remotion-best-practices/rules/extract-frames.md:
- Around line 89-99: The callback examples in extractFrames (the for await
(using videoSample of sink.samplesAtTimestamps(timestamps)) loop and the
onVideoSample callback) re-wrap the same object with a second using (e.g., using
frame = sample), causing a double-dispose; remove the extra re-owning inside the
callbacks and use the provided videoSample directly (so do not create a new
using/frame variable), and apply the same removal to the other callback examples
referenced (the blocks around lines 174-180 and 213-218) to keep resource
ownership consistent for extractFrames, sink.samplesAtTimestamps, videoSample,
and onVideoSample.- Around line 14-16: The README claim "copy-pasteable into any project" is
misleading because the snippet relies on theusingdeclaration which requires
TypeScript 5.2+ and runtime support/polyfills; either update the documentation
in extract-frames.md to explicitly state the prerequisite (TypeScript >=5.2,
tsconfig setting and any runtime polyfill), or replace theusing-based
resource management in the example with a portable try/finally variant that
explicitly disposes resources (i.e., removeusingand wrap resource creation
in try { ... } finally { resource.dispose(); }), ensuring all references to
usingin the snippet are updated accordingly.In @.agents/skills/remotion-best-practices/rules/get-video-dimensions.md:
- Around line 47-59: The local-file example using Input and FileSource calls
getPrimaryVideoTrack() and then dereferences
videoTrack.displayWidth/displayHeight without checking for null; add the same
null guard as in the main example (check if videoTrack is falsy and
handle/return early) before accessing displayWidth and displayHeight to avoid
runtime crashes when getPrimaryVideoTrack() returns null.In @.agents/skills/remotion-best-practices/rules/sequencing.md:
- Around line 10-21: The example is missing the import for useVideoConfig;
update the example's imports to include useVideoConfig from "remotion" so the
call to useVideoConfig() works; locate the top of the snippet where Sequence is
imported (and where Title/Subtitle components are referenced) and add
useVideoConfig to that import statement (ensuring the symbols Sequence and
useVideoConfig are both imported from "remotion").In @.agents/skills/remotion-best-practices/rules/text-animations.md:
- Line 5: In the front-matter tags line, remove the accidental token "ken" so
the tag reads "highlighter" (fix the "highlighter ken" typo) and in the body
replace the duplicated phrase "for an example for how" with "for an example of
how" (or "for an example showing how") to correct the copy-edit slip; make the
same two fixes in the other occurrence noted ("20-20").In @.agents/skills/remotion-best-practices/rules/timing.md:
- Line 161: Fix the grammar in the sentence on the noted rule line: change
"Convexities and curves need be combined for an easing function:" to
"Convexities and curves need to be combined for an easing function:" so the
phrase includes the missing "to"; update the text in timing.md where that
sentence appears.- Around line 74-79: The example mixes two timing mechanisms and references an
undefined ENTRANCE_DELAY; pick one approach and make it consistent. Either
remove the delay parameter and compute frame by subtracting a defined
ENTRANCE_DELAY (define ENTRANCE_DELAY constant and use spring({ frame: frame -
ENTRANCE_DELAY, fps })) or keep the original frame and only use the delay option
(remove frame subtraction and use spring({ frame, fps, delay: 20 })); update the
entrance call accordingly and ensure ENTRANCE_DELAY is defined if you choose the
subtraction approach.In @.agents/skills/remotion-best-practices/rules/trimming.md:
- Around line 15-19: The issue is that useVideoConfig() returns an object but
the code assigns it to fps, breaking arithmetic; update the code to destructure
fps from useVideoConfig (e.g., const { fps } = useVideoConfig()) and then use
that fps value in the Sequence from calculations (references: useVideoConfig,
fps variable, Sequence component using from={-0.5 * fps} and other
multiplications like 1.5 * fps). Ensure any other uses of fps in this file
reference the destructured fps value.In @.agents/skills/remotion-best-practices/rules/videos.md:
- Around line 41-52: The text incorrectly says "Values are in seconds"; update
the description to state that trimBefore and trimAfter accept frame counts
(frames), not seconds, and clarify usage by referencing useVideoConfig() and fps
(e.g., trimBefore={2 * fps} means 2 seconds at 30fps); ensure the documentation
for the Video component's trimBefore and trimAfter props (and the example using
staticFile and fps) remains consistent with the frames-based unit.- Around line 156-171: The docs imply toneFrequency can be changed reactively,
but Remotion's audio graph requires toneFrequency to be constant for the
lifetime of a mountedIn @.agents/skills/remotion-best-practices/SKILL.md:
- Line 10: Replace the awkward phrase "Use this skills" in SKILL.md with correct
grammar; change the usage guidance line that currently reads "Use this skills
whenever you are dealing with Remotion code to obtain the domain-specific
knowledge." to either "Use this skill whenever you are dealing with Remotion
code to obtain the domain-specific knowledge." (singular) or "Use these skills
whenever you are dealing with Remotion code to obtain the domain-specific
knowledge." (plural) to match the intended meaning.
Nitpick comments:
In @.agents/skills/remotion-best-practices/rules/charts.md:
- Line 14: Update the rule text that currently reads "Disable all animations by
third party libraries." to hyphenate "third-party" so it reads "Disable all
animations by third-party libraries."; locate the exact sentence in the
charts.md content block and replace the non-hyphenated phrase to ensure grammar
consistency across the rules.In @.agents/skills/remotion-best-practices/rules/fonts.md:
- Around line 127-130: The phrasing in the "Using in components" section
currently encourages calling loadFont() "at the top level of your component",
which can nudge readers to call loadFont() on every render; update the text to
align with Remotion guidance by removing the "at the top level of your
component" clause and instead recommend loading fonts once in a dedicated module
and reusing exported font objects (referencing loadFont() and the pattern of
exporting imports), so the doc explicitly advises module-scope font loading and
reuse rather than component-body calls.In @.agents/skills/remotion-best-practices/rules/images.md:
- Around line 36-44: The fenced code block that displays the directory tree
(starting with "my-video/" and the nested "public/" entries) lacks a language
identifier which triggers markdownlint; update that fenced block in images.md to
include a language tag such as "text" (i.e., change the openingtotext)
so the tree is treated as plain text and the linter warning is resolved while
preserving the directory layout.In @.agents/skills/remotion-best-practices/rules/lottie.md:
- Around line 4-5: The front-matter in this rule uses the key "category:
Animation" which is inconsistent with the rest of the bundle that uses "tags:".
Replace the "category: Animation" entry in the file's metadata block with a
"tags:" key (e.g., tags: ["Animation"]) so the YAML front-matter matches other
rule files; ensure quotes/array formatting follows the existing files' style and
keep the rest of the metadata unchanged.In @.agents/skills/remotion-best-practices/rules/tailwind.md:
- Around line 4-5: The metadata block currently only contains "metadata:" with
no tags; add a tags field to that metadata (e.g., tags: tailwind, css, styling,
best-practices) so the rule file matches other rule files' metadata structure;
update the metadata section in
.agents/skills/remotion-best-practices/rules/tailwind.md by adding a tags entry
alongside the existing metadata key so the file is discoverable and consistent
with files like measuring-dom-nodes.md.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Organization UI **Review profile**: CHILL **Plan**: Pro **Run ID**: `2dc961fb-ee7a-4656-aab8-ab820e050e86` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between daaa4a169637c7decba80840901158df64642d0f and 3569af9f9f8a3ca3c8c679deac4b67cc8adcbac3. </details> <details> <summary>📒 Files selected for processing (33)</summary> * `.agents/skills/remotion-best-practices/SKILL.md` * `.agents/skills/remotion-best-practices/_meta.json` * `.agents/skills/remotion-best-practices/rules/3d.md` * `.agents/skills/remotion-best-practices/rules/animations.md` * `.agents/skills/remotion-best-practices/rules/assets.md` * `.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx` * `.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx` * `.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx` * `.agents/skills/remotion-best-practices/rules/audio.md` * `.agents/skills/remotion-best-practices/rules/calculate-metadata.md` * `.agents/skills/remotion-best-practices/rules/can-decode.md` * `.agents/skills/remotion-best-practices/rules/charts.md` * `.agents/skills/remotion-best-practices/rules/compositions.md` * `.agents/skills/remotion-best-practices/rules/display-captions.md` * `.agents/skills/remotion-best-practices/rules/extract-frames.md` * `.agents/skills/remotion-best-practices/rules/fonts.md` * `.agents/skills/remotion-best-practices/rules/get-audio-duration.md` * `.agents/skills/remotion-best-practices/rules/get-video-dimensions.md` * `.agents/skills/remotion-best-practices/rules/get-video-duration.md` * `.agents/skills/remotion-best-practices/rules/gifs.md` * `.agents/skills/remotion-best-practices/rules/images.md` * `.agents/skills/remotion-best-practices/rules/import-srt-captions.md` * `.agents/skills/remotion-best-practices/rules/lottie.md` * `.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md` * `.agents/skills/remotion-best-practices/rules/measuring-text.md` * `.agents/skills/remotion-best-practices/rules/sequencing.md` * `.agents/skills/remotion-best-practices/rules/tailwind.md` * `.agents/skills/remotion-best-practices/rules/text-animations.md` * `.agents/skills/remotion-best-practices/rules/timing.md` * `.agents/skills/remotion-best-practices/rules/transcribe-captions.md` * `.agents/skills/remotion-best-practices/rules/transitions.md` * `.agents/skills/remotion-best-practices/rules/trimming.md` * `.agents/skills/remotion-best-practices/rules/videos.md` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| { | ||
| "owner": "am-will", | ||
| "slug": "remotion-best-practices", | ||
| "displayName": "Remotion Best Practices", | ||
| "latest": { | ||
| "version": "1.0.0", | ||
| "publishedAt": 1769024303669, | ||
| "commit": "https://github.com/clawdbot/skills/commit/cf14c4a145107299b14a4eba382d442800fd4666" | ||
| }, | ||
| "history": [] | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for any code that reads _meta.json from skill directories
rg -n "_meta\.json" --type ts --type jsRepository: truffle-ai/dexto
Length of output: 42
🏁 Script executed:
# Find and inspect the discover-skills file
fd -t f "discover-skills" --type tsRepository: truffle-ai/dexto
Length of output: 229
🏁 Script executed:
# Check what files are in the skill directories to understand the pattern
find .agents/skills -type f -name "*.md" -o -name "*.json" | head -20Repository: truffle-ai/dexto
Length of output: 1184
🏁 Script executed:
# Search broadly for any code that loads or validates skill metadata
rg -i "skill.*meta|meta.*skill" --type ts --type js -A 2 -B 2Repository: truffle-ai/dexto
Length of output: 42
🏁 Script executed:
# Check if _meta.json follows any naming convention or is referenced in any config files
rg "_meta" --type json --type md --type yaml --type yml -A 1 -B 1Repository: truffle-ai/dexto
Length of output: 87
🏁 Script executed:
# Find discover-skills file
fd -type f discover-skillsRepository: truffle-ai/dexto
Length of output: 230
🏁 Script executed:
# Search for "SKILL.md" to understand skill discovery patterns
rg "SKILL\.md" -A 3 -B 3Repository: truffle-ai/dexto
Length of output: 35363
🏁 Script executed:
# Look for any skill loading or discovery logic
rg -i "skills.*load|discover.*skill|skill.*discover" -A 2 -B 2Repository: truffle-ai/dexto
Length of output: 18699
🏁 Script executed:
# Check if there are any configuration files that define how skills are loaded
fd -type f -name "*.config.*" -o -name "*config.ts" -o -name "*config.js"Repository: truffle-ai/dexto
Length of output: 230
Remove unused _meta.json metadata file.
This file is not consumed by the skill discovery system, which only recognizes skill directories containing SKILL.md. No code in the codebase reads or validates this metadata. Other skills in the repository (automations, create-skill) don't include similar metadata files.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/_meta.json around lines 1 - 11,
Delete the unused metadata file named _meta.json (the JSON object containing
owner, slug, displayName, latest, history) from the remotion-best-practices
skill directory since the skill discovery only uses SKILL.md and no code reads
this metadata; remove the file and any imports or references to _meta.json if
present (search for "_meta.json" or "remotion-best-practices" references) to
ensure there are no dangling references.
| ```tsx | ||
| import { useCurrentFrame } from "remotion"; | ||
|
|
||
| export const FadeIn = () => { | ||
| const frame = useCurrentFrame(); | ||
| const { fps } = useVideoConfig(); | ||
|
|
||
| const opacity = interpolate(frame, [0, 2 * fps], [0, 1], { | ||
| extrapolateRight: 'clamp', | ||
| }); | ||
|
|
||
| return ( | ||
| <div style={{ opacity }}>Hello World!</div> | ||
| ); | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
Missing imports in the code example.
The example uses useVideoConfig and interpolate without importing them, which will cause runtime errors.
🔧 Proposed fix to add missing imports
-import { useCurrentFrame } from "remotion";
+import { useCurrentFrame, useVideoConfig, interpolate } from "remotion";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/animations.md around lines 11 -
26, The example FadeIn component imports useCurrentFrame but omits
useVideoConfig and interpolate, causing runtime errors; update the import
statement for the component (the top of the snippet using useCurrentFrame and
FadeIn) to also import useVideoConfig and interpolate from "remotion" so all
referenced symbols (useCurrentFrame, useVideoConfig, interpolate, FadeIn) are
declared.
| const progress = spring({ | ||
| frame: frame - i * 5 - 10, | ||
| fps, | ||
| config: {damping: 18, stiffness: 80}, | ||
| }); | ||
|
|
||
| const barHeight = | ||
| ((item.price - minPrice) / priceRange) * chartHeight * progress; | ||
|
|
||
| return ( | ||
| <Bar key={item.month} height={barHeight} progress={progress} /> |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Remotion, can spring() return values greater than 1 unless the result is clamped or overshoot clamping is enabled?
💡 Result:
Yes. In Remotion, spring() can overshoot its to value (default to: 1), so it may return values greater than 1 when overshootClamping is false (the default). Enabling config.overshootClamping: true prevents this by returning to whenever the animation would go past it. [1]
Clamp the spring progress to prevent chart from overshooting dataset values.
In Remotion, spring() can return values greater than 1 by default (when overshootClamping is not enabled). This means the bar height will briefly encode prices above your dataset, which is inappropriate for a best-practices example.
Either clamp the progress value before using it, or add overshootClamping: true to the spring config:
Option 1: Clamp progress
const progress = spring({
frame: frame - i * 5 - 10,
fps,
config: {damping: 18, stiffness: 80},
});
+const clampedProgress = Math.max(0, Math.min(progress, 1));
const barHeight =
- ((item.price - minPrice) / priceRange) * chartHeight * progress;
+ ((item.price - minPrice) / priceRange) * chartHeight * clampedProgress;
return (
- <Bar key={item.month} height={barHeight} progress={progress} />
+ <Bar key={item.month} height={barHeight} progress={clampedProgress} />
);Option 2: Enable overshootClamping (more idiomatic)
const progress = spring({
frame: frame - i * 5 - 10,
fps,
config: {damping: 18, stiffness: 80, overshootClamping: true},
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const progress = spring({ | |
| frame: frame - i * 5 - 10, | |
| fps, | |
| config: {damping: 18, stiffness: 80}, | |
| }); | |
| const barHeight = | |
| ((item.price - minPrice) / priceRange) * chartHeight * progress; | |
| return ( | |
| <Bar key={item.month} height={barHeight} progress={progress} /> | |
| const progress = spring({ | |
| frame: frame - i * 5 - 10, | |
| fps, | |
| config: {damping: 18, stiffness: 80, overshootClamping: true}, | |
| }); | |
| const barHeight = | |
| ((item.price - minPrice) / priceRange) * chartHeight * progress; | |
| return ( | |
| <Bar key={item.month} height={barHeight} progress={progress} /> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx
around lines 156 - 166, The spring() call used to animate bar heights can exceed
1, causing bars to overshoot; update the spring config in the block that creates
progress (the spring(...) call) to include overshootClamping: true or clamp the
returned progress value before using it (e.g., bound progress to [0,1]) and then
use that clamped value when computing barHeight and passing progress into the
Bar component so bars never render taller than the dataset-implied height.
| ## Pitch | ||
|
|
||
| Use `toneFrequency` to adjust the pitch without affecting speed. Values range from 0.01 to 2: | ||
|
|
||
| ```tsx | ||
| <Audio | ||
| src={staticFile("audio.mp3")} | ||
| toneFrequency={1.5} // Higher pitch | ||
| /> | ||
| <Audio | ||
| src={staticFile("audio.mp3")} | ||
| toneFrequency={0.8} // Lower pitch | ||
| /> | ||
| ``` | ||
|
|
||
| Pitch shifting only works during server-side rendering, not in the Remotion Studio preview or in the `<Player />`. |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Remotion Audio toneFrequency static animatable constraint
💡 Result:
In Remotion’s new @remotion/media <Audio> component, toneFrequency is not animatable (it must be static while the tag is mounted):
toneFrequencyaccepts a number between0.01and2(1= original pitch).- Constraint: “The value must stay the same across the entire time the video tag is mounted.” So you can’t pass a frame-based callback / change it over time.
- It only works in server-side rendering (not in Studio preview / client-side rendering). [1]
If you need pitch changes over time, the usual workaround is to split the audio into multiple <Audio> instances (trim/sequence them) and give each segment a different static toneFrequency. [1]
Type-wise, toneFrequency is just number on the props (no function type), reinforcing that it’s intended to be static. [2]
Sources: [1], [2]
🏁 Script executed:
# Check the current state of the audio.md file to understand context
cat -n .agents/skills/remotion-best-practices/rules/audio.md | sed -n '150,180p'Repository: truffle-ai/dexto
Length of output: 778
🏁 Script executed:
# Search for toneFrequency mentions in the codebase
rg "toneFrequency" --type md --type tsx --type ts -B 2 -A 2Repository: truffle-ai/dexto
Length of output: 87
Add the static-value constraint for toneFrequency.
The current guidance mentions the valid range and SSR-only support, but not that toneFrequency must remain constant while the <Audio> tag is mounted. Without this clarification, readers may mistakenly attempt to animate toneFrequency, leading to broken implementations. If pitch changes over time are needed, the workaround is to split audio into multiple <Audio> instances with different static toneFrequency values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/audio.md around lines 157 -
172, The docs for toneFrequency on the <Audio> component omit that the prop must
be a static value while the <Audio> element is mounted; update the text to state
that toneFrequency cannot be animated or changed after mount (it is SSR-only)
and add the suggested workaround: to change pitch over time split the audio into
multiple <Audio> instances each with a different static toneFrequency. Mention
the exact symbol toneFrequency and the <Audio> component so readers can find the
guidance easily.
| export const canDecodeBlob = async (blob: Blob) => { | ||
| const input = new Input({ | ||
| formats: ALL_FORMATS, | ||
| source: new BlobSource(blob), | ||
| }); | ||
|
|
||
| // Same validation logic as above | ||
| }; |
There was a problem hiding this comment.
Incomplete function body in canDecodeBlob example.
The canDecodeBlob function only contains a comment placeholder without the actual validation logic. Users copy-pasting this code will get a function that does nothing. Consider including the full implementation or explicitly noting this is a skeleton.
📝 Suggested fix with full implementation
export const canDecodeBlob = async (blob: Blob) => {
const input = new Input({
formats: ALL_FORMATS,
source: new BlobSource(blob),
});
- // Same validation logic as above
+ try {
+ await input.getFormat();
+ } catch {
+ return false;
+ }
+
+ const videoTrack = await input.getPrimaryVideoTrack();
+ if (videoTrack && !(await videoTrack.canDecode())) {
+ return false;
+ }
+
+ const audioTrack = await input.getPrimaryAudioTrack();
+ if (audioTrack && !(await audioTrack.canDecode())) {
+ return false;
+ }
+
+ return true;
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const canDecodeBlob = async (blob: Blob) => { | |
| const input = new Input({ | |
| formats: ALL_FORMATS, | |
| source: new BlobSource(blob), | |
| }); | |
| // Same validation logic as above | |
| }; | |
| export const canDecodeBlob = async (blob: Blob) => { | |
| const input = new Input({ | |
| formats: ALL_FORMATS, | |
| source: new BlobSource(blob), | |
| }); | |
| try { | |
| await input.getFormat(); | |
| } catch { | |
| return false; | |
| } | |
| const videoTrack = await input.getPrimaryVideoTrack(); | |
| if (videoTrack && !(await videoTrack.canDecode())) { | |
| return false; | |
| } | |
| const audioTrack = await input.getPrimaryAudioTrack(); | |
| if (audioTrack && !(await audioTrack.canDecode())) { | |
| return false; | |
| } | |
| return true; | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/can-decode.md around lines 67 -
74, The example for canDecodeBlob is incomplete—replace the placeholder comment
with the same validation logic used in the earlier example (e.g., create the
Input with ALL_FORMATS and new BlobSource(blob), then attempt the
validation/decode call and return a boolean based on success), handling errors
and returning false on failure; specifically update the canDecodeBlob
implementation (which uses Input, ALL_FORMATS, and BlobSource) to perform the
actual validation/try-decode flow and return true/false rather than leaving it
as a skeleton.
| - `Easing.exp` | ||
| - `Easing.circle` | ||
|
|
||
| Convexities and curves need be combined for an easing function: |
There was a problem hiding this comment.
Fix grammar.
"Convexities and curves need be combined" should be "need to be combined".
✏️ Proposed fix
-Convexities and curves need be combined for an easing function:
+Convexities and curves need to be combined for an easing function:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Convexities and curves need be combined for an easing function: | |
| Convexities and curves need to be combined for an easing function: |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/timing.md at line 161, Fix the
grammar in the sentence on the noted rule line: change "Convexities and curves
need be combined for an easing function:" to "Convexities and curves need to be
combined for an easing function:" so the phrase includes the missing "to";
update the text in timing.md where that sentence appears.
| import { Sequence, useVideoConfig } from "remotion"; | ||
|
|
||
| const fps = useVideoConfig(); | ||
|
|
||
| <Sequence from={-0.5 * fps}> |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Remotion useVideoConfig() return type documentation
💡 Result:
useVideoConfig() is typed to return VideoConfig.
- Docs: Remotion’s
useVideoConfig()page lists the returned fields (width,height,fps,durationInFrames,id,defaultProps,props,defaultCodec, etc.). [1] - TypeScript signature (source):
export const useVideoConfig = (): VideoConfig => { ... }[2] VideoConfigtype definition (fromremotionpackage types): [3]width: numberheight: numberfps: numberdurationInFrames: numberid: stringdefaultProps: Record<string, unknown>props: Record<string, unknown>defaultCodec: Codec | nulldefaultOutName: string | nulldefaultVideoImageFormat: VideoImageFormat | nulldefaultPixelFormat: PixelFormat | null
Sources: [1] [2] [3]
🏁 Script executed:
cat -n ".agents/skills/remotion-best-practices/rules/trimming.md" | head -50Repository: truffle-ai/dexto
Length of output: 1513
🏁 Script executed:
cat -n ".agents/skills/remotion-best-practices/rules/trimming.md" | tail -n +23Repository: truffle-ai/dexto
Length of output: 975
Destructure fps from useVideoConfig().
useVideoConfig() returns an object containing properties like fps, width, and height. The code should destructure fps from the returned object: const {fps} = useVideoConfig();. As written, const fps = useVideoConfig(); assigns the entire object to fps, breaking the arithmetic operations on lines 19 and 33 (-0.5 * fps and 1.5 * fps).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/trimming.md around lines 15 -
19, The issue is that useVideoConfig() returns an object but the code assigns it
to fps, breaking arithmetic; update the code to destructure fps from
useVideoConfig (e.g., const { fps } = useVideoConfig()) and then use that fps
value in the Sequence from calculations (references: useVideoConfig, fps
variable, Sequence component using from={-0.5 * fps} and other multiplications
like 1.5 * fps). Ensure any other uses of fps in this file reference the
destructured fps value.
| Use `trimBefore` and `trimAfter` to remove portions of the video. Values are in seconds. | ||
|
|
||
| ```tsx | ||
| const { fps } = useVideoConfig(); | ||
|
|
||
| return ( | ||
| <Video | ||
| src={staticFile("video.mp4")} | ||
| trimBefore={2 * fps} // Skip the first 2 seconds | ||
| trimAfter={10 * fps} // End at the 10 second mark | ||
| /> | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .agents/skills/remotion-best-practices/rules/videos.md | sed -n '41,52p'Repository: truffle-ai/dexto
Length of output: 444
🌐 Web query:
Remotion @remotion/media Video component trimBefore trimAfter documentation
💡 Result:
For @remotion/media, the trimming props are documented on the <Video> component page:
- Docs page:
@remotion/media→<Video>(/docs/media/video) trimBefore?: number: trims frames from the start of the source video (left side). Example: at 30fps,trimBefore={60}skips the first 2 seconds.trimAfter?: number: trims frames from the end of the source video (right side). Example:trimBefore={60} trimAfter={120}plays only the 2s segment from 00:02 to 00:04. For exact behavior, Remotion points to the “Order of operations” doc. [1]
Related behavior (“Order of operations”): trimming is applied before offsetting with <Sequence> and before stretching with playbackRate (applies to <Video> as well). [2]
Sources: [1] (remotion.dev) [2] (remotion.dev)
Citations:
- 1: https://www.remotion.dev/docs/media/video
- 2: https://www.remotion.dev/docs/audio/order-of-operations
Correct the trim unit description.
trimBefore and trimAfter accept frame counts, not seconds. The Remotion <Video> documentation explicitly defines these props in frames (e.g., trimBefore={60} at 30fps skips the first 2 seconds). Line 41 incorrectly states "Values are in seconds," which contradicts the code example that correctly multiplies by fps. Readers following the text description instead of the example will trim by the wrong amount.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/videos.md around lines 41 - 52,
The text incorrectly says "Values are in seconds"; update the description to
state that trimBefore and trimAfter accept frame counts (frames), not seconds,
and clarify usage by referencing useVideoConfig() and fps (e.g., trimBefore={2 *
fps} means 2 seconds at 30fps); ensure the documentation for the Video
component's trimBefore and trimAfter props (and the example using staticFile and
fps) remains consistent with the frames-based unit.
| ## Pitch | ||
|
|
||
| Use `toneFrequency` to adjust the pitch without affecting speed. Values range from 0.01 to 2: | ||
|
|
||
| ```tsx | ||
| <Video | ||
| src={staticFile("video.mp4")} | ||
| toneFrequency={1.5} // Higher pitch | ||
| /> | ||
| <Video | ||
| src={staticFile("video.mp4")} | ||
| toneFrequency={0.8} // Lower pitch | ||
| /> | ||
| ``` | ||
|
|
||
| Pitch shifting only works during server-side rendering, not in the Remotion Studio preview or in the `<Player />`. |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Remotion toneFrequency constant immutable must not change
💡 Result:
In Remotion, toneFrequency is not a “constant”/immutable setting enforced by Remotion—it’s just an optional number prop you can pass to <Audio /> (and internally, media components) to influence pitch processing. It appears in the public TypeScript props surface as toneFrequency?: number. [1]
What is effectively “must not change” in practice:
- Treat
toneFrequencyas immutable for a given mounted<Audio>instance. If you need the pitch to change over time, split the audio into multiple<Sequence>blocks / multiple<Audio>elements (or force a remount via a changingkey) rather than trying to animatetoneFrequencyon one element. (Remotion’s audio graph/scheduling is built around setting up nodes, and changing such configuration mid-flight is generally not something the browser audio pipeline handles seamlessly.)
Also note:
toneFrequencysupport has historically been tied to@remotion/mediabehavior and has had compatibility gaps (e.g. “notoneFrequencyprop supported in preview” has been tracked separately), so don’t assume it works identically in Studio preview vs render. [2]- Remotion has had release work specifically around “fallback to toneFrequency” in
@remotion/media, indicating it’s part of the media-processing pipeline rather than a general reactive runtime knob. [3]
Sources:
[1] Remotion type definitions showing toneFrequency?: number on RemotionAudioProps (UNPKG) https://app.unpkg.com/remotion%404.0.361/files/dist/cjs/audio/props.d.ts
[2] Issue tracker listing “@remotion/media: No toneFrequency prop supported in preview” (Issuehunt mirror) https://oss.issuehunt.io/r/remotion-dev/remotion?tab=closed
[3] Remotion release note mentioning “@remotion/media: Fallback to toneFrequency” (GitHub releases) https://github.com/remotion-dev/remotion/releases
🏁 Script executed:
# First, let's read the actual file to understand the full context
cat -n ".agents/skills/remotion-best-practices/rules/videos.md" | sed -n '150,180p'Repository: truffle-ai/dexto
Length of output: 739
Document that toneFrequency must remain constant for the lifetime of a mounted <Video> component.
The current section reads like toneFrequency can be adjusted reactively like volume or playbackRate, but Remotion's audio graph is built to set up nodes at mount time. If you need to change pitch over time, you must use separate <Video> components in different <Sequence> blocks or force remounting with a changing key, rather than updating toneFrequency on a mounted component. This is an important constraint for a best-practices guide.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/rules/videos.md around lines 156 -
171, The docs imply toneFrequency can be changed reactively, but Remotion's
audio graph requires toneFrequency to be constant for the lifetime of a mounted
<Video> component; update the Pitch section to state this constraint explicitly
and describe the correct patterns: use separate <Video> components inside
different <Sequence> blocks or force remounting by changing the component's key
to achieve pitch changes over time, and note that pitch shifting only works
during server-side render (not in Remotion Studio or <Player />).
|
|
||
| ## When to use | ||
|
|
||
| Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge. |
There was a problem hiding this comment.
Fix the singular/plural typo in the usage guidance.
Use this skills reads awkwardly in the entry-point doc.
✏️ Suggested wording
-Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge.
+Use this skill whenever you are dealing with Remotion code to get domain-specific guidance.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge. | |
| Use this skill whenever you are dealing with Remotion code to get domain-specific guidance. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/remotion-best-practices/SKILL.md at line 10, Replace the
awkward phrase "Use this skills" in SKILL.md with correct grammar; change the
usage guidance line that currently reads "Use this skills whenever you are
dealing with Remotion code to obtain the domain-specific knowledge." to either
"Use this skill whenever you are dealing with Remotion code to obtain the
domain-specific knowledge." (singular) or "Use these skills whenever you are
dealing with Remotion code to obtain the domain-specific knowledge." (plural) to
match the intended meaning.
Release Note
pnpm changeset(select packages + bump)Summary by CodeRabbit