{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-diff-wipe",
  "title": "Code Diff Wipe",
  "description": "Before/after code reveal via clip-path wipe with a handle marker.",
  "dependencies": [
    "remotion"
  ],
  "files": [
    {
      "path": "registry/bases/editframe/components/code-diff-wipe/index.tsx",
      "content": "\"use client\";\n\nimport { Timegroup } from \"@editframe/react\";\nimport type { CSSProperties } from \"react\";\n\nconst DEFAULT_BEFORE = `function getUser(id) {\n  return fetch('/api/user/' + id)\n    .then(function (res) {\n      return res.json();\n    })\n    .then(function (data) {\n      if (data.error) {\n        throw new Error(data.error);\n      }\n      return data.user;\n    });\n}`;\n\nconst DEFAULT_AFTER = `async function getUser(id: string) {\n  const res = await fetch(\\`/api/user/\\${id}\\`);\n  const { user, error } = await res.json();\n  if (error) throw new Error(error);\n  return user;\n}`;\n\nexport interface CodeDiffWipeProps {\n  before?: string;\n  after?: string;\n  language?: string;\n  background?: string;\n  accent?: string;\n  transitionStart?: number;\n  transitionDuration?: number;\n  showHandle?: boolean;\n  speed?: number;\n  fps?: number;\n  durationInFrames?: number;\n  width?: number;\n  height?: number;\n  className?: string;\n}\n\nconst CodePane = ({\n  code,\n  background,\n  label,\n  labelColor,\n  language,\n  dimmed,\n}: {\n  code: string;\n  background: string;\n  label: string;\n  labelColor: string;\n  language: string;\n  dimmed?: boolean;\n}) => {\n  const lines = code.split(\"\\n\");\n  return (\n    <div\n      style={{\n        background,\n        display: \"flex\",\n        flexDirection: \"column\",\n        inset: 0,\n        position: \"absolute\",\n      }}\n    >\n      {/* Header */}\n      <div\n        style={{\n          alignItems: \"center\",\n          background: \"rgba(255,255,255,0.02)\",\n          borderBottom: \"1px solid rgba(255,255,255,0.06)\",\n          display: \"flex\",\n          height: 44,\n          justifyContent: \"space-between\",\n          padding: \"0 18px\",\n        }}\n      >\n        <div\n          style={{\n            color: \"#71717a\",\n            fontFamily:\n              \"var(--font-geist-mono), ui-monospace, SFMono-Regular, monospace\",\n            fontSize: 13,\n          }}\n        >\n          {language}\n        </div>\n        <div\n          style={{\n            background: `${labelColor}1a`,\n            border: `1px solid ${labelColor}55`,\n            borderRadius: 999,\n            color: labelColor,\n            fontSize: 11,\n            fontWeight: 700,\n            letterSpacing: \"0.12em\",\n            padding: \"4px 10px\",\n          }}\n        >\n          {label}\n        </div>\n      </div>\n\n      {/* Code */}\n      <pre\n        style={{\n          color: dimmed ? \"#71717a\" : \"#e4e4e7\",\n          flex: 1,\n          fontFamily:\n            \"var(--font-geist-mono), ui-monospace, SFMono-Regular, monospace\",\n          fontSize: 16,\n          lineHeight: 1.6,\n          margin: 0,\n          overflow: \"hidden\",\n          padding: 24,\n          whiteSpace: \"pre\",\n        }}\n      >\n        {lines.map((line, i) => (\n          <div key={i} style={{ display: \"flex\" }}>\n            <span\n              style={{\n                color: \"#3f3f46\",\n                marginRight: 16,\n                textAlign: \"right\",\n                userSelect: \"none\",\n                width: 32,\n              }}\n            >\n              {i + 1}\n            </span>\n            <span>{line || \" \"}</span>\n          </div>\n        ))}\n      </pre>\n    </div>\n  );\n};\n\nexport const CodeDiffWipe = ({\n  before = DEFAULT_BEFORE,\n  after = DEFAULT_AFTER,\n  language = \"tsx\",\n  background = \"#0a0a0a\",\n  accent = \"#0ea5e9\",\n  transitionStart = 20,\n  transitionDuration = 60,\n  showHandle = true,\n  speed = 1,\n  fps = 30,\n  durationInFrames = 120,\n  width = 1280,\n  height = 720,\n  className,\n}: CodeDiffWipeProps) => {\n  const safeSpeed = Math.max(0.01, speed);\n  const durationMs = (durationInFrames / fps) * 1000;\n  const frameMs = 1000 / fps;\n  const startMs = transitionStart * frameMs;\n  const durationMsCalc = (transitionDuration * frameMs) / safeSpeed;\n\n  const containerStyle: CSSProperties = {\n    alignItems: \"center\",\n    background: \"#050505\",\n    display: \"flex\",\n    fontFamily:\n      \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\",\n    height,\n    justifyContent: \"center\",\n    overflow: \"hidden\",\n    position: \"relative\",\n    width,\n  };\n\n  return (\n    <Timegroup\n      className={className}\n      duration={`${durationMs}ms`}\n      mode=\"fixed\"\n      style={containerStyle}\n    >\n      <>\n        <style>{`\n          @keyframes framecn-code-diff-wipe {\n            from { clip-path: inset(0 100% 0 0); }\n            to { clip-path: inset(0 0 0 0); }\n          }\n          @keyframes framecn-code-diff-handle {\n            from { left: 100%; }\n            to { left: 0%; }\n          }\n        `}</style>\n        <div\n          style={{\n            background,\n            borderRadius: 14,\n            boxShadow:\n              \"0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.06)\",\n            height: 560,\n            overflow: \"hidden\",\n            position: \"relative\",\n            width: 980,\n          }}\n        >\n          {/* AFTER (bottom layer) */}\n          <CodePane\n            code={after}\n            background={background}\n            label=\"AFTER\"\n            labelColor={accent}\n            language={language}\n          />\n\n          {/* BEFORE (top layer, clipped) */}\n          <div\n            style={{\n              animation: `framecn-code-diff-wipe ${durationMsCalc}ms cubic-bezier(0.16, 1, 0.3, 1) ${startMs}ms backwards`,\n              inset: 0,\n              position: \"absolute\",\n            }}\n          >\n            <CodePane\n              code={before}\n              background={background}\n              label=\"BEFORE\"\n              labelColor=\"#ef4444\"\n              language={language}\n              dimmed\n            />\n          </div>\n\n          {/* Handle */}\n          {showHandle && (\n            <div\n              style={{\n                animation: `framecn-code-diff-handle ${durationMsCalc}ms cubic-bezier(0.16, 1, 0.3, 1) ${startMs}ms backwards`,\n                background: accent,\n                bottom: 0,\n                boxShadow: `0 0 24px ${accent}`,\n                position: \"absolute\",\n                top: 0,\n                transform: \"translateX(-1px)\",\n                width: 2,\n              }}\n            >\n              <div\n                style={{\n                  alignItems: \"center\",\n                  background: accent,\n                  borderRadius: \"50%\",\n                  boxShadow: `0 0 32px ${accent}aa`,\n                  color: \"#0a0a0a\",\n                  display: \"flex\",\n                  fontSize: 18,\n                  fontWeight: 700,\n                  height: 40,\n                  justifyContent: \"center\",\n                  left: \"50%\",\n                  position: \"absolute\",\n                  top: \"50%\",\n                  transform: \"translate(-50%, -50%)\",\n                  width: 40,\n                }}\n              >\n                {\"<>\"}\n              </div>\n            </div>\n          )}\n        </div>\n      </>\n    </Timegroup>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/framecn/code-diff-wipe.tsx"
    }
  ],
  "type": "registry:component"
}