Gemma4-WebGPU / src /components /GemmaIntro.tsx
BryanBradfo's picture
Gemma 4 multimodal WebGPU detection Space
576d07a
Raw
History Blame Contribute Delete
2.68 kB
/**
* Liquid effect adapted from https://www.framer.com/@kevin-levron/
*/
import { useEffect, useRef, useCallback, useState } from "react";
import LiquidBackground from "../utils/liquid1.min.js";
type LiquidApp = ReturnType<typeof LiquidBackground>;
interface GemmaIntroProps {
onEnter: () => void;
}
export function GemmaIntro({ onEnter }: GemmaIntroProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);
const appRef = useRef<LiquidApp | null>(null);
const [fading, setFading] = useState(false);
const [ready, setReady] = useState(false);
useEffect(() => {
let disposed = false;
async function init() {
if (disposed || !canvasRef.current) return;
const app = LiquidBackground(canvasRef.current);
appRef.current = app;
app.loadImage("/gemma4.png");
app.liquidPlane.material.metalness = 0.82;
app.liquidPlane.material.roughness = 0.48;
app.liquidPlane.uniforms.displacementScale.value = 6;
app.setRain(false);
setTimeout(() => {
if (!disposed) setReady(true);
}, 300);
}
init();
return () => {
disposed = true;
if (appRef.current) {
appRef.current.dispose();
appRef.current = null;
}
};
}, []);
const handleClick = useCallback(() => {
if (fading) return;
setFading(true);
setTimeout(() => {
if (appRef.current) {
appRef.current.dispose();
appRef.current = null;
}
onEnter();
}, 600);
}, [fading, onEnter]);
return (
<div
className="absolute inset-0 z-30 cursor-pointer bg-black"
onClick={handleClick}
>
<canvas
ref={canvasRef}
className={`absolute inset-0 w-full h-full transition-opacity duration-700 ${
ready ? "opacity-100" : "opacity-0"
}`}
/>
<div
className={`absolute inset-0 flex flex-col items-center justify-end transition-opacity duration-500 pb-10 ${
fading ? "opacity-0" : ready ? "opacity-100" : "opacity-0"
}`}
>
<h1 className="text-6xl sm:text-7xl font-bold tracking-tight select-none drop-shadow-[0_2px_12px_rgba(0,0,0,0.5)]">
<span className="text-white">Gemma 4</span>{" "}
<span className="text-white/90">WebGPU</span>
</h1>
<p className="mt-6 text-lg text-white/80 select-none animate-pulse-gentle drop-shadow-[0_1px_6px_rgba(0,0,0,0.5)]">
Click anywhere to start
</p>
</div>
<div
className={`absolute inset-0 bg-black transition-opacity duration-600 pointer-events-none ${
fading ? "opacity-100" : "opacity-0"
}`}
/>
</div>
);
}