Catalog
No preview yet

Source

121 lines
// Radial Progress — a sweeping circular progress ring with a counting number
// in the center and a label. SVG with a 0..100 viewBox, so it's resolution-
// independent for free. Native Remotion (spring + interpolate, frame-driven).
// Generated on the fly via Wireflow's block API.

import {
  AbsoluteFill,
  interpolate,
  spring,
  useCurrentFrame,
  useVideoConfig,
} from 'remotion';
import { loadFont as loadGrotesk } from '@remotion/google-fonts/SpaceGrotesk';

const { fontFamily: GROTESK } = loadGrotesk();

export type RadialProgressProps = {
  value: number | string;
  label: string;
  suffix: string;
  ringColor: string;
  trackColor: string;
  textColor: string;
  backgroundColor: string;
};

export default function RadialProgress({
  value = 87,
  label = 'Goal complete',
  suffix = '%',
  ringColor = '#5b3df5',
  trackColor = '#20203a',
  textColor = '#ffffff',
  backgroundColor = '#0a0a14',
}: Partial<RadialProgressProps>) {
  const frame = useCurrentFrame();
  const { fps, durationInFrames } = useVideoConfig();
  const target = Math.max(0, Math.min(100, Number(value) || 0));

  const grow = spring({
    frame: frame - 6,
    fps,
    config: { damping: 18, stiffness: 90 },
    durationInFrames: 42,
  });
  const exit = interpolate(
    frame,
    [durationInFrames - 10, durationInFrames - 1],
    [1, 0],
    { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
  );

  const R = 38;
  const C = 2 * Math.PI * R;
  const dashoffset = C * (1 - (target / 100) * grow);
  const display = Math.round(target * grow);

  return (
    <AbsoluteFill
      style={{
        backgroundColor,
        justifyContent: 'center',
        alignItems: 'center',
        opacity: exit,
        fontFamily: GROTESK,
      }}
    >
      <svg viewBox="0 0 100 100" style={{ width: '62%', height: 'auto' }}>
        <circle
          cx="50"
          cy="50"
          r={R}
          fill="none"
          stroke={trackColor}
          strokeWidth="7"
        />
        <circle
          cx="50"
          cy="50"
          r={R}
          fill="none"
          stroke={ringColor}
          strokeWidth="7"
          strokeLinecap="round"
          strokeDasharray={C}
          strokeDashoffset={dashoffset}
          transform="rotate(-90 50 50)"
        />
        <text
          x="50"
          y="49"
          fill={textColor}
          fontSize="21"
          fontWeight="800"
          textAnchor="middle"
          dominantBaseline="central"
          fontFamily={GROTESK}
          style={{ fontVariantNumeric: 'tabular-nums' }}
        >
          {display}
          {suffix}
        </text>
        <text
          x="50"
          y="67"
          fill={textColor}
          opacity={0.55}
          fontSize="6.4"
          fontWeight="600"
          letterSpacing="0.6"
          textAnchor="middle"
          dominantBaseline="central"
          fontFamily={GROTESK}
        >
          {String(label).toUpperCase()}
        </text>
      </svg>
    </AbsoluteFill>
  );
}

Schema (Zod)

import { z } from 'zod';

export const Schema = z.object({
  value: z
    .union([z.number(), z.string()])
    .default(87)
    .describe('$port:text Progress value 0–100'),
  label: z.string().default('Goal complete').describe('$port:text Label'),
  suffix: z.string().default('%').describe('Suffix after the number'),
  ringColor: z
    .string()
    .default('#5b3df5')
    .describe('$style:color Progress ring color'),
  trackColor: z
    .string()
    .default('#20203a')
    .describe('$style:color Track (unfilled) color'),
  textColor: z.string().default('#ffffff').describe('$style:color Text color'),
  backgroundColor: z
    .string()
    .default('#0a0a14')
    .describe('$style:color Background color'),
});

Radial Progress

radial_progress

A sweeping circular progress ring with a counting number in the center and a label. Resolution-independent SVG. Use for completion, goals, scores, or any 0–100 metric.

Workflow Inputs (2)

  • Progress value 0–100
    value
    TEXT
  • Label
    label
    TEXT

Config Fields (5)

  • suffix
  • ringColor
  • textColor
  • trackColor
  • backgroundColor

Meta

Updated
6/4/2026