Spaces:
Running
Running
| import { useEffect, useRef } from "react"; | |
| interface Dot { | |
| x: number; | |
| y: number; | |
| vx: number; | |
| vy: number; | |
| radius: number; | |
| opacity: number; | |
| } | |
| export const LoadingScreen = ({ | |
| isLoading, | |
| progress, | |
| error, | |
| onLoad, | |
| }: { | |
| isLoading: boolean; | |
| progress: number; | |
| error: string | null; | |
| onLoad: () => void; | |
| }) => { | |
| const canvasRef = useRef<HTMLCanvasElement>(null); | |
| useEffect(() => { | |
| const canvas = canvasRef.current; | |
| if (!canvas) return; | |
| const ctx = canvas.getContext("2d"); | |
| if (!ctx) return; | |
| let animationFrameId: number; | |
| let dots: Dot[] = []; | |
| const setup = () => { | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| dots = []; | |
| const numDots = Math.floor((canvas.width * canvas.height) / 22000); | |
| for (let i = 0; i < numDots; ++i) { | |
| dots.push({ | |
| x: Math.random() * canvas.width, | |
| y: Math.random() * canvas.height, | |
| vx: (Math.random() - 0.5) * 0.3, | |
| vy: (Math.random() - 0.5) * 0.3, | |
| radius: Math.random() * 1.5 + 0.5, | |
| opacity: Math.random() * 0.4 + 0.15, | |
| }); | |
| } | |
| }; | |
| const draw = () => { | |
| if (!ctx) return; | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| dots.forEach((dot) => { | |
| dot.x += dot.vx; | |
| dot.y += dot.vy; | |
| if (dot.x <= 0 || dot.x >= canvas.width) dot.vx *= -1; | |
| if (dot.y <= 0 || dot.y >= canvas.height) dot.vy *= -1; | |
| ctx.beginPath(); | |
| ctx.arc(dot.x, dot.y, dot.radius, 0, Math.PI * 2); | |
| ctx.fillStyle = `rgba(74, 222, 128, ${dot.opacity})`; | |
| ctx.fill(); | |
| }); | |
| const maxDist = 120; | |
| ctx.lineWidth = 0.5; | |
| for (let i = 0; i < dots.length; i++) { | |
| for (let j = i + 1; j < dots.length; j++) { | |
| const dx = dots[i].x - dots[j].x; | |
| const dy = dots[i].y - dots[j].y; | |
| const distance = Math.sqrt(dx * dx + dy * dy); | |
| if (distance < maxDist) { | |
| const opacity = 1 - distance / maxDist; | |
| ctx.strokeStyle = `rgba(74, 222, 128, ${opacity * 0.2})`; | |
| ctx.beginPath(); | |
| ctx.moveTo(dots[i].x, dots[i].y); | |
| ctx.lineTo(dots[j].x, dots[j].y); | |
| ctx.stroke(); | |
| } | |
| } | |
| } | |
| animationFrameId = requestAnimationFrame(draw); | |
| }; | |
| const handleResize = () => { | |
| cancelAnimationFrame(animationFrameId); | |
| setup(); | |
| draw(); | |
| }; | |
| setup(); | |
| draw(); | |
| window.addEventListener("resize", handleResize); | |
| return () => { | |
| window.removeEventListener("resize", handleResize); | |
| cancelAnimationFrame(animationFrameId); | |
| }; | |
| }, []); | |
| return ( | |
| <div className="relative flex flex-col items-center justify-center h-screen bg-gradient-to-br from-[#0a0f1a] via-[#0d1520] to-[#060a12] text-gray-100 p-8 overflow-hidden"> | |
| <canvas | |
| ref={canvasRef} | |
| className="absolute top-0 left-0 w-full h-full z-0" | |
| /> | |
| <div className="absolute top-0 left-0 w-full h-full z-10 bg-[radial-gradient(ellipse_at_center,_rgba(10,15,26,0)_30%,_rgba(6,10,18,0.9)_95%)]" /> | |
| <div className="relative z-20 max-w-2xl w-full flex flex-col items-center bg-white/5 border border-white/10 backdrop-blur-xl rounded-3xl p-10 shadow-[0_35px_65px_rgba(0,0,0,0.5)] space-y-8"> | |
| <div className="flex flex-col items-center gap-3"> | |
| <div className="text-6xl">💻</div> | |
| <h1 className="text-4xl md:text-5xl font-bold text-white tracking-tight"> | |
| Maincoder <span className="text-emerald-400">1B</span> | |
| </h1> | |
| <p className="text-lg text-emerald-300/80"> | |
| In-browser code generation, powered by WebGPU | |
| </p> | |
| </div> | |
| <div className="w-full text-left text-gray-300 space-y-3 text-base"> | |
| <p> | |
| Run{" "} | |
| <a | |
| href="https://huggingface.co/Maincode/Maincoder-1B-ONNX" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-emerald-400 hover:underline font-medium" | |
| > | |
| Maincoder-1B | |
| </a>{" "} | |
| entirely in your browser using{" "} | |
| <a | |
| href="https://huggingface.co/docs/transformers.js" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-emerald-400 hover:underline font-medium" | |
| > | |
| Transformers.js | |
| </a>{" "} | |
| and WebGPU. No server, no data leaves your device. | |
| </p> | |
| <p className="text-sm text-gray-400"> | |
| A 1B-parameter code generation model achieving 76.2% on HumanEval | |
| (~600MB download, int4 quantized). Requires a WebGPU-capable browser | |
| (Chrome 113+). | |
| </p> | |
| </div> | |
| <div className="w-full max-w-md"> | |
| <button | |
| onClick={isLoading ? undefined : onLoad} | |
| disabled={isLoading} | |
| className={`w-full flex items-center justify-center font-semibold transition-all text-lg rounded-2xl border ${ | |
| isLoading | |
| ? "bg-white/5 text-gray-400 cursor-not-allowed border-white/10" | |
| : "bg-emerald-600 hover:bg-emerald-500 text-white border-emerald-500/50 shadow-[0_15px_35px_rgba(16,185,129,0.25)]" | |
| }`} | |
| > | |
| <div className="px-6 py-3.5"> | |
| {isLoading ? ( | |
| <div className="flex items-center"> | |
| <span className="inline-block w-5 h-5 border-2 border-emerald-400/80 border-t-transparent rounded-full animate-spin" /> | |
| <span className="ml-3 text-md font-medium text-emerald-300"> | |
| Downloading model... ({progress}%) | |
| </span> | |
| </div> | |
| ) : ( | |
| "Load Maincoder-1B" | |
| )} | |
| </div> | |
| </button> | |
| {isLoading && ( | |
| <div className="mt-4 w-full bg-white/10 rounded-full h-2 overflow-hidden"> | |
| <div | |
| className="h-full bg-gradient-to-r from-emerald-500 to-emerald-400 rounded-full transition-all duration-300" | |
| style={{ width: `${progress}%` }} | |
| /> | |
| </div> | |
| )} | |
| </div> | |
| {error && ( | |
| <div className="bg-red-900/30 border border-red-500/40 rounded-2xl p-4 w-full text-center"> | |
| <p className="text-sm text-red-300">Error: {error}</p> | |
| <button | |
| onClick={onLoad} | |
| className="mt-3 text-sm px-4 py-2 rounded-full bg-white/15 hover:bg-white/25 border border-white/20 text-white font-semibold transition-all" | |
| > | |
| Retry | |
| </button> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| }; | |