{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cut-stat",
  "title": "Cut Stat",
  "description": "A blue bar graph wipes upward beside a big minus 44% caption, 'less time to a finished cut'.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "files": [
    {
      "path": "registry/remocn/cut-stat/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont as loadPlexMono } from \"@remotion/google-fonts/IBMPlexMono\";\nimport { loadFont as loadInstrument } from \"@remotion/google-fonts/InstrumentSans\";\nimport { Fragment, useId } from \"react\";\nimport {\n  AbsoluteFill,\n  Easing,\n  interpolate,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\n\nconst instrument = loadInstrument(\"normal\", {\n  weights: [\"400\", \"500\"],\n  subsets: [\"latin\"],\n});\nconst plex = loadPlexMono(\"normal\", { weights: [\"500\"], subsets: [\"latin\"] });\n\nexport interface CutStatProps {\n  value?: number;\n  decimals?: number;\n  prefix?: string;\n  suffix?: string;\n  label?: string;\n  caption?: string;\n  fromLabel?: string;\n  toLabel?: string;\n  accent?: string;\n  background?: string;\n  speed?: number;\n  theme?: \"dark\" | \"light\";\n}\n\nconst MESH = [\"#ecdcf2\", \"#8796ee\", \"#2e45b7\", \"#0e1645\"] as const;\nconst MESH_BG = \"#0a0d24\";\nconst BLOBS: [number, number][] = [\n  [16, 20],\n  [84, 26],\n  [72, 86],\n  [22, 80],\n  [52, 48],\n  [92, 62],\n];\n\nconst PALETTES = {\n  dark: {\n    bg: \"#0A0A0B\",\n    fg: \"#F4F3F0\",\n    muted: \"#8E8D94\",\n    fieldFg: \"#F6F4FF\",\n    fieldMuted: \"rgba(246,244,255,0.66)\",\n    edge: \"#F6F4FF\",\n    tick: \"rgba(255,255,255,0.09)\",\n    fieldTick: \"rgba(255,255,255,0.16)\",\n    fieldBg: MESH_BG,\n    blobs: [MESH[3], MESH[3], MESH[1], MESH[2], MESH[1], MESH[0]],\n  },\n  light: {\n    bg: \"#F5F4F0\",\n    fg: \"#111113\",\n    muted: \"#6E6C67\",\n    fieldFg: \"#0E1238\",\n    fieldMuted: \"rgba(14,18,56,0.6)\",\n    edge: \"#111113\",\n    tick: \"rgba(17,17,19,0.1)\",\n    fieldTick: \"rgba(14,18,56,0.16)\",\n    fieldBg: \"#DCE0F8\",\n    blobs: [\"#c9d0f7\", \"#a9b4f2\", MESH[1], \"#b3bdf4\", MESH[0], \"#f3eef9\"],\n  },\n} as const;\n\nconst EASE_OUT = Easing.bezier(0.22, 1, 0.36, 1);\nconst EASE_CUT = Easing.bezier(0.72, 0, 0.16, 1);\nconst CLAMP = {\n  extrapolateLeft: \"clamp\",\n  extrapolateRight: \"clamp\",\n} as const;\n\nfunction estimateEm(text: string) {\n  let w = 0;\n  for (const ch of text) {\n    if (/[0-9]/.test(ch)) w += 0.56;\n    else if (ch === \"%\") w += 0.78;\n    else if (/[.,]/.test(ch)) w += 0.24;\n    else if (/[−\\-+×x]/.test(ch)) w += 0.52;\n    else if (ch === \"$\" || ch === \"€\") w += 0.56;\n    else if (ch === \" \") w += 0.22;\n    else w += 0.56;\n  }\n  return w;\n}\n\nfunction Grain({ opacity }: { opacity: number }) {\n  const id = `grain-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n  return (\n    <svg\n      width=\"100%\"\n      height=\"100%\"\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        opacity,\n        mixBlendMode: \"overlay\",\n      }}\n      aria-hidden\n    >\n      <filter id={id}>\n        <feTurbulence\n          type=\"fractalNoise\"\n          baseFrequency=\"0.8\"\n          numOctaves={2}\n          seed={11}\n          stitchTiles=\"stitch\"\n        />\n        <feColorMatrix values=\"0 0 0 0 0.5  0 0 0 0 0.5  0 0 0 0 0.5  0 0 0 1 0\" />\n      </filter>\n      <rect width=\"100%\" height=\"100%\" filter={`url(#${id})`} />\n    </svg>\n  );\n}\n\nexport function CutStat({\n  value = 44,\n  decimals = 0,\n  prefix = \"−\",\n  suffix = \"%\",\n  label = \"less time to a finished cut\",\n  caption = \"vs. keyframing every scene by hand\",\n  fromLabel = \"Before\",\n  toLabel = \"With remocn\",\n  accent = \"#3B5BFD\",\n  background,\n  speed = 1,\n  theme = \"dark\",\n}: CutStatProps) {\n  const raw = useCurrentFrame();\n  const frame = raw * speed;\n  const { width, height, durationInFrames } = useVideoConfig();\n  const p = PALETTES[theme];\n\n  const portrait = height > width * 1.1;\n  const u = Math.min(width, height) / 720;\n  const v = Math.min(95, Math.max(5, value));\n  const along = portrait ? height : width;\n\n  const intro = interpolate(frame, [0, 6], [0, 1], CLAMP);\n  const fill = interpolate(frame, [0, 15], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n  const cut = interpolate(frame, [19, 51], [0, 1], {\n    ...CLAMP,\n    easing: EASE_CUT,\n  });\n  const flash = interpolate(frame, [49, 52, 63], [0, 1, 0], CLAMP);\n  const drift = interpolate(raw, [0, durationInFrames], [0, 1], CLAMP);\n  const cutPx = (along * v * cut) / 100;\n  const remaining = 100 - v * cut;\n  const counted = v * cut;\n  const fmt = (n: number) => n.toFixed(decimals);\n  const swapT = interpolate(frame, [44, 56], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n\n  const margin = (portrait ? 56 : 52) * u;\n  const zone = (along * v) / 100;\n  const finalText = `${prefix}${fmt(v)}${suffix}`;\n  const em = estimateEm(finalText);\n  const roomW = portrait\n    ? width - margin * 2\n    : Math.max(zone, width * 0.36) - margin * 1.6;\n  const statFs = Math.min(\n    (portrait ? 300 : 236) * u,\n    roomW / em,\n    portrait ? Math.max(zone, height * 0.3) * 0.5 : Infinity,\n  );\n  const words = label.split(/\\s+/).filter(Boolean);\n  const wordT = (i: number) =>\n    interpolate(frame, [47 + i * 3, 65 + i * 3], [0, 1], {\n      ...CLAMP,\n      easing: EASE_OUT,\n    });\n  const capT = interpolate(\n    frame,\n    [63 + words.length * 2, 81 + words.length * 2],\n    [0, 1],\n    {\n      ...CLAMP,\n      easing: EASE_OUT,\n    },\n  );\n\n  const transparent = background === \"transparent\";\n  const labelFs = 14 * u;\n  const blobs = BLOBS.map(([x, y], i) => {\n    const c = p.blobs[i];\n    const dx = Math.sin(i * 1.7 + drift * 2.2) * 3;\n    const dy = Math.cos(i * 1.3 + drift * 2.2) * 3;\n    return `radial-gradient(85% 95% at ${x + dx}% ${y + dy}%, ${c} 0%, transparent 68%)`;\n  });\n  blobs[2] = `radial-gradient(85% 95% at ${72 + drift * 3}% ${86 - drift * 3}%, color-mix(in oklab, ${accent} ${theme === \"dark\" ? 70 : 45}%, ${MESH[1]}) 0%, transparent 68%)`;\n\n  const shut = cutPx + along * (1 - fill);\n  const fieldClip = portrait\n    ? `inset(0 0 ${shut}px 0)`\n    : `inset(0 ${shut}px 0 0)`;\n  const edgePos = along - shut;\n  const edgeO =\n    fill < 1\n      ? fill > 0.02 && fill < 0.98\n        ? 1\n        : 0\n      : cut <= 0\n        ? 0\n        : cut < 1\n          ? 1\n          : 0.35 + flash * 0.65;\n\n  const release = interpolate(frame, [53, 69], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n  const clipAt = edgePos * (1 - release);\n  const statClip = portrait\n    ? `inset(${clipAt}px 0 0 0)`\n    : `inset(0 0 0 ${clipAt}px)`;\n\n  const scaleT = interpolate(frame, [4, 20], [0, 1], CLAMP);\n  const scale = (line: string, text: string) => (\n    <div style={{ position: \"absolute\", inset: 0, opacity: scaleT }}>\n      {Array.from({ length: 11 }, (_, i) => {\n        const at = (along * i) / 10;\n        return (\n          <Fragment key={i}>\n            {i > 0 && i < 10 ? (\n              <div\n                style={{\n                  position: \"absolute\",\n                  background: line,\n                  ...(portrait\n                    ? { left: 0, right: 0, top: at, height: 1 }\n                    : { top: 0, bottom: 0, left: at, width: 1 }),\n                }}\n              />\n            ) : null}\n            <div\n              style={{\n                position: \"absolute\",\n                fontFamily: plex.fontFamily,\n                fontWeight: 500,\n                fontSize: 11 * u * (portrait ? 1.3 : 1),\n                letterSpacing: \"0.04em\",\n                color: text,\n                fontVariantNumeric: \"tabular-nums\",\n                ...(portrait\n                  ? {\n                      right: 18 * u,\n                      top: Math.min(\n                        Math.max(at - 18 * u, 8 * u),\n                        height - 26 * u,\n                      ),\n                    }\n                  : {\n                      bottom: 16 * u,\n                      left: Math.min(\n                        Math.max(at + 7 * u, 8 * u),\n                        width - 30 * u,\n                      ),\n                    }),\n              }}\n            >\n              {i * 10}\n            </div>\n          </Fragment>\n        );\n      })}\n    </div>\n  );\n\n  const readout = (fg: string, muted: string) => (\n    <div\n      style={{\n        position: \"absolute\",\n        left: margin,\n        top: margin,\n        display: \"flex\",\n        alignItems: \"center\",\n        gap: 12 * u,\n        fontFamily: plex.fontFamily,\n        fontWeight: 500,\n        fontSize: labelFs,\n        letterSpacing: \"0.06em\",\n        textTransform: \"uppercase\",\n        color: fg,\n      }}\n    >\n      <span\n        style={{\n          display: \"grid\",\n          overflow: \"hidden\",\n        }}\n      >\n        <span\n          style={{\n            gridArea: \"1 / 1\",\n            transform: `translateY(${-swapT * 110}%)`,\n          }}\n        >\n          {fromLabel}\n        </span>\n        <span\n          style={{\n            gridArea: \"1 / 1\",\n            transform: `translateY(${(1 - swapT) * 110}%)`,\n          }}\n        >\n          {toLabel}\n        </span>\n      </span>\n      <span style={{ width: 24 * u, height: 1, background: muted }} />\n      <span\n        style={{\n          color: muted,\n          fontVariantNumeric: \"tabular-nums\",\n        }}\n      >\n        {fmt(remaining)}%\n      </span>\n    </div>\n  );\n\n  const statStyle = {\n    fontFamily: instrument.fontFamily,\n    fontWeight: 500,\n    fontSize: statFs,\n    lineHeight: 0.9,\n    letterSpacing: \"-0.05em\",\n    fontVariantNumeric: \"tabular-nums\",\n    color: p.fg,\n    whiteSpace: \"nowrap\",\n  } as const;\n\n  return (\n    <AbsoluteFill\n      style={{\n        background: transparent ? \"transparent\" : (background ?? p.bg),\n        overflow: \"hidden\",\n      }}\n    >\n      {scale(p.tick, p.muted)}\n      <div style={{ position: \"absolute\", inset: 0, opacity: intro }}>\n        {readout(p.fg, p.muted)}\n      </div>\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          clipPath: statClip,\n          opacity: interpolate(frame, [18, 20], [0, 1], CLAMP),\n          zIndex: 2,\n        }}\n      >\n        <div\n          style={{\n            position: \"absolute\",\n            ...(portrait\n              ? {\n                  left: margin,\n                  right: margin * 1.6,\n                  bottom: margin,\n                  height: Math.max(zone, height * 0.3) - margin,\n                  justifyContent: \"flex-end\",\n                }\n              : {\n                  right: margin,\n                  top: margin,\n                  bottom: margin * 1.45,\n                  width: Math.max(zone, width * 0.36) - margin * 1.6,\n                  justifyContent: \"flex-end\",\n                }),\n            display: \"flex\",\n            flexDirection: \"column\",\n            alignItems: portrait ? \"flex-start\" : \"flex-end\",\n            textAlign: portrait ? \"left\" : \"right\",\n          }}\n        >\n          <div\n            style={{\n              ...statStyle,\n              marginRight: portrait ? 0 : -statFs * 0.04,\n              marginLeft: portrait ? -statFs * 0.04 : 0,\n            }}\n          >\n            {prefix}\n            {fmt(counted)}\n            {suffix}\n          </div>\n          <div\n            style={{\n              marginTop: statFs * 0.14,\n              maxWidth: portrait\n                ? width - margin * 2\n                : Math.max(roomW, 300 * u),\n              fontFamily: instrument.fontFamily,\n              fontWeight: 400,\n              fontSize: (portrait ? 46 : 34) * u,\n              lineHeight: 1.12,\n              letterSpacing: \"-0.02em\",\n              color: p.fg,\n              textWrap: \"balance\",\n            }}\n          >\n            {words.map((w, k) => {\n              const t = wordT(k);\n              return (\n                <Fragment key={`${w}-${k}`}>\n                  {k > 0 ? \" \" : null}\n                  <span\n                    style={{\n                      display: \"inline-block\",\n                      overflow: \"hidden\",\n                      verticalAlign: \"top\",\n                      paddingBottom: \"0.12em\",\n                      marginBottom: \"-0.12em\",\n                    }}\n                  >\n                    <span\n                      style={{\n                        display: \"inline-block\",\n                        transform: `translateY(${(1 - t) * 105}%)`,\n                      }}\n                    >\n                      {w}\n                    </span>\n                  </span>\n                </Fragment>\n              );\n            })}\n          </div>\n          {caption ? (\n            <div\n              style={{\n                marginTop: 16 * u,\n                fontFamily: plex.fontFamily,\n                fontWeight: 500,\n                fontSize: labelFs * (portrait ? 1.3 : 1),\n                letterSpacing: \"0.04em\",\n                textTransform: \"uppercase\",\n                color: p.muted,\n                opacity: capT,\n                transform: `translateY(${(1 - capT) * 8 * u}px)`,\n              }}\n            >\n              {caption}\n            </div>\n          ) : null}\n        </div>\n      </div>\n\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          clipPath: fieldClip,\n          opacity: intro,\n          background: [...blobs, p.fieldBg].join(\", \"),\n        }}\n      >\n        <Grain opacity={0.1} />\n        {scale(p.fieldTick, p.fieldMuted)}\n        {readout(p.fieldFg, p.fieldMuted)}\n      </div>\n\n      <div\n        style={{\n          position: \"absolute\",\n          ...(portrait\n            ? { left: 0, right: 0, top: edgePos - 1 * u, height: 2 * u }\n            : { top: 0, bottom: 0, left: edgePos - 1 * u, width: 2 * u }),\n          background: p.edge,\n          opacity: edgeO * intro,\n          zIndex: 3,\n        }}\n      />\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/cut-stat.tsx"
    }
  ],
  "type": "registry:component"
}
