{
  "title": "Browser Support",
  "description": "Detects browser local AI support and guides users through enabling Chrome Built-in AI",
  "name": "native-ai-browser-support",
  "dependencies": [
    "copy-to-clipboard"
  ],
  "registryDependencies": [
    "alert",
    "button",
    "card",
    "tabs"
  ],
  "type": "registry:ui",
  "files": [
    {
      "path": "components/paceui/native-ai/browser-support/index.tsx",
      "type": "registry:ui",
      "content": "import { type ReactNode, useState } from \"react\";\n\nimport copy from \"copy-to-clipboard\";\nimport { Check, CheckCircle2, Copy, Cpu, Loader2, RefreshCw, Smartphone } from \"lucide-react\";\n\nimport { SUPPORTED_NATIVE_BROWSERS, useBrowserSupport } from \"@/hooks/native-ai/use-browser-support\";\nimport { cn } from \"@/lib/utils.ts\";\n\nimport { Alert, AlertDescription, AlertTitle } from \"@/components/ui/alert\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\n\ntype SupportedBrowser = \"chrome\" | \"firefox\" | \"edge\" | \"safari\";\n\nconst BROWSER_INSTRUCTIONS: Record<SupportedBrowser, ReactNode[]> = {\n    chrome: [\n        <>\n            <CopyableCode>chrome://settings/system</CopyableCode>: Ensure Hardware Acceleration\n        </>,\n        <>\n            <CopyableCode>chrome://flags/#prompt-api-for-gemini-nano</CopyableCode>: Set it to{\" \"}\n            <span className=\"font-medium\">Enabled</span>.\n        </>,\n        <>\n            <CopyableCode>chrome://flags/#optimization-guide-on-device-model</CopyableCode>: Set it to{\" \"}\n            <span className=\"font-medium\">Enabled BypassPerfRequirement</span>.\n        </>,\n        <>\n            <CopyableCode>chrome://components</CopyableCode>: Local{\" \"}\n            <span className=\"text-foreground font-medium\">Optimization Guide On Device Model</span>, and click{\" \"}\n            <span className=\"text-foreground font-medium\">Check for update</span> to finish downloading the local model.\n        </>,\n        <>\n            Click <span className=\"text-foreground font-medium\">Relaunch</span> to restart Chrome.\n        </>,\n    ],\n    firefox: [\n        <>\n            Open <CopyableCode>about:config</CopyableCode> in your address bar and accept the warning.\n        </>,\n        <>\n            Search for <span className=\"font-medium\">dom.webgpu.enabled</span> and set it to{\" \"}\n            <span className=\"text-foreground font-medium\">true</span>.\n        </>,\n        <>\n            Search for <span className=\"font-medium\">gfx.webrender.all</span> and ensure it is set to{\" \"}\n            <span className=\"text-foreground font-medium\">true</span> for GPU acceleration.\n        </>,\n        <>Restart Firefox to enable WebGPU hardware-accelerated local AI execution.</>,\n    ],\n    edge: [\n        <>\n            Open <CopyableCode>edge://settings/system</CopyableCode> and ensure{\" \"}\n            <span className=\"text-foreground font-medium\">Use graphics acceleration when available</span> is ON.\n        </>,\n        <>\n            Navigate to <CopyableCode>edge://flags/#enable-webgpu-developer-features</CopyableCode> and set to{\" \"}\n            <span className=\"text-foreground font-medium\">Enabled</span>.\n        </>,\n        <>\n            Optional (Edge Dev/Canary): Open <CopyableCode>edge://flags/#prompt-api-for-gemini-nano</CopyableCode> and\n            set to <span className=\"text-foreground font-medium\">Enabled</span>.\n        </>,\n        <>\n            Click <span className=\"text-foreground font-medium\">Restart</span> to reload Edge and activate local model\n            execution.\n        </>,\n    ],\n    safari: [\n        <>\n            Open Safari <span className=\"font-medium\">Settings</span> (\n            <kbd className=\"bg-muted/80 rounded border px-1.5 py-0.5 font-mono text-xs\">⌘ ,</kbd>) and switch to the{\" \"}\n            <span className=\"text-foreground font-medium\">Advanced</span> tab.\n        </>,\n        <>\n            Check <span className=\"text-foreground font-medium\">\"Show features for web developers\"</span> at the bottom.\n        </>,\n        <>\n            In the top menu bar, open <span className=\"text-foreground font-medium\">Develop &gt; Feature Flags</span>{\" \"}\n            and ensure <span className=\"text-foreground font-medium\">WebGPU</span> is checked.\n        </>,\n        <>Reload the page to execute models locally on Apple Silicon / Metal GPU.</>,\n    ],\n};\n\nfunction CopyableCode({ children }: { children: string }) {\n    const [copied, setCopied] = useState(false);\n\n    const handleCopy = async () => {\n        const success = await copy(children);\n        if (success) {\n            setCopied(true);\n            setTimeout(() => setCopied(false), 2000);\n        }\n    };\n\n    return (\n        <Button\n            type=\"button\"\n            onClick={handleCopy}\n            title=\"Click to copy URL\"\n            size=\"sm\"\n            className=\"gap-1.5 px-2.5\"\n            variant=\"secondary\">\n            <span>{children}</span>\n            {copied ? (\n                <Check className=\"size-3.5 shrink-0 text-emerald-500\" />\n            ) : (\n                <Copy className=\"size-3.5 shrink-0 opacity-60 transition-opacity hover:opacity-100\" />\n            )}\n        </Button>\n    );\n}\n\nfunction BrowserTabContent({ browser }: { browser: SupportedBrowser }) {\n    const isSupported = SUPPORTED_NATIVE_BROWSERS.includes(browser);\n\n    if (!isSupported) {\n        return (\n            <div className=\"text-muted-foreground rounded-md border border-dashed p-6 text-center text-sm\">\n                This browser is not yet supported natively. Please use a supported browser like Chrome.\n            </div>\n        );\n    }\n\n    return (\n        <ol className=\"list-inside list-decimal space-y-3 text-sm leading-relaxed\">\n            {BROWSER_INSTRUCTIONS[browser].map((step, idx) => (\n                <li key={idx}>{step}</li>\n            ))}\n        </ol>\n    );\n}\n\nexport const BrowserSupport = ({ className }: { className?: string }) => {\n    const { isLoading, isSupported, isMobile, engine, errorReason, detectedBrowser, recheck } = useBrowserSupport();\n    const browsers: SupportedBrowser[] = [\"chrome\", \"firefox\", \"edge\", \"safari\"];\n\n    if (isLoading) {\n        return (\n            <Card className=\"mx-auto my-8 w-full max-w-2xl p-8 text-center shadow-md\">\n                <Loader2 className=\"text-muted-foreground mx-auto h-8 w-8 animate-spin\" />\n                <p className=\"text-muted-foreground mt-2 text-sm\">Checking browser AI support...</p>\n            </Card>\n        );\n    }\n\n    return (\n        <Card className={cn(\"flex flex-col border-none shadow-none\", className)}>\n            <CardHeader>\n                <CardTitle className=\"text-lg\">Native AI Browser Support</CardTitle>\n                <CardDescription>\n                    {isSupported\n                        ? engine === \"polyfill-webllm\"\n                            ? \"Your browser is ready with WebGPU local AI fallback processing.\"\n                            : \"Your browser is successfully configured for Chrome native AI processing.\"\n                        : isMobile\n                          ? \"Mobile devices are not supported yet. Please switch to a desktop browser.\"\n                          : \"This application requires built-in local AI or WebGPU hardware acceleration on your device.\"}\n                </CardDescription>\n            </CardHeader>\n\n            <CardContent className=\"flex min-h-0 grow flex-col\">\n                <Alert variant={isMobile ? \"destructive\" : \"default\"}>\n                    {isSupported ? (\n                        <CheckCircle2 className=\"size-4.5\" />\n                    ) : isMobile ? (\n                        <Smartphone className=\"size-4\" />\n                    ) : (\n                        <Cpu className=\"size-4\" />\n                    )}\n                    <AlertTitle className=\"font-medium\">\n                        {isSupported\n                            ? \"You're ready to go!\"\n                            : isMobile\n                              ? \"Mobile Devices Not Supported\"\n                              : \"AI Support Check Failed\"}\n                    </AlertTitle>\n                    <AlertDescription className=\"mt-1 text-xs leading-relaxed opacity-90\">\n                        {isSupported\n                            ? engine === \"polyfill-webllm\"\n                                ? \"WebGPU Local AI Polyfill is active on your browser. AI tasks run 100% on your device.\"\n                                : \"Chrome Built-in AI is active on your device. You can start typing and generating text locally.\"\n                            : errorReason ||\n                              \"Your browser does not currently support local AI APIs or WebGPU acceleration.\"}\n                    </AlertDescription>\n                </Alert>\n\n                <div className=\"custom-scrollbar grow overflow-y-auto\">\n                    <Tabs defaultValue={detectedBrowser} className=\"mt-4 w-full\">\n                        <TabsList className=\"bg-muted/60 p-1\">\n                            {browsers.map((browser) => (\n                                <TabsTrigger\n                                    key={browser}\n                                    value={browser}\n                                    className=\"font-medium capitalize shadow-none\">\n                                    {browser}\n                                </TabsTrigger>\n                            ))}\n                        </TabsList>\n\n                        {browsers.map((browser) => (\n                            <TabsContent key={browser} value={browser} className=\"mt-3\">\n                                <BrowserTabContent browser={browser} />\n                            </TabsContent>\n                        ))}\n                    </Tabs>\n                </div>\n            </CardContent>\n\n            <CardFooter className=\"flex justify-end px-6\">\n                <Button onClick={recheck} variant=\"outline\" className=\"gap-2.5\">\n                    <RefreshCw className=\"size-4\" />\n                    Re-check Support\n                </Button>\n            </CardFooter>\n        </Card>\n    );\n};\n\nexport { BrowserSupport as SetupCard, BrowserSupport as NativeAiBrowserSupport };\n"
    },
    {
      "path": "hooks/native-ai/use-browser-support.ts",
      "type": "registry:ui",
      "content": "import { useCallback, useEffect, useState } from \"react\";\n\nexport type BrowserType = \"chrome\" | \"firefox\" | \"edge\" | \"safari\";\n\nexport const SUPPORTED_NATIVE_BROWSERS: BrowserType[] = [\"chrome\"];\n\nexport type AIEngine = \"chrome-native\" | \"polyfill-webllm\";\n\nexport function detectMobile(): boolean {\n    if (typeof window === \"undefined\" || !navigator?.userAgent) {\n        return false;\n    }\n\n    const ua = navigator.userAgent;\n    const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i.test(ua);\n    const isCoarsePointer = typeof window.matchMedia === \"function\" && window.matchMedia(\"(pointer: coarse)\").matches;\n\n    return isMobileUA || (isCoarsePointer && \"ontouchstart\" in window);\n}\n\nexport function detectBrowser(): BrowserType {\n    if (typeof window === \"undefined\" || !navigator?.userAgent) {\n        return \"chrome\";\n    }\n\n    const ua = navigator.userAgent;\n    if (ua.includes(\"Edg/\")) return \"edge\";\n    if (ua.includes(\"Firefox\") || ua.includes(\"FxIOS\")) return \"firefox\";\n    if (ua.includes(\"Safari\") && !ua.includes(\"Chrome\") && !ua.includes(\"Chromium\")) return \"safari\";\n    if (ua.includes(\"Chrome\") || ua.includes(\"Chromium\")) return \"chrome\";\n\n    return \"chrome\";\n}\n\nexport const useBrowserSupport = () => {\n    const [isLoading, setIsLoading] = useState<boolean>(true);\n    const [isSupported, setIsSupported] = useState<boolean>(false);\n    const [isMobile, setIsMobile] = useState<boolean>(false);\n    const [engine, setEngine] = useState<AIEngine | null>(null);\n    const [errorReason, setErrorReason] = useState<string | undefined>(undefined);\n    const [detectedBrowser, setDetectedBrowser] = useState<BrowserType>(\"chrome\");\n    const [canEnable, setCanEnable] = useState<boolean>(false);\n\n    const checkSupport = useCallback(async () => {\n        setIsLoading(true);\n        const mobile = detectMobile();\n        setIsMobile(mobile);\n\n        const browser = detectBrowser();\n        setDetectedBrowser(browser);\n\n        if (mobile) {\n            setIsSupported(false);\n            setCanEnable(false);\n            setEngine(null);\n            setErrorReason(\n                \"Mobile devices are not supported yet. Native AI requires desktop browsers with hardware acceleration.\",\n            );\n            setIsLoading(false);\n            return;\n        }\n\n        const canBeEnabled = SUPPORTED_NATIVE_BROWSERS.includes(browser);\n        setCanEnable(canBeEnabled);\n\n        const globalLangModel =\n            typeof window !== \"undefined\" ? (window as any).LanguageModel || (window as any).ai?.languageModel : null;\n        const hasChromeAI = !!(globalLangModel && !globalLangModel.__isPolyfill);\n\n        if (hasChromeAI) {\n            setIsSupported(true);\n            setEngine(\"chrome-native\");\n            setErrorReason(undefined);\n        } else {\n            setIsSupported(false);\n            setEngine(null);\n            setErrorReason(\n                browser === \"chrome\"\n                    ? \"Chrome Built-in AI is not enabled or missing model flags in your browser.\"\n                    : `${browser.charAt(0).toUpperCase() + browser.slice(1)} does not currently support Chrome's native AI APIs. Use Chrome with AI flags.`,\n            );\n        }\n\n        setIsLoading(false);\n    }, []);\n\n    useEffect(() => {\n        checkSupport();\n    }, [checkSupport]);\n\n    return {\n        isLoading,\n        isSupported,\n        isMobile,\n        engine,\n        errorReason,\n        detectedBrowser,\n        canEnable,\n        recheck: checkSupport,\n    };\n};\n"
    }
  ],
  "mcp": {
    "description": "Device-local AI-powered functionality. Detects browser local AI support and guides users through enabling Chrome Built-in AI Ideal for privacy-first AI interfaces, streaming text responses, and Chrome Gemini Nano integrations.",
    "tags": [
      "native-ai",
      "ui"
    ]
  }
}