Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply best practices for creating programmatic videos with Remotion and React
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/audio-visualization.md
1---2name: audio-visualization3description: Audio visualization patterns - spectrum bars, waveforms, bass-reactive effects4metadata:5tags: audio, visualization, spectrum, waveform, bass, music, audiogram, frequency6---78# Audio Visualization in Remotion910## Prerequisites1112```bash13npx remotion add @remotion/media-utils14```1516## Loading Audio Data1718Use `useWindowedAudioData()` (https://www.remotion.dev/docs/use-windowed-audio-data) to load audio data:1920```tsx21import { useWindowedAudioData } from "@remotion/media-utils";22import { staticFile, useCurrentFrame, useVideoConfig } from "remotion";2324const frame = useCurrentFrame();25const { fps } = useVideoConfig();2627const { audioData, dataOffsetInSeconds } = useWindowedAudioData({28src: staticFile("podcast.wav"),29frame,30fps,31windowInSeconds: 30,32});33```3435## Spectrum Bar Visualization3637Use `visualizeAudio()` (https://www.remotion.dev/docs/visualize-audio) to get frequency data for bar charts:3839```tsx40import { useWindowedAudioData, visualizeAudio } from "@remotion/media-utils";41import { staticFile, useCurrentFrame, useVideoConfig } from "remotion";4243const frame = useCurrentFrame();44const { fps } = useVideoConfig();4546const { audioData, dataOffsetInSeconds } = useWindowedAudioData({47src: staticFile("music.mp3"),48frame,49fps,50windowInSeconds: 30,51});5253if (!audioData) {54return null;55}5657const frequencies = visualizeAudio({58fps,59frame,60audioData,61numberOfSamples: 256,62optimizeFor: "speed",63dataOffsetInSeconds,64});6566return (67<div style={{ display: "flex", alignItems: "flex-end", height: 200 }}>68{frequencies.map((v, i) => (69<div70key={i}71style={{72flex: 1,73height: `${v * 100}%`,74backgroundColor: "#0b84f3",75margin: "0 1px",76}}77/>78))}79</div>80);81```8283- `numberOfSamples` must be power of 2 (32, 64, 128, 256, 512, 1024)84- Values range 0-1; left of array = bass, right = highs85- Use `optimizeFor: "speed"` for Lambda or high sample counts8687**Important:** When passing `audioData` to child components, also pass the `frame` from the parent. Do not call `useCurrentFrame()` in each child - this causes discontinuous visualization when children are inside `<Sequence>` with offsets.8889## Waveform Visualization9091Use `visualizeAudioWaveform()` (https://www.remotion.dev/docs/media-utils/visualize-audio-waveform) with `createSmoothSvgPath()` (https://www.remotion.dev/docs/media-utils/create-smooth-svg-path) for oscilloscope-style displays:9293```tsx94import {95createSmoothSvgPath,96useWindowedAudioData,97visualizeAudioWaveform,98} from "@remotion/media-utils";99import { staticFile, useCurrentFrame, useVideoConfig } from "remotion";100101const frame = useCurrentFrame();102const { width, fps } = useVideoConfig();103const HEIGHT = 200;104105const { audioData, dataOffsetInSeconds } = useWindowedAudioData({106src: staticFile("voice.wav"),107frame,108fps,109windowInSeconds: 30,110});111112if (!audioData) {113return null;114}115116const waveform = visualizeAudioWaveform({117fps,118frame,119audioData,120numberOfSamples: 256,121windowInSeconds: 0.5,122dataOffsetInSeconds,123});124125const path = createSmoothSvgPath({126points: waveform.map((y, i) => ({127x: (i / (waveform.length - 1)) * width,128y: HEIGHT / 2 + (y * HEIGHT) / 2,129})),130});131132return (133<svg width={width} height={HEIGHT}>134<path d={path} fill="none" stroke="#0b84f3" strokeWidth={2} />135</svg>136);137```138139## Bass-Reactive Effects140141Extract low frequencies for beat-reactive animations:142143```tsx144const frequencies = visualizeAudio({145fps,146frame,147audioData,148numberOfSamples: 128,149optimizeFor: "speed",150dataOffsetInSeconds,151});152153const lowFrequencies = frequencies.slice(0, 32);154const bassIntensity =155lowFrequencies.reduce((sum, v) => sum + v, 0) / lowFrequencies.length;156157const scale = 1 + bassIntensity * 0.5;158const opacity = Math.min(0.6, bassIntensity * 0.8);159```160161## Volume-Based Waveform162163Use `getWaveformPortion()` (https://www.remotion.dev/docs/get-waveform-portion) when you need simplified volume data instead of frequency spectrum:164165```tsx166import { getWaveformPortion } from "@remotion/media-utils";167import { useCurrentFrame, useVideoConfig } from "remotion";168169const frame = useCurrentFrame();170const { fps } = useVideoConfig();171const currentTimeInSeconds = frame / fps;172173const waveform = getWaveformPortion({174audioData,175startTimeInSeconds: currentTimeInSeconds,176durationInSeconds: 5,177numberOfSamples: 50,178});179180// Returns array of { index, amplitude } objects (amplitude: 0-1)181waveform.map((bar) => (182<div key={bar.index} style={{ height: bar.amplitude * 100 }} />183));184```185186## Postprocessing187188Low frequencies naturally dominate. Apply logarithmic scaling for visual balance:189190```tsx191const minDb = -100;192const maxDb = -30;193194const scaled = frequencies.map((value) => {195const db = 20 * Math.log10(value);196return (db - minDb) / (maxDb - minDb);197});198```199