caption-utils
remotionui/caption-utilsFreeUtility
Caption page grouping and word-active helpers
Install it
npx shadcn@latest add https://remotionui.com/r/caption-utils.jsonSource
1import {2 createTikTokStyleCaptions,3 type Caption,4 type TikTokPage,5} from "@remotion/captions";6import { interpolate } from "remotion";7import { EASING } from "./motion-tokens";89export const DEFAULT_CAPTION_PAGE_MS = 1200;1011export function groupCaptionsIntoPages(12 captions: Caption[],13 combineTokensWithinMilliseconds = DEFAULT_CAPTION_PAGE_MS,14): TikTokPage[] {15 const { pages } = createTikTokStyleCaptions({16 captions,17 combineTokensWithinMilliseconds,18 });19 return pages;20}2122/** Absolute composition time for the current sequence frame. */23export function getAbsoluteTimeMs(page: TikTokPage, frame: number, fps: number) {24 const relativeMs = (frame / fps) * 1000;25 return page.startMs + relativeMs;26}2728export function isTokenActive(29 token: { fromMs: number; toMs: number },30 absoluteTimeMs: number,31) {32 return token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs;33}3435/** Token timing relative to the page sequence start (required inside `<Sequence from={...}>`). */36export function getTokenRelativeFrames(37 token: { fromMs: number; toMs: number },38 page: TikTokPage,39 fps: number,40) {41 const startFrame = Math.round(((token.fromMs - page.startMs) / 1000) * fps);42 const endFrame = Math.round(((token.toMs - page.startMs) / 1000) * fps);43 return { startFrame, endFrame };44}4546export function getTokenEmphasis(47 frame: number,48 token: { fromMs: number; toMs: number },49 page: TikTokPage,50 fps: number,51 options?: { enterFrames?: number; exitFrames?: number },52) {53 // A word holds for 200-800ms, so emphasis has to arrive fast and release54 // slower — a symmetric ramp reads as a flicker on short tokens.55 const enterFrames = options?.enterFrames ?? 4;56 const exitFrames = options?.exitFrames ?? 9;57 const { startFrame, endFrame } = getTokenRelativeFrames(token, page, fps);58 const absoluteTimeMs = getAbsoluteTimeMs(page, frame, fps);59 const active = isTokenActive(token, absoluteTimeMs);6061 const enter = interpolate(62 frame,63 [startFrame, startFrame + enterFrames],64 [0, 1],65 {66 extrapolateLeft: "clamp",67 extrapolateRight: "clamp",68 easing: EASING.enter,69 },70 );7172 // Releasing emphasis is a settle, not an exit — accelerating away would snap73 // the word back to its resting size.74 const exit = interpolate(75 frame,76 [endFrame, endFrame + exitFrames],77 [1, 0],78 {79 extrapolateLeft: "clamp",80 extrapolateRight: "clamp",81 easing: EASING.editorial,82 },83 );8485 if (active) {86// … truncated
More from remotionui
All 127 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| ai-composer-utilsai-composer-utils | remotionui | Utilities | Free | no deps | |
| audio-viz-utilsaudio-viz-utils | remotionui | Utilities | Free | no deps | |
| chart-utilschart-utils | remotionui | Utilities | Free | no deps | |
| code-syntaxcode-syntax | remotionui | Utilities | Free | no deps | |
| layoutlayout | remotionui | Utilities | Free | no deps | |
| map-utilsmap-utils | remotionui | Utilities | Free | no deps | |
| media-utilsmedia-utils | remotionui | Utilities | Free | no deps | |
| motion-primitivemotion-primitive | remotionui | Utilities | Free | no deps |
