- Created a new utility script `lottie-to-svg.ts` to convert Lottie animations to SVG format using `bodymovin-to-smil`. - Added a new Lottie animation file `zipper.json` for the zipper animation. - Generated the corresponding SVG file `zipper.svg` from the Lottie animation. - Updated `deno.json` to include new dependencies and references for the zipper animation. - Modified `main.css` to introduce new color variables and styles for the zipper animation.
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { useBackground } from "../game-engine/background-provider.tsx";
|
|
import cn from "@bureaudouble/outils/cn.ts";
|
|
|
|
export default function GlobalBackgroundImageDisplay(
|
|
{ className }: { className?: string },
|
|
) {
|
|
const { backgroundState } = useBackground();
|
|
const [currentImage, setCurrentImage] = useState<string | null>(null);
|
|
const [currentOpacity, setCurrentOpacity] = useState<number>(0);
|
|
const imgRef = useRef<HTMLImageElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (backgroundState.imageUrl) {
|
|
// Preload image and then fade in
|
|
const img = new Image();
|
|
img.onload = () => {
|
|
setCurrentImage(backgroundState.imageUrl);
|
|
setCurrentOpacity(backgroundState.opacity);
|
|
};
|
|
img.src = backgroundState.imageUrl;
|
|
} else {
|
|
// // No image, fade out
|
|
// setCurrentOpacity(0);
|
|
// // Delay hiding the image to allow fade-out transition
|
|
// const timer = setTimeout(() => {
|
|
// setCurrentImage(null);
|
|
// }, 500); // Match CSS transition duration
|
|
// return () => clearTimeout(timer);
|
|
}
|
|
}, [backgroundState.imageUrl, backgroundState.opacity, backgroundState.key]);
|
|
|
|
const filters = [
|
|
"filter-[invert(1)_grayscale(100%)_sepia(100%)_hue-rotate(305deg)_saturate(150%)]",
|
|
"filter-[invert(100%)_grayscale(100%)_sepia(100%)_hue-rotate(305deg)_saturate(150%)_brightness(130%)] mix-blend-multiply",
|
|
"after:mix-blend-hard-light after:bg-mix-background after:z-10 after:inset-0 after:block after:relative after:size-full [&_img]:filter-[invert(1)_grayscale(1)_contrast(1.4)]",
|
|
];
|
|
|
|
return (
|
|
<div
|
|
key={backgroundState.key}
|
|
className={cn(
|
|
"absolute inset-0 z-0 pointer-events-none",
|
|
"fixed max-w-sm w-full m-auto",
|
|
filters.at(-1),
|
|
className,
|
|
)}
|
|
style={{
|
|
opacity: currentOpacity,
|
|
transition: "opacity 0.5s ease-in-out",
|
|
}}
|
|
>
|
|
{currentImage && (
|
|
<img
|
|
ref={imgRef}
|
|
src={currentImage}
|
|
alt="Narrative Background"
|
|
className="absolute inset-0 w-full h-full object-cover"
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|