feat: initialize TJWater WebGIS frontend
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import type { RiveParameters } from "@rive-app/react-webgl2";
|
||||
import { useRive, useStateMachineInput } from "@rive-app/react-webgl2";
|
||||
import { memo, useEffect, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const RIVE_SOURCE = "https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/obsidian-2.0.riv";
|
||||
const STATE_MACHINE = "default";
|
||||
|
||||
function useDeferredRiveInit() {
|
||||
const [ready, setReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const id = requestAnimationFrame(() => setReady(true));
|
||||
return () => cancelAnimationFrame(id);
|
||||
}, []);
|
||||
|
||||
return ready;
|
||||
}
|
||||
|
||||
export type PersonaState = "idle" | "listening" | "thinking" | "speaking" | "asleep";
|
||||
|
||||
export type PersonaProps = {
|
||||
className?: string;
|
||||
onLoadError?: RiveParameters["onLoadError"];
|
||||
state?: PersonaState;
|
||||
};
|
||||
|
||||
export const Persona = memo(function Persona({
|
||||
className,
|
||||
onLoadError,
|
||||
state = "idle"
|
||||
}: PersonaProps) {
|
||||
const ready = useDeferredRiveInit();
|
||||
|
||||
const { rive, RiveComponent } = useRive(
|
||||
ready
|
||||
? {
|
||||
autoplay: true,
|
||||
onLoadError,
|
||||
src: RIVE_SOURCE,
|
||||
stateMachines: STATE_MACHINE
|
||||
}
|
||||
: null
|
||||
);
|
||||
|
||||
const listeningInput = useStateMachineInput(rive, STATE_MACHINE, "listening");
|
||||
const thinkingInput = useStateMachineInput(rive, STATE_MACHINE, "thinking");
|
||||
const speakingInput = useStateMachineInput(rive, STATE_MACHINE, "speaking");
|
||||
const asleepInput = useStateMachineInput(rive, STATE_MACHINE, "asleep");
|
||||
|
||||
useEffect(() => {
|
||||
if (listeningInput) {
|
||||
listeningInput.value = state === "listening";
|
||||
}
|
||||
if (thinkingInput) {
|
||||
thinkingInput.value = state === "thinking";
|
||||
}
|
||||
if (speakingInput) {
|
||||
speakingInput.value = state === "speaking";
|
||||
}
|
||||
if (asleepInput) {
|
||||
asleepInput.value = state === "asleep";
|
||||
}
|
||||
}, [state, listeningInput, thinkingInput, speakingInput, asleepInput]);
|
||||
|
||||
return (
|
||||
<RiveComponent
|
||||
className={cn("size-16 shrink-0", className)}
|
||||
style={{ filter: "brightness(0.45) contrast(1.35)" }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user