import { ChevronDown } from "lucide-react"; import { MODEL_OPTIONS } from "../constants/models"; import IBMLogo from "./icons/IBMLogo"; import HfLogo from "./icons/HfLogo"; import { useEffect, useRef } from "react"; // Define the structure of our animated dots interface Dot { x: number; y: number; vx: number; vy: number; radius: number; opacity: number; } export const LoadingScreen = ({ isLoading, progress, error, loadSelectedModel, selectedModelId, isModelDropdownOpen, setIsModelDropdownOpen, handleModelSelect, }: { isLoading: boolean; progress: number; error: string | null; loadSelectedModel: () => void; selectedModelId: string; isModelDropdownOpen: boolean; setIsModelDropdownOpen: (isOpen: boolean) => void; handleModelSelect: (modelId: string) => void; }) => { const model = MODEL_OPTIONS.find((opt) => opt.id === selectedModelId); const canvasRef = useRef(null); // Background Animation Effect useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); if (!ctx) return; let animationFrameId: number; let dots: Dot[] = []; const maxConnectionDistance = 130; // Max distance to draw a line between dots const dotSpeed = 0.3; // How fast dots move const setup = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; dots = []; // Adjust dot density based on screen area const numDots = Math.floor((canvas.width * canvas.height) / 20000); for (let i = 0; i < numDots; ++i) { dots.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, vx: (Math.random() - 0.5) * dotSpeed, // Random horizontal velocity vy: (Math.random() - 0.5) * dotSpeed, // Random vertical velocity radius: Math.random() * 1.5 + 0.5, opacity: Math.random() * 0.5 + 0.2, }); } }; const draw = () => { if (!ctx) return; ctx.clearRect(0, 0, canvas.width, canvas.height); // 1. Update and draw dots dots.forEach((dot) => { // Update position dot.x += dot.vx; dot.y += dot.vy; // Bounce off edges if (dot.x <= 0 || dot.x >= canvas.width) dot.vx *= -1; if (dot.y <= 0 || dot.y >= canvas.height) dot.vy *= -1; // Draw dot ctx.beginPath(); ctx.arc(dot.x, dot.y, dot.radius, 0, Math.PI * 2); ctx.fillStyle = `rgba(255, 255, 255, ${dot.opacity})`; ctx.fill(); }); // 2. Draw connecting lines ctx.lineWidth = 0.5; // Use a thin line for connections for (let i = 0; i < dots.length; i++) { for (let j = i + 1; j < dots.length; j++) { const dot1 = dots[i]; const dot2 = dots[j]; const dx = dot1.x - dot2.x; const dy = dot1.y - dot2.y; const distance = Math.sqrt(dx * dx + dy * dy); // If dots are close enough, draw a line if (distance < maxConnectionDistance) { // Calculate opacity based on distance (closer = more opaque) const opacity = 1 - distance / maxConnectionDistance; ctx.strokeStyle = `rgba(255, 255, 255, ${opacity * 0.3})`; // Faint white lines ctx.beginPath(); ctx.moveTo(dot1.x, dot1.y); ctx.lineTo(dot2.x, dot2.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 (
{/* Background Canvas for Animation */} {/* Vignette Overlay */}
{/* Main Content */}
×

Granite-4.0 WebGPU

In-browser tool calling, powered by Transformers.js

This demo showcases in-browser tool calling with Granite-4.0, a new series of models by{" "} IBM Granite {" "} designed for edge AI and on-device deployment.

Everything runs entirely in your browser with{" "} Transformers.js {" "} and ONNX Runtime Web, meaning no data is sent to a server. It can even run offline!

Select a model and click load to get started.

{isModelDropdownOpen && (
{MODEL_OPTIONS.map((option) => ( ))}
)}
{error && (

Error: {error}

)}
{/* Click-away listener for dropdown */} {isModelDropdownOpen && (
setIsModelDropdownOpen(false)} /> )}
); };