Follow-up to #1753, which covered two false licensing lines. This is the rest of an audit of the same skill: 21 further defects, of which 6 are confirmed by executing the CLI, not by reading docs.
The reason for the split: #1753 was verifiable from LICENSE.md alone. These needed a real install, because a command being absent from the docs does not prove it is absent from the binary. So I installed remotion@4.0.505 in a clean project with a real composition and ran things.
Everything below is against LifeOS/install/skills/Remotion/ as shipped.
A. Code that cannot work — Tools/Render.ts
Three exported functions call CLI surfaces that do not exist, and each swallows the failure, so they return an empty value on every call rather than erroring.
A1. listCompositions() (line ~174) fails four separate ways
const result = await $`bunx remotion compositions --json`.cwd(cwd).text()
return JSON.parse(result)
} catch (error: any) { ...; return [] }
--json does not exist. It is silently ignored and the human table is printed anyway:
$ bunx remotion compositions index.ts --json
The following compositions are available:
probe 30 1080x1920 30 (1.00 sec)
- No entry point is passed, but the command requires one: "The
compositions command requires you to specify a entry point."
- The Bun banner breaks
JSON.parse regardless. Running the exact code path above:
Failed to list compositions: JSON Parse error: Unexpected identifier "You"
"You" is the start of "You are running Remotion with Bun, which is mostly supported…", which the CLI writes to stdout before any output. Even if --json existed and emitted perfect JSON, this would still throw, because the banner is printed first. Bundling progress bars land on stdout too.
catch { return [] } makes a hard failure indistinguishable from "this project has no compositions."
A2. getVideoMetadata() (~line 268) and getAudioDuration() (~line 280)
await $`bunx remotion parse-video ${videoPath} --json`.text()
await $`bunx remotion parse-audio ${audioPath} --json`.text()
Neither subcommand exists. The binary says so:
$ bunx remotion parse-video
Command parse-video not found.
$ bunx remotion parse-audio
Command parse-audio not found.
The full list from remotion --help on 4.0.505 is: studio, render, still, bundle, compositions, benchmark, versions, gpu, upgrade, add, skills, browser.
Both functions catch { return null }, so they return null on every call. The comment above the first one says "This requires @remotion/media-utils in the project", but the code shells out to a CLI rather than calling the library — and @remotion/media-utils is browser-side, so it would not run in Node anyway. ffprobe is the workable substitute.
A3. createProject() (~line 211) — wrong flag form, and one template does not exist
The code does args.push('--template', options.template). Templates are flags, not the value of --template. The canonical form from create-video --help is create-video --yes --blank my-video, and the directory goes last.
The typed union offers 'tts', which is not among the 22 real template flags (grep -c tts over the help output returns 0). Real list: blank, hello-world, next, vercel, next-no-tailwind, next-pages-dir, recorder, prompt-to-motion-graphics, javascript, render-server, electron, react-router, three, still, audiogram, music-visualization, prompt-to-video, skia, overlay, code-hike, stargazer, tiktok.
B. Wrong API facts
B1. CriticalRules.md §6 — renderStillOnWeb(), four errors in twelve lines
import { renderStillOnWeb } from '@remotion/renderer/web';
const { blob, url, canvas } = await renderStillOnWeb({
composition: 'my-still',
inputProps: { /* ... */ },
});
- Wrong package.
import('@remotion/renderer/web') → Cannot find module. It is @remotion/web-renderer.
- Wrong version. The heading says v4.0.447; the docs mark it
AvailableFrom v="4.0.397".
- Wrong return shape. From the shipped
.d.ts:
export type RenderStillOnWebResult = {
internalState: InternalState;
canvas(): Promise<OffscreenCanvas>;
blob(options?: RenderStillOnWebEncodeOptions): Promise<Blob>;
url(options?: RenderStillOnWebEncodeOptions): Promise<string>;
};
They are async methods, not properties. That destructuring yields three functions.
- Wrong arguments.
composition is an object (id, component, durationInFrames, fps, width, height, …), not an id string, and the required frame is missing.
This is the file agents treat as law, which is why it is listed first.
B2. Tools/Ref-videos.md — trimBefore/trimAfter units are inverted
Use trimBefore and trimAfter to remove portions of the video. Values are in seconds.
They are frames. The line contradicts three things at once: the docs (trimBefore={60} at fps 30 skips 2 seconds), its own example two lines below (trimBefore={2 * fps}), and Ref-audio.md, which states "in frames" correctly. A reader who follows the prose and writes trimBefore={2} trims 2 frames and gets no error.
B3. Tools/Ref-images.md — getImageDimensions imported from the wrong package
Two occurrences import it from remotion. Confirmed by execution:
"getImageDimensions" in remotion → false
"getImageDimensions" in @remotion/media-utils → true
Both appear inside calculateMetadata, so this breaks at bundle time.
B4. Tools/Ref-lambda.md — Lambda capacity overstated ~4x, and one number does not exist
Max ~2 hours Full HD per render (5GB output limit).
The default ephemeral disk on 4.x is 2048 MB, which docs/lambda/disk-size maps to ~32 min at 1080p. Two hours needs 8192 MB, configured explicitly. And "5GB output limit" appears nowhere in the Lambda docs — limits states "Storage: Configurable, limited to 10GB at most".
Same file, intro: "Chunks render in parallel across hundreds of Lambda invocations". The documented cap is 200 ("Every render uses between 3 and 200 concurrent Lambda functions"), and upstream's own error message says the limit exists deliberately. "Hundreds" reads as a soft number.
B5. Patterns.md — teaches the legacy media API with a deprecated prop
import { Audio, Video, staticFile } from 'remotion'
<Audio src={staticFile('music.mp3')} volume={0.3} startFrom={30} />
<Video>/<Audio> from remotion are the legacy components (now <Html5Video>/<Html5Audio>; the docs say "For new video usage, prefer <Video> from @remotion/media"), and startFrom was renamed to trimBefore in 4.0.319 and cannot be combined with the new prop. Six sibling Ref-* files already import from @remotion/media; this one file teaches the old way.
B6. Tools/Ref-ai-pipeline.md — the one copyable example uses the form the skill forbids
Two <img src={staticFile(...)}> in the AI pipeline example, while Ref-images.md says: "You MUST use the <Img> component from remotion. Do not use: Native HTML <img> elements… The <Img> component ensures images are fully loaded before rendering, preventing flickering and blank frames during video export." The symptom only shows up at render.
B7. ArtIntegration.md — wrong theme value in the quick reference
LIFEOS_THEME.typography.subtitle // { fontSize: 36 }. In Tools/Theme.ts, subtitle is 48; 36 is heading. The quick reference exists so agents do not open the .ts, so a wrong value here is worse than no value.
C. Paths that do not exist — and one of them is a skill
Checked with ls locally and against this repo's tree via the GitHub API; none of these exist in LifeOS/install/ either:
Workflows/ContentToAnimation.md routes its entire step 1 through a Parser skill. There is no Parser and no _PARSER in LifeOS/install/skills/ — I listed the directory. Every row of the "Input Types" table (YouTube, article, PDF, tweet) points at it, so the non-AI workflow cannot start as written.
ArtIntegration.md → LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Art/PREFERENCES.md, under a MANDATORY heading.
ArtIntegration.md → skills/Art/Examples/. Art ships Lib/, Tools/, Workflows/ only.
Patterns.md → Tools/Reference/. The files are flat Tools/Ref-*.md, as SKILL.md itself documents.
Workflows/ContentToAnimation.md → ~/.claude/skills/Remotion/theme. The file is Tools/Theme.ts, under a MANDATORY: Apply LifeOS Theme heading.
Workflows/ContentToAnimation.md ends a bullet mid-path: - Reference: ~/.claude/.
D. Contradicts the skill's own rule
CriticalRules.md has a section titled "bunx, never npx". Against that:
Workflows/ContentToAnimation.md instructs npm install and npx remotion render …. It is the only render instruction in that workflow, so it is the line that gets executed.
- 14 lines across 10
Ref-*.md files ship four-package-manager install blocks (npx / bunx / yarn / pnpm exec). Less harmful, since the bunx variant sits right below, but it is the same contradiction.
E. Smaller, still worth fixing
Tools/Ref-timing.md — const spring = spring({...}) redeclares the imported spring; copy-pasting throws.
Tools/Ref-timing.md — a block titled "Delay" applies two delay mechanisms at once (frame: frame - ENTRANCE_DELAY and delay: 20), which add up, and ENTRANCE_DELAY is never defined in the file.
Tools/Ref-trimming.md — const fps = useVideoConfig() misses the destructuring, so -0.5 * fps is NaN and <Sequence from={NaN}>.
Tools/Ref-compositions.md — claims Map and Set are supported in defaultProps. I could not find that in any primary source, and /docs/composition#defaultprops says the opposite: "Props must be an object that contains only pure JSON-serializable values."
Tools/Ref-gifs.md — "<Gif> has the same props as <AnimatedImage>", while /docs/animatedimage#differences-to-gif lists differences, including that <AnimatedImage> does not support onLoad.
Tools/Ref-ai-pipeline.md and Workflows/GeneratedContentVideo.md name GPT-Image-1; the Art skill's own description says Flux, Nano Banana Pro and GPT-Image-2.
What held up
Worth saying, since a long defect list can read as "the whole skill is rotten." It is not. I verified and found correct: the AV1 platform limits (matches /docs/encoding word for word), toneFrequency range and server-only caveat in all three places it appears, the objectFit availability version (4.0.442, exact), @remotion/elevenlabs at 4.0.443 (exact), the 1000-concurrent-executions-per-region default, every <AnimatedImage> default, the spring() defaults (mass: 1, damping: 10, stiffness: 100), fillTextBox's signature, all 14 flags that Tools/Render.ts builds for remotion render, all 8 codec values, and the claim of "31 pattern files" (there are exactly 31).
The pattern, if it is useful
The three worst defects share a shape: a plausible fact about upstream, written without a probe. Not copy errors — inferences. Same root cause as the two licensing lines in #1753. A CI check that greps the skill for remotion <subcommand> and diffs against remotion --help would have caught A1 through A3 automatically.
Happy to open a PR for any subset, though I understand the public repo is regenerated by rsync from a private tree at release time, so this may need to land upstream of here.
Verification environment: remotion@4.0.505 and @remotion/cli@4.0.505 (the current latest on npm), bun 1.3.14, macOS on Apple Silicon, clean project with one registered composition. Docs checked against remotion-dev/remotion main on 2026-08-03.
Follow-up to #1753, which covered two false licensing lines. This is the rest of an audit of the same skill: 21 further defects, of which 6 are confirmed by executing the CLI, not by reading docs.
The reason for the split: #1753 was verifiable from
LICENSE.mdalone. These needed a real install, because a command being absent from the docs does not prove it is absent from the binary. So I installedremotion@4.0.505in a clean project with a real composition and ran things.Everything below is against
LifeOS/install/skills/Remotion/as shipped.A. Code that cannot work —
Tools/Render.tsThree exported functions call CLI surfaces that do not exist, and each swallows the failure, so they return an empty value on every call rather than erroring.
A1.
listCompositions()(line ~174) fails four separate ways--jsondoes not exist. It is silently ignored and the human table is printed anyway:compositionscommand requires you to specify a entry point."JSON.parseregardless. Running the exact code path above:"You"is the start of "You are running Remotion with Bun, which is mostly supported…", which the CLI writes to stdout before any output. Even if--jsonexisted and emitted perfect JSON, this would still throw, because the banner is printed first. Bundling progress bars land on stdout too.catch { return [] }makes a hard failure indistinguishable from "this project has no compositions."A2.
getVideoMetadata()(~line 268) andgetAudioDuration()(~line 280)Neither subcommand exists. The binary says so:
The full list from
remotion --helpon 4.0.505 is:studio,render,still,bundle,compositions,benchmark,versions,gpu,upgrade,add,skills,browser.Both functions
catch { return null }, so they returnnullon every call. The comment above the first one says "This requires @remotion/media-utils in the project", but the code shells out to a CLI rather than calling the library — and@remotion/media-utilsis browser-side, so it would not run in Node anyway.ffprobeis the workable substitute.A3.
createProject()(~line 211) — wrong flag form, and one template does not existThe code does
args.push('--template', options.template). Templates are flags, not the value of--template. The canonical form fromcreate-video --helpiscreate-video --yes --blank my-video, and the directory goes last.The typed union offers
'tts', which is not among the 22 real template flags (grep -c ttsover the help output returns 0). Real list:blank,hello-world,next,vercel,next-no-tailwind,next-pages-dir,recorder,prompt-to-motion-graphics,javascript,render-server,electron,react-router,three,still,audiogram,music-visualization,prompt-to-video,skia,overlay,code-hike,stargazer,tiktok.B. Wrong API facts
B1.
CriticalRules.md§6 —renderStillOnWeb(), four errors in twelve linesimport('@remotion/renderer/web')→Cannot find module. It is@remotion/web-renderer.AvailableFrom v="4.0.397"..d.ts:compositionis an object (id,component,durationInFrames,fps,width,height, …), not an id string, and the requiredframeis missing.This is the file agents treat as law, which is why it is listed first.
B2.
Tools/Ref-videos.md—trimBefore/trimAfterunits are invertedThey are frames. The line contradicts three things at once: the docs (
trimBefore={60}at fps 30 skips 2 seconds), its own example two lines below (trimBefore={2 * fps}), andRef-audio.md, which states "in frames" correctly. A reader who follows the prose and writestrimBefore={2}trims 2 frames and gets no error.B3.
Tools/Ref-images.md—getImageDimensionsimported from the wrong packageTwo occurrences import it from
remotion. Confirmed by execution:Both appear inside
calculateMetadata, so this breaks at bundle time.B4.
Tools/Ref-lambda.md— Lambda capacity overstated ~4x, and one number does not existThe default ephemeral disk on 4.x is 2048 MB, which
docs/lambda/disk-sizemaps to ~32 min at 1080p. Two hours needs 8192 MB, configured explicitly. And "5GB output limit" appears nowhere in the Lambda docs —limitsstates "Storage: Configurable, limited to 10GB at most".Same file, intro: "Chunks render in parallel across hundreds of Lambda invocations". The documented cap is 200 ("Every render uses between 3 and 200 concurrent Lambda functions"), and upstream's own error message says the limit exists deliberately. "Hundreds" reads as a soft number.
B5.
Patterns.md— teaches the legacy media API with a deprecated prop<Video>/<Audio>fromremotionare the legacy components (now<Html5Video>/<Html5Audio>; the docs say "For new video usage, prefer<Video>from@remotion/media"), andstartFromwas renamed totrimBeforein 4.0.319 and cannot be combined with the new prop. Six siblingRef-*files already import from@remotion/media; this one file teaches the old way.B6.
Tools/Ref-ai-pipeline.md— the one copyable example uses the form the skill forbidsTwo
<img src={staticFile(...)}>in the AI pipeline example, whileRef-images.mdsays: "You MUST use the<Img>component fromremotion. Do not use: Native HTML<img>elements… The<Img>component ensures images are fully loaded before rendering, preventing flickering and blank frames during video export." The symptom only shows up at render.B7.
ArtIntegration.md— wrong theme value in the quick referenceLIFEOS_THEME.typography.subtitle // { fontSize: 36 }. InTools/Theme.ts,subtitleis 48; 36 isheading. The quick reference exists so agents do not open the.ts, so a wrong value here is worse than no value.C. Paths that do not exist — and one of them is a skill
Checked with
lslocally and against this repo's tree via the GitHub API; none of these exist inLifeOS/install/either:Workflows/ContentToAnimation.mdroutes its entire step 1 through aParserskill. There is noParserand no_PARSERinLifeOS/install/skills/— I listed the directory. Every row of the "Input Types" table (YouTube, article, PDF, tweet) points at it, so the non-AI workflow cannot start as written.ArtIntegration.md→LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Art/PREFERENCES.md, under a MANDATORY heading.ArtIntegration.md→skills/Art/Examples/.ArtshipsLib/,Tools/,Workflows/only.Patterns.md→Tools/Reference/. The files are flatTools/Ref-*.md, asSKILL.mditself documents.Workflows/ContentToAnimation.md→~/.claude/skills/Remotion/theme. The file isTools/Theme.ts, under a MANDATORY: Apply LifeOS Theme heading.Workflows/ContentToAnimation.mdends a bullet mid-path:- Reference: ~/.claude/.D. Contradicts the skill's own rule
CriticalRules.mdhas a section titled "bunx, nevernpx". Against that:Workflows/ContentToAnimation.mdinstructsnpm installandnpx remotion render …. It is the only render instruction in that workflow, so it is the line that gets executed.Ref-*.mdfiles ship four-package-manager install blocks (npx/bunx/yarn/pnpm exec). Less harmful, since thebunxvariant sits right below, but it is the same contradiction.E. Smaller, still worth fixing
Tools/Ref-timing.md—const spring = spring({...})redeclares the importedspring; copy-pasting throws.Tools/Ref-timing.md— a block titled "Delay" applies two delay mechanisms at once (frame: frame - ENTRANCE_DELAYanddelay: 20), which add up, andENTRANCE_DELAYis never defined in the file.Tools/Ref-trimming.md—const fps = useVideoConfig()misses the destructuring, so-0.5 * fpsisNaNand<Sequence from={NaN}>.Tools/Ref-compositions.md— claimsMapandSetare supported indefaultProps. I could not find that in any primary source, and/docs/composition#defaultpropssays the opposite: "Props must be an object that contains only pure JSON-serializable values."Tools/Ref-gifs.md— "<Gif>has the same props as<AnimatedImage>", while/docs/animatedimage#differences-to-giflists differences, including that<AnimatedImage>does not supportonLoad.Tools/Ref-ai-pipeline.mdandWorkflows/GeneratedContentVideo.mdname GPT-Image-1; the Art skill's own description says Flux, Nano Banana Pro and GPT-Image-2.What held up
Worth saying, since a long defect list can read as "the whole skill is rotten." It is not. I verified and found correct: the AV1 platform limits (matches
/docs/encodingword for word),toneFrequencyrange and server-only caveat in all three places it appears, theobjectFitavailability version (4.0.442, exact),@remotion/elevenlabsat 4.0.443 (exact), the 1000-concurrent-executions-per-region default, every<AnimatedImage>default, thespring()defaults (mass: 1, damping: 10, stiffness: 100),fillTextBox's signature, all 14 flags thatTools/Render.tsbuilds forremotion render, all 8 codec values, and the claim of "31 pattern files" (there are exactly 31).The pattern, if it is useful
The three worst defects share a shape: a plausible fact about upstream, written without a probe. Not copy errors — inferences. Same root cause as the two licensing lines in #1753. A CI check that greps the skill for
remotion <subcommand>and diffs againstremotion --helpwould have caught A1 through A3 automatically.Happy to open a PR for any subset, though I understand the public repo is regenerated by rsync from a private tree at release time, so this may need to land upstream of here.
Verification environment:
remotion@4.0.505and@remotion/cli@4.0.505(the currentlateston npm), bun 1.3.14, macOS on Apple Silicon, clean project with one registered composition. Docs checked againstremotion-dev/remotionmainon 2026-08-03.