counter
remotionui/counterFreeComponent
Animated number with grouping, decimals, odometer digit roll and a reserved width
Live preview
live · rendered by the registry
Rendered by remotionui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://remotionui.com/r/counter.jsonSource
1import { useMemo } from "react";2import { interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";3import { scaleFont } from "@/remotion/lib/layout";4import {5 resolveSpringConfig,6 type MotionSpring,7} from "@/remotion/lib/motion-primitive";8import { EASING_ENTER } from "@/remotion/lib/timing";910export type CounterProps = {11 /** Value the count starts from. */12 from?: number;13 /** Value the count lands on. */14 to: number;15 durationInFrames?: number;16 delayInFrames?: number;17 /** Fixed decimal places. Also fixes the width, so nothing shifts. */18 decimals?: number;19 /** Group thousands with the locale's separator. */20 grouping?: boolean;21 /** Locale for grouping and decimal marks. */22 locale?: string;23 /** Full override of the number formatting. */24 format?: (value: number) => string;25 prefix?: string;26 suffix?: string;27 /**28 * Roll each digit like an odometer instead of swapping it. Lower digits spin29 * continuously; higher ones only turn over as the ones below them wrap.30 */31 roll?: boolean;32 /** Drive the ramp with a spring instead of the ease-out curve. */33 spring?: MotionSpring;34 /** Small scale pop on the frame the number lands. */35 settle?: boolean;36 fontSize?: number;37 fontWeight?: number;38 color?: string;39 fontFamily?: string;40 style?: React.CSSProperties;41};4243/** Frames the landing pop takes. */44const SETTLE_FRAMES = 9;45const SETTLE_SCALE = 1.03;46/** A digit only turns over once the digits below it are nearly wrapped. */47const CARRY_START = 0.88;4849function buildFormatter({50 decimals,51 grouping,52 locale,53 format,54}: {55 decimals: number;56 grouping: boolean;57 locale?: string;58 format?: (value: number) => string;59}): (value: number) => string {60 if (format) return format;6162 const formatter = new Intl.NumberFormat(locale, {63 minimumFractionDigits: decimals,64 maximumFractionDigits: decimals,65 useGrouping: grouping,66 });6768 return (value: number) => formatter.format(value);69}7071/**72 * Animated number.73 *74 * Two things a counter has to get right: it must never resize while it runs —75 * a centred value that jumps a character wider on every tick reads as a bug —76 * and it must decelerate, because a number arriving at constant speed has no77 * moment of landing. The width is reserved from the longest value up front and78 * the ramp is an ease-out.79 */80export const Counter: React.FC<CounterProps> = ({81 from = 0,82 to,83 durationInFrames = 60,84 delayInFrames = 0,85 decimals = 0,86// … truncated
More from remotionui
All 127 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| audio-pulseaudio-pulse | remotionui | Components | Free | no deps | |
| audiogram-barsaudiogram-bars | remotionui | Components | Free | no deps | |
| blur-focus-inblur-focus-in | remotionui | Components | Free | no deps | |
| blur-inblur-in | remotionui | Components | Free | no deps | |
| blur-revealblur-reveal | remotionui | Components | Free | no deps | |
| caption-highlightcaption-highlight | remotionui | Components | Free | no deps | |
| chromatic-aberration-wipechromatic-aberration-wipe | remotionui | Components | Free | no deps | |
| confetti-burstconfetti-burst | remotionui | Components | Free | no deps |
