Captions & Advanced Typography
Overview
The Agent Board leverages Remotion's typography and captioning engines to create high-impact, data-driven video content. This section covers the implementation of automated captions, TikTok-style word highlighting, and advanced text animation patterns.
Captioning Workflows
Captions are handled through the @remotion/captions package. You can either import pre-existing .srt files or generate timestamps through transcription services.
Importing SRT Files
To use standard subtitle files, use the parseSRT utility to convert them into a Caption array compatible with Remotion components.
import { parseSRT } from '@remotion/captions';
import { staticFile } from 'remotion';
const captions = parseSRT(staticFile('subtitles.srt'));
Generating TikTok-Style Captions
To create the popular "word-by-word" or "phrase-by-phrase" effect, use createTikTokStyleCaptions. This utility groups words into "pages" based on timing.
import { useMemo } from 'react';
import { createTikTokStyleCaptions } from '@remotion/captions';
const SWITCH_CAPTIONS_EVERY_MS = 1200;
const { pages } = useMemo(() => {
return createTikTokStyleCaptions({
captions,
combineTokensWithinMilliseconds: SWITCH_CAPTIONS_EVERY_MS,
});
}, [captions]);
Rendering Captions with Word Highlighting
A TikTokPage contains a list of tokens. By comparing the useCurrentFrame() time with the token's fromMs and toMs, you can apply active styles for word highlighting.
Implementation Pattern
import { Sequence, useVideoConfig, useCurrentFrame, AbsoluteFill } from 'remotion';
import type { TikTokPage } from '@remotion/captions';
const CaptionPage: React.FC<{ page: TikTokPage }> = ({ page }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const absoluteTimeMs = page.startMs + (frame / fps) * 1000;
return (
<div style={{ fontSize: 60, fontWeight: 'bold' }}>
{page.tokens.map((token, i) => {
const isActive = token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs;
return (
<span key={i} style={{ color: isActive ? '#39E508' : 'white' }}>
{token.text}{' '}
</span>
);
})}
</div>
);
};
Advanced Typography
Font Management
The Agent Board supports both Google Fonts and local assets.
Google Fonts: Use the @remotion/google-fonts package for type-safety and automatic loading.
import { loadFont } from '@remotion/google-fonts/Inter';
const { fontFamily } = loadFont();
// Use fontFamily in your inline styles
Local Fonts: Use staticFile() within a FontFace declaration to ensure the font is bundled correctly.
Text Animation Patterns
Do not use CSS transitions or Tailwind animation classes, as they are not deterministic during rendering. All animations must be driven by the frame.
Typewriter Effect
The typewriter effect calculates the substring to display based on the current frame index.
const CHAR_FRAMES = 2; // Speed: 1 char every 2 frames
const typedText = fullText.slice(0, Math.floor(frame / CHAR_FRAMES));
return <div>{typedText}</div>;
Spring-Animated Word Wipe
For highlighting specific words within a static sentence, use a spring animation to drive a scaleX transform on a background highlight box.
import { spring, useVideoConfig, useCurrentFrame } from 'remotion';
const Highlight: React.FC<{ delay: number }> = ({ delay }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const progress = spring({
frame,
fps,
delay,
config: { damping: 200 }
});
return (
<div style={{
transform: `scaleX(${progress})`,
transformOrigin: 'left',
backgroundColor: 'yellow'
}} />
);
};
Measuring Text Dimensions
To prevent text overflow in dynamic layouts, use the DOM measurement pattern. Since Remotion renders in a real browser, you can measure elements during the layout phase.
- Render text with
opacity: 0. - Measure using
getBoundingClientRect()or use helper utilities to check if text fits within its container. - Adjust
fontSizeorletterSpacingdynamically before the final render.
Note: For performance-intensive layouts, prefer pre-calculating text width using a canvas-based measurement tool if the font is already loaded.