{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "hero-heatmap", "type": "registry:ui", "description": "Split-layout hero section with responsive Heatmap shader visuals, CTA, and tech stack badges", "dependencies": [ "@paper-design/shaders-react" ], "registryDependencies": [ "badge", "button" ], "files": [ { "path": "registry/default/ui/hero-heatmap.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport type { SVGProps } from \"react\"\nimport { Heatmap } from \"@paper-design/shaders-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\n\nconst MemoizedHeatmap = React.memo(Heatmap)\n\ntype HeatmapProps = React.ComponentProps\ntype HeatmapIcon = React.ComponentType>\n\nexport interface HeroHeatmapTechItem {\n name: string\n version?: string\n icon?: HeatmapIcon\n}\n\nexport interface HeroHeatmapCTAProps {\n label: React.ReactNode\n href: string\n target?: React.HTMLAttributeAnchorTarget\n rel?: string\n onClick?: React.MouseEventHandler\n className?: string\n buttonClassName?: string\n}\n\n/** Heatmap shader props that can be passed at the root for convenience */\nexport type HeroHeatmapShaderOverrides = Partial<\n Pick<\n HeatmapProps,\n | \"width\"\n | \"height\"\n | \"image\"\n | \"colors\"\n | \"colorBack\"\n | \"contour\"\n | \"angle\"\n | \"noise\"\n | \"innerGlow\"\n | \"outerGlow\"\n | \"speed\"\n | \"scale\"\n >\n>\n\nexport interface HeroHeatmapRootProps\n extends Omit, \"title\">,\n HeroHeatmapShaderOverrides {\n srTitle?: string\n title?: React.ReactNode\n subtitle?: React.ReactNode\n description?: React.ReactNode\n showCta?: boolean\n ctaProps?: Partial\n renderCta?: (defaultCta: React.ReactNode) => React.ReactNode\n showBadges?: boolean\n techStack?: HeroHeatmapTechItem[]\n renderBadge?: (\n tech: HeroHeatmapTechItem,\n index: number,\n defaultBadge: React.ReactNode\n ) => React.ReactNode\n desktopShaderProps?: Partial\n mobileShaderProps?: Partial\n}\n\nexport interface HeroHeatmapHeadingProps\n extends Omit, \"title\"> {\n title?: React.ReactNode\n subtitle?: React.ReactNode\n headingClassName?: string\n}\n\nexport interface HeroHeatmapDescriptionProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n description?: React.ReactNode\n descriptionClassName?: string\n}\n\nexport interface HeroHeatmapActionsProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n showCta?: boolean\n ctaProps?: Partial\n renderCta?: (defaultCta: React.ReactNode) => React.ReactNode\n}\n\nexport interface HeroHeatmapBadgesProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n showBadges?: boolean\n techStack?: HeroHeatmapTechItem[]\n renderBadge?: (\n tech: HeroHeatmapTechItem,\n index: number,\n defaultBadge: React.ReactNode\n ) => React.ReactNode\n}\n\nexport interface HeroHeatmapVisualProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n desktopShaderProps?: Partial\n desktopClassName?: string\n}\n\nexport interface HeroHeatmapMobileVisualProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n mobileShaderProps?: Partial\n}\n\nexport interface HeroHeatmapProps extends HeroHeatmapRootProps {\n containerClassName?: string\n contentClassName?: string\n headingWrapClassName?: string\n headingClassName?: string\n descriptionWrapClassName?: string\n descriptionClassName?: string\n ctaWrapClassName?: string\n badgesWrapClassName?: string\n visualClassName?: string\n mobileVisualClassName?: string\n}\n\ninterface HeroHeatmapContextValue {\n srTitle: string\n title: React.ReactNode\n subtitle: React.ReactNode\n description: React.ReactNode\n showCta: boolean\n mergedCtaProps: HeroHeatmapCTAProps\n renderCta?: (defaultCta: React.ReactNode) => React.ReactNode\n showBadges: boolean\n techStack: HeroHeatmapTechItem[]\n renderBadge?: HeroHeatmapBadgesProps[\"renderBadge\"]\n mergedDesktopShaderProps: Partial\n mergedMobileShaderProps: Partial\n}\n\nconst defaultDesktopShaderProps: Partial = {\n width: 1280,\n height: 720,\n image: \"/cult-icon.svg\",\n colors: [\n \"#112069\",\n \"#1f3ca3\",\n \"#367c66\",\n \"#adfa1e\",\n \"#ffe77a\",\n \"#ff9a1f\",\n \"#ed40b3\",\n ],\n colorBack: \"#000000\",\n contour: 0.5,\n angle: 0,\n noise: 0,\n innerGlow: 0.5,\n outerGlow: 0.5,\n speed: 1,\n scale: 0.55,\n}\n\nconst defaultMobileShaderProps: Partial = {\n image: \"/cult-icon.svg\",\n colors: [\n \"#112069\",\n \"#1f3ca3\",\n \"#367c66\",\n \"#adfa1e\",\n \"#ffe77a\",\n \"#ff9a1f\",\n \"#ed40b3\",\n ],\n colorBack: \"#00000000\",\n contour: 0.5,\n angle: 0,\n noise: 0,\n innerGlow: 0.4,\n outerGlow: 0.35,\n speed: 0.85,\n scale: 0.68,\n style: { height: \"100%\", width: \"100%\" },\n}\n\nconst defaultCtaProps: HeroHeatmapCTAProps = {\n label: \"Check it out today\",\n href: \"https://aisdkagents.com\",\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n}\n\nconst defaultDescription = (\n <>\n Full-stack vercel ai sdk patterns for workflows, tool calling, and agent\n orchestration. Built with{\" \"}\n ai sdk v6 and{\" \"}\n shadcn/ui.\n Headless, themable, practical.\n \n)\n\nconst defaultTechStack: HeroHeatmapTechItem[] = [\n {\n name: \"Next.js\",\n version: \"v16\",\n icon: NextjsIcon,\n },\n {\n name: \"AI SDK\",\n version: \"v6\",\n icon: AISDKIcon,\n },\n]\n\nconst HeroHeatmapContext = React.createContext<\n HeroHeatmapContextValue | undefined\n>(undefined)\n\nfunction useHeroHeatmapContext() {\n const context = React.useContext(HeroHeatmapContext)\n if (!context) {\n throw new Error(\n \"HeroHeatmap components must be used within HeroHeatmapRoot\"\n )\n }\n return context\n}\n\nexport function useHeroHeatmap() {\n return useHeroHeatmapContext()\n}\n\nexport const HeroHeatmapRoot = React.forwardRef<\n HTMLElement,\n HeroHeatmapRootProps\n>(({ className, children, srTitle = \"AI SDK Agents\", title = \n AI SDK Agents\n , subtitle = \"Copy and Paste\", description = defaultDescription, showCta = true, ctaProps, renderCta, showBadges = true, techStack = defaultTechStack, renderBadge, desktopShaderProps, mobileShaderProps, width, height, image, colors, colorBack, contour, angle, noise, innerGlow, outerGlow, speed, scale, ...props }, ref) => {\n const mergedCtaProps = React.useMemo(\n () => ({\n ...defaultCtaProps,\n ...ctaProps,\n }),\n [ctaProps]\n )\n\n const shaderOverrides = React.useMemo((): Partial => {\n const overrides: Partial = {}\n if (width !== undefined) overrides.width = width\n if (height !== undefined) overrides.height = height\n if (image !== undefined) overrides.image = image\n if (colors !== undefined) overrides.colors = colors\n if (colorBack !== undefined) overrides.colorBack = colorBack\n if (contour !== undefined) overrides.contour = contour\n if (angle !== undefined) overrides.angle = angle\n if (noise !== undefined) overrides.noise = noise\n if (innerGlow !== undefined) overrides.innerGlow = innerGlow\n if (outerGlow !== undefined) overrides.outerGlow = outerGlow\n if (speed !== undefined) overrides.speed = speed\n if (scale !== undefined) overrides.scale = scale\n return overrides\n }, [\n width,\n height,\n image,\n colors,\n colorBack,\n contour,\n angle,\n noise,\n innerGlow,\n outerGlow,\n speed,\n scale,\n ])\n\n const mergedDesktopShaderProps = React.useMemo(\n () => ({\n ...defaultDesktopShaderProps,\n ...shaderOverrides,\n ...desktopShaderProps,\n }),\n [shaderOverrides, desktopShaderProps]\n )\n\n const mergedMobileShaderProps = React.useMemo(\n () => ({\n ...defaultMobileShaderProps,\n ...shaderOverrides,\n ...mobileShaderProps,\n style: {\n ...(defaultMobileShaderProps.style as React.CSSProperties),\n ...(mobileShaderProps?.style as React.CSSProperties | undefined),\n },\n }),\n [shaderOverrides, mobileShaderProps]\n )\n\n const contextValue = React.useMemo(\n () => ({\n srTitle,\n title,\n subtitle,\n description,\n showCta,\n mergedCtaProps,\n renderCta,\n showBadges,\n techStack,\n renderBadge,\n mergedDesktopShaderProps,\n mergedMobileShaderProps,\n }),\n [\n srTitle,\n title,\n subtitle,\n description,\n showCta,\n mergedCtaProps,\n renderCta,\n showBadges,\n techStack,\n renderBadge,\n mergedDesktopShaderProps,\n mergedMobileShaderProps,\n ]\n )\n\n return (\n \n \n

{srTitle}

\n {children}\n \n
\n )\n})\nHeroHeatmapRoot.displayName = \"HeroHeatmapRoot\"\n\nexport function HeroHeatmapContainer({\n className,\n ...props\n}: React.ComponentPropsWithoutRef<\"div\">) {\n return (\n \n )\n}\n\nexport function HeroHeatmapContent({\n className,\n ...props\n}: React.ComponentPropsWithoutRef<\"div\">) {\n return (\n \n )\n}\n\nexport function HeroHeatmapHeading({\n className,\n title,\n subtitle,\n headingClassName,\n children,\n ...props\n}: HeroHeatmapHeadingProps) {\n const context = useHeroHeatmapContext()\n const resolvedTitle = title ?? context.title\n const resolvedSubtitle = subtitle ?? context.subtitle\n\n return (\n \n {children ?? (\n
\n \n {resolvedTitle}
\n {resolvedSubtitle}\n \n
\n )}\n \n )\n}\n\nexport function HeroHeatmapDescription({\n className,\n description,\n descriptionClassName,\n children,\n ...props\n}: HeroHeatmapDescriptionProps) {\n const context = useHeroHeatmapContext()\n const resolvedDescription = description ?? context.description\n\n return (\n \n {children ?? (\n \n {resolvedDescription}\n

\n )}\n \n )\n}\n\nexport function HeroHeatmapActions({\n className,\n showCta,\n ctaProps,\n renderCta,\n children,\n ...props\n}: HeroHeatmapActionsProps) {\n const context = useHeroHeatmapContext()\n const shouldShowCta = showCta ?? context.showCta\n const resolvedCtaProps = { ...context.mergedCtaProps, ...ctaProps }\n const resolvedRenderCta = renderCta ?? context.renderCta\n\n if (!shouldShowCta) {\n return null\n }\n\n const defaultCta = \n\n return (\n \n {children ??\n (resolvedRenderCta ? resolvedRenderCta(defaultCta) : defaultCta)}\n \n )\n}\n\nexport function HeroHeatmapCTA({\n label,\n href,\n target,\n rel,\n onClick,\n className,\n buttonClassName,\n}: HeroHeatmapCTAProps) {\n return (\n \n \n \n )\n}\n\nexport function HeroHeatmapBadges({\n className,\n showBadges,\n techStack,\n renderBadge,\n ...props\n}: HeroHeatmapBadgesProps) {\n const context = useHeroHeatmapContext()\n const shouldShowBadges = showBadges ?? context.showBadges\n const resolvedTechStack = techStack ?? context.techStack\n const resolvedRenderBadge = renderBadge ?? context.renderBadge\n\n if (!shouldShowBadges) {\n return null\n }\n\n return (\n \n {resolvedTechStack.map((tech, index) => {\n const Icon = tech.icon\n const defaultBadge = (\n \n {Icon ? : null}\n {tech.name}\n {tech.version ? (\n \n {tech.version}\n \n ) : null}\n \n )\n\n if (resolvedRenderBadge) {\n return (\n \n {resolvedRenderBadge(tech, index, defaultBadge)}\n \n )\n }\n\n return defaultBadge\n })}\n \n )\n}\n\nexport function HeroHeatmapVisual({\n className,\n desktopClassName,\n desktopShaderProps,\n ...props\n}: HeroHeatmapVisualProps) {\n const context = useHeroHeatmapContext()\n const resolvedDesktopShaderProps = {\n ...context.mergedDesktopShaderProps,\n ...desktopShaderProps,\n }\n\n return (\n