← Catalog
Edit Props (live)
TEXT
TEXT
config
config
config
config
config
config
config
Source
136 lines// Animated Stat Counter — a big number that counts up from zero (ease-out)
// with a label and optional prefix/suffix. Native Remotion, frame-driven.
// Ubiquitous in marketing/finance content; trivial, looks expensive.
import {
AbsoluteFill,
Easing,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { loadFont as loadInter } from '@remotion/google-fonts/Inter';
import { loadFont as loadGrotesk } from '@remotion/google-fonts/SpaceGrotesk';
const { fontFamily: GROTESK } = loadGrotesk();
const { fontFamily: INTER } = loadInter();
const FONT_MAP: Record<string, string> = {
SpaceGrotesk: GROTESK,
Inter: INTER,
};
export type AnimatedStatCounterProps = {
value: number | string;
label: string;
prefix: string;
suffix: string;
decimals: number;
accentColor: string;
textColor: string;
backgroundColor: string;
font: 'SpaceGrotesk' | 'Inter';
};
export default function AnimatedStatCounter({
value = 1000,
label = 'Active users',
prefix = '',
suffix = '',
decimals = 0,
accentColor = '#22c55e',
textColor = '#ffffff',
backgroundColor = '#0a0a14',
font = 'SpaceGrotesk',
}: Partial<AnimatedStatCounterProps>) {
const frame = useCurrentFrame();
const { fps, durationInFrames, width } = useVideoConfig();
// Resolution-independent: px authored at a 1080-wide reference, scaled
// by k. k=1 at 1080 (identical output), scales cleanly at any width.
const k = width / 1080;
const family = FONT_MAP[font] ?? GROTESK;
const target = Number(value) || 0;
const dec = Math.max(0, Math.min(4, Number(decimals) || 0));
const countEnd = Math.min(durationInFrames - 10, Math.round(fps * 1.5));
const t = interpolate(frame, [8, countEnd], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.out(Easing.cubic),
});
const current = target * t;
const display =
prefix +
current.toLocaleString(undefined, {
minimumFractionDigits: dec,
maximumFractionDigits: dec,
}) +
suffix;
const popIn = spring({
frame,
fps,
config: { damping: 13 },
durationInFrames: 20,
});
const exit = interpolate(
frame,
[durationInFrames - 10, durationInFrames - 1],
[1, 0],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
const labelOpacity = interpolate(
frame,
[countEnd - 6, countEnd + 8],
[0, 1],
{
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
}
);
return (
<AbsoluteFill
style={{
backgroundColor,
justifyContent: 'center',
alignItems: 'center',
opacity: exit,
fontFamily: family,
}}
>
<div
style={{
textAlign: 'center',
transform: `scale(${interpolate(popIn, [0, 1], [0.72, 1])})`,
opacity: popIn,
}}
>
<div
style={{
fontSize: 220 * k,
fontWeight: 900,
color: accentColor,
letterSpacing: '-0.03em',
lineHeight: 1,
fontVariantNumeric: 'tabular-nums',
}}
>
{display}
</div>
<div
style={{
marginTop: 28 * k,
fontSize: 50 * k,
fontWeight: 600,
color: textColor,
opacity: labelOpacity,
}}
>
{label}
</div>
</div>
</AbsoluteFill>
);
}
Schema (Zod)
import { z } from 'zod';
export const Schema = z.object({
value: z
.union([z.number(), z.string()])
.default(1000)
.describe('$port:text The target number (counts up from zero)'),
label: z
.string()
.default('Active users')
.describe('$port:text Label under the number'),
prefix: z.string().default('').describe('Prefix, e.g. $ (optional)'),
suffix: z.string().default('').describe('Suffix, e.g. % or K (optional)'),
decimals: z.number().default(0).describe('$style:size Decimal places (0–4)'),
accentColor: z
.string()
.default('#22c55e')
.describe('$style:color Number color'),
textColor: z.string().default('#ffffff').describe('$style:color Label color'),
backgroundColor: z
.string()
.default('#0a0a14')
.describe('$style:color Background color'),
font: z
.enum(['SpaceGrotesk', 'Inter'])
.default('SpaceGrotesk')
.describe('$style:font Font'),
});
Animated Stat Counter
animated_stat_counterA big number that counts up from zero with an ease-out, plus a label and optional prefix/suffix. Use for any stat, metric, price, or count reveal.
Workflow Inputs (2)
- The target number (counts up from zero)
valueTEXT - Label under the number
labelTEXT
Config Fields (7)
fontprefixsuffixdecimalstextColoraccentColorbackgroundColor
Meta
- Updated
- 7/10/2026