Ministral_3B_WebGPU / src /components /WelcomeScreen.tsx
Jofthomas's picture
Add demo files (#1)
d5c6d34 verified
raw
history blame
8.08 kB
import Button from "./Button";
import { useState, useEffect } from "react";
import { THEME } from "../constants";
import HfIcon from "./HfIcon";
interface WelcomeScreenProps {
onStart: () => void;
}
export default function WelcomeScreen({ onStart }: WelcomeScreenProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<>
<div
className="absolute inset-0 flex items-center justify-center p-6 overflow-y-auto"
style={{
backgroundColor: THEME.beigeLight,
backgroundImage: `
linear-gradient(${THEME.beigeDark} 1px, transparent 1px),
linear-gradient(90deg, ${THEME.beigeDark} 1px, transparent 1px)
`,
backgroundSize: "40px 40px",
color: THEME.textBlack,
}}
>
<div
className={`relative max-w-4xl w-full backdrop-blur-sm p-10 md:p-12 rounded-sm border shadow-2xl transition-all duration-700 ${mounted ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
style={{
backgroundColor: `${THEME.beigeLight}F2`, // 95% opacity
borderColor: THEME.beigeDark,
}}
>
{/* 1. Top Right Status Indicator */}
<div className="absolute top-6 right-6 group cursor-help z-10">
<span className="absolute right-full mr-4 top-1/2 -translate-y-1/2 whitespace-nowrap text-xs font-mono uppercase tracking-widest text-gray-500 opacity-0 group-hover:opacity-100 transition-all duration-300 translate-x-2 group-hover:translate-x-0 pointer-events-none">
System Ready
</span>
<div className="relative flex h-3 w-3">
<span
className="animate-ping absolute inline-flex h-full w-full rounded-full opacity-75"
style={{ backgroundColor: THEME.mistralOrange }}
></span>
<span
className="relative inline-flex rounded-sm h-3 w-3"
style={{ backgroundColor: THEME.mistralOrange }}
></span>
</div>
</div>
<div className="space-y-12">
{/* Header Section */}
<div className="text-center space-y-4 animate-enter">
<div className="flex flex-col items-center justify-center space-y-5">
<div className="relative group">
<img
src="Ministral.png"
alt="Ministral Logo"
className="h-24 object-contain transition-transform duration-500 group-hover:scale-105 drop-shadow-sm"
/>
</div>
<h1
className="text-6xl md:text-7xl font-semibold tracking-tighter"
style={{ color: THEME.textBlack }}
>
Ministral WebGPU
</h1>
</div>
<p className="text-xl md:text-2xl text-gray-600 max-w-2xl mx-auto font-light leading-relaxed">
Frontier multimodal AI, running entirely in your browser.
<br />
Powered by{" "}
<a
href="https://huggingface.co/mistralai/Ministral-3-3B-Instruct-2512-ONNX"
className="font-medium underline decoration-2 underline-offset-4 transition-all hover:decoration-[3px]"
style={{
color: THEME.mistralOrange,
textDecorationColor: THEME.mistralOrange,
}}
target="_blank"
rel="noopener noreferrer"
>
Ministral-3-3B
</a>
</p>
</div>
{/* Content Grid */}
<div
className="grid grid-cols-1 md:grid-cols-3 gap-8 border-t border-b py-10 animate-enter delay-100"
style={{ borderColor: THEME.beigeDark }}
>
{/* Feature 1 */}
<div className="space-y-3 group">
<div
className="w-10 h-10 flex items-center justify-center text-white font-bold text-lg shadow-sm transition-transform duration-300 group-hover:-translate-y-1"
style={{ backgroundColor: THEME.mistralOrange }}
>
1
</div>
<h4
className="font-semibold text-xl"
style={{ color: THEME.textBlack }}
>
Load Model
</h4>
<p className="text-gray-600 leading-relaxed">
Downloads the optimized Ministral model (~3GB) directly to
your browser cache.
</p>
</div>
{/* Feature 2 */}
<div className="space-y-3 group">
<div
className="w-10 h-10 flex items-center justify-center text-white font-bold text-lg shadow-sm transition-transform duration-300 group-hover:-translate-y-1"
style={{ backgroundColor: THEME.mistralOrange }}
>
2
</div>
<h4
className="font-semibold text-xl"
style={{ color: THEME.textBlack }}
>
Private & Local
</h4>
<p className="text-gray-600 leading-relaxed">
Your video feed is processed locally and never sent to a
server, powered by
<a href="https://github.com/huggingface/transformers.js">
<span className="font-medium underline">
<HfIcon className="size-6 ml-1 mt-[-1px] inline" />
Transformers.js
</span>
</a>
.
</p>
</div>
{/* Feature 3 */}
<div className="space-y-3 group">
<div
className="w-10 h-10 flex items-center justify-center text-white font-bold text-lg shadow-sm transition-transform duration-300 group-hover:-translate-y-1"
style={{ backgroundColor: THEME.mistralOrange }}
>
3
</div>
<h4
className="font-semibold text-xl"
style={{ color: THEME.textBlack }}
>
Real-time Vision
</h4>
<p className="text-gray-600 leading-relaxed">
The model analyzes the current frame and responds to the
user's prompt.
</p>
</div>
</div>
{/* Action Area */}
<div className="flex flex-col items-center animate-enter delay-200">
<Button
onClick={onStart}
className="group relative px-8 py-5 text-white overflow-hidden transition-all hover:shadow-2xl hover:-translate-y-0.5"
>
<div className="absolute inset-0 bg-white/20 translate-y-full group-hover:translate-y-0 transition-transform duration-300 ease-out" />
<span className="relative font-bold text-xl tracking-wide flex items-center gap-3">
START LIVE CAPTIONING
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2.5}
stroke="currentColor"
className="w-5 h-5 transition-transform duration-300 group-hover:translate-x-1"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3"
/>
</svg>
</span>
</Button>
</div>
</div>
</div>
</div>
</>
);
}