Skip to main content
Glama
template.tsx.j24.87 kB
{/* chuk-motion/src/chuk_motion/components/animations/Counter/template.tsx.j2 */} import React from 'react'; import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion'; interface CounterProps { startValue: number; endValue: number; prefix?: string; suffix?: string; decimals: number; animation: string; startFrame: number; durationInFrames: number; } export const Counter: React.FC<CounterProps> = ({ startValue, endValue, prefix = '', suffix = '', decimals, animation, startFrame, durationInFrames }) => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const relativeFrame = frame - startFrame; // Don't render if outside the time range if (durationInFrames > 0 && (frame < startFrame || frame >= startFrame + durationInFrames)) { return null; } // Calculate current value based on animation type let currentValue = startValue; let displayValue = ''; if (animation === 'count_up') { // Smooth count up animation using spring const progress = spring({ frame: relativeFrame, fps, config: { damping: [[ motion.default_spring.config.damping ]], mass: [[ motion.default_spring.config.mass ]], stiffness: [[ motion.default_spring.config.stiffness ]] } }); currentValue = interpolate(progress, [0, 1], [startValue, endValue]); displayValue = currentValue.toFixed(decimals); } else if (animation === 'flip') { // Digit flip animation - discrete steps const progress = spring({ frame: relativeFrame, fps, config: { damping: [[ motion.default_spring.config.damping ]], mass: [[ motion.default_spring.config.mass ]], stiffness: [[ motion.default_spring.config.stiffness ]] } }); currentValue = Math.floor(interpolate(progress, [0, 1], [startValue, endValue])); displayValue = currentValue.toFixed(decimals); } else if (animation === 'slot_machine') { // Slot machine roll effect - fast then slow const progress = spring({ frame: relativeFrame, fps, config: { damping: [[ motion.default_spring.config.damping ]], mass: [[ motion.default_spring.config.mass ]], stiffness: [[ motion.default_spring.config.stiffness ]] } }); currentValue = interpolate(progress, [0, 1], [startValue, endValue]); displayValue = currentValue.toFixed(decimals); } else if (animation === 'digital') { // Digital display style - flickering digits const progress = spring({ frame: relativeFrame, fps, config: { damping: [[ motion.default_spring.config.damping ]], mass: [[ motion.default_spring.config.mass ]], stiffness: [[ motion.default_spring.config.stiffness ]] } }); currentValue = interpolate(progress, [0, 1], [startValue, endValue]); displayValue = currentValue.toFixed(decimals); } else { // Default: linear interpolation currentValue = interpolate( relativeFrame, [0, durationInFrames], [startValue, endValue], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' } ); displayValue = currentValue.toFixed(decimals); } // Fade in at start const fadeIn = interpolate(relativeFrame, [0, 10], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); // Fade out near end const fadeOut = interpolate( relativeFrame, [durationInFrames - 10, durationInFrames], [1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' } ); const opacity = Math.min(fadeIn, fadeOut); // Scale animation for emphasis const scale = spring({ frame: relativeFrame, fps, config: { damping: [[ motion.default_spring.config.damping ]], mass: [[ motion.default_spring.config.mass ]], stiffness: [[ motion.default_spring.config.stiffness ]] } }); const scaleValue = interpolate(scale, [0, 1], [0.8, 1]); return ( <AbsoluteFill style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', pointerEvents: 'none' }} > <div style={{ opacity, transform: `scale(${scaleValue})`, fontFamily: "'[[ "', '".join(typography.primary_font.fonts) ]]'", fontSize: parseInt('[[ typography.font_sizes[typography.default_resolution]['4xl'] ]]'), fontWeight: '[[ typography.font_weights.black ]]', color: '[[ colors.primary[0] ]]', textAlign: 'center', textShadow: `0 [[ spacing.spacing.xxs ]]px [[ spacing.spacing.lg ]]px [[ colors.primary[0] ]]80`, letterSpacing: '[[ typography.letter_spacing.tight ]]' }} > {prefix}{displayValue}{suffix} </div> </AbsoluteFill> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chrishayuk/chuk-mcp-remotion'

If you have feedback or need assistance with the MCP directory API, please join our Discord server