mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 10:11:31 +00:00
Merge branch 'main' into feature/add-to-scene-video-2
This commit is contained in:
4 files changed
+27
-158
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 3.5 MiB |
@@ -0,0 +1,19 @@
|
||||
|
||||
.tile-background-animation {
|
||||
background-image: url('/resources/images/tilebg.png');
|
||||
background-repeat: repeat;
|
||||
background-size: 512px;
|
||||
animation: background-animation-scrolling 60s linear infinite;
|
||||
-webkit-animation: background-animation-scrolling 60s linear infinite;
|
||||
filter: grayscale(100%);
|
||||
-webkit-filter: grayscale(100%);
|
||||
}
|
||||
|
||||
@keyframes background-animation-scrolling {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 512px 512px;
|
||||
}
|
||||
}
|
||||
@@ -1,168 +1,14 @@
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
|
||||
function getRandomImages(count: number) {
|
||||
const images = Array.from({ length: count }, (_, i) => ({
|
||||
id: i + 1,
|
||||
src: `/resources/images/generate/image${i + 1}.png`,
|
||||
alt: `Generated image ${i + 1}`,
|
||||
}));
|
||||
|
||||
// Shuffle the array
|
||||
return [...images].sort(() => Math.random() - 0.5);
|
||||
}
|
||||
|
||||
interface ImageColumnProps {
|
||||
images: Array<{ id: number; src: string; alt: string }>;
|
||||
delay: number;
|
||||
reverse?: boolean;
|
||||
isLoaded: boolean;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
function ImageColumn({
|
||||
images,
|
||||
delay,
|
||||
reverse = false,
|
||||
duration = 100,
|
||||
isLoaded,
|
||||
}: ImageColumnProps) {
|
||||
const columnRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!columnRef.current) return;
|
||||
|
||||
const column = columnRef.current;
|
||||
const animation = column.animate(
|
||||
[
|
||||
{ transform: reverse ? "translateY(-50%)" : "translateY(0)" },
|
||||
{ transform: reverse ? "translateY(0)" : "translateY(-50%)" },
|
||||
],
|
||||
{
|
||||
duration: duration * 1000,
|
||||
iterations: Infinity,
|
||||
easing: "linear",
|
||||
delay: delay + 1000,
|
||||
fill: "both",
|
||||
},
|
||||
);
|
||||
|
||||
if (!isLoaded) {
|
||||
animation.pause();
|
||||
}
|
||||
|
||||
return () => {
|
||||
animation.cancel();
|
||||
};
|
||||
}, [delay, duration, isLoaded, reverse]);
|
||||
|
||||
return (
|
||||
<div className="relative h-screen overflow-hidden">
|
||||
<div
|
||||
ref={columnRef}
|
||||
className="absolute left-0 right-0 flex flex-col gap-6"
|
||||
style={{
|
||||
transform: reverse ? "translateY(-50%)" : "translateY(0)",
|
||||
willChange: "transform",
|
||||
}}
|
||||
>
|
||||
{[...images, ...images].map((image, i) => (
|
||||
<div
|
||||
key={`${image.id}-${i}`}
|
||||
className={`relative aspect-[4/5] w-full overflow-hidden rounded-lg shadow-lg transition-all duration-700 ease-out ${
|
||||
isLoaded
|
||||
? "translate-y-0 opacity-100"
|
||||
: "translate-y-12 opacity-0"
|
||||
}`}
|
||||
style={{
|
||||
transitionDelay: `${delay + (i % images.length) * 50}ms`,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
className="h-full w-full object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
import "./Background.css";
|
||||
|
||||
export default function GalleryBackground() {
|
||||
const [images, _setImages] = useState(() => getRandomImages(20));
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// delay for smooth animation
|
||||
const timer = setTimeout(() => {
|
||||
setIsLoaded(true);
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Columns for masonry layout
|
||||
const columns = {
|
||||
col1: images.filter((_, i) => i % 5 === 0),
|
||||
col2: images.filter((_, i) => i % 5 === 1),
|
||||
col3: images.filter((_, i) => i % 5 === 2),
|
||||
col4: images.filter((_, i) => i % 5 === 3),
|
||||
col5: images.filter((_, i) => i % 5 === 4),
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="pointer-events-none fixed inset-0 z-[1] overflow-hidden bg-[radial-gradient(50%_50%_at_50%_50%,rgba(0,0,0,0.00)_49%,rgba(0,0,0,0.60)_100%)]" />
|
||||
<div className="fixed inset-0 z-0 overflow-hidden">
|
||||
<div className="fixed inset-0 z-0 overflow-hidden tile-background-animation">
|
||||
<div
|
||||
className={`h-full w-full transition-opacity duration-1000 ${isLoaded ? "opacity-30" : "opacity-0"}`}
|
||||
className={`h-full w-full transition-opacity duration-1000 opacity-30`}
|
||||
>
|
||||
<div className="absolute inset-0 grid grid-cols-5 gap-6 px-6 opacity-35">
|
||||
<ImageColumn
|
||||
images={columns.col1}
|
||||
delay={0}
|
||||
isLoaded={isLoaded}
|
||||
duration={100}
|
||||
/>
|
||||
<ImageColumn
|
||||
images={columns.col2}
|
||||
delay={columns.col1.length * 50}
|
||||
isLoaded={isLoaded}
|
||||
reverse={true}
|
||||
duration={100}
|
||||
/>
|
||||
<ImageColumn
|
||||
images={columns.col3}
|
||||
delay={(columns.col1.length + columns.col2.length) * 50}
|
||||
isLoaded={isLoaded}
|
||||
duration={125}
|
||||
/>
|
||||
<ImageColumn
|
||||
images={columns.col4}
|
||||
delay={
|
||||
(columns.col1.length +
|
||||
columns.col2.length +
|
||||
columns.col3.length) *
|
||||
50
|
||||
}
|
||||
isLoaded={isLoaded}
|
||||
reverse={true}
|
||||
duration={160}
|
||||
/>
|
||||
<ImageColumn
|
||||
images={columns.col5}
|
||||
delay={
|
||||
(columns.col1.length +
|
||||
columns.col2.length +
|
||||
columns.col3.length +
|
||||
columns.col4.length) *
|
||||
50
|
||||
}
|
||||
isLoaded={isLoaded}
|
||||
duration={110}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -196,12 +196,15 @@ export const PromptBoxVideo = ({
|
||||
};
|
||||
|
||||
const handleEnqueue = async () => {
|
||||
|
||||
setIsEnqueueing(true);
|
||||
|
||||
console.log("generateResponse", generateResponse);
|
||||
|
||||
const generateResponse = await FalKlingImageToVideo({
|
||||
image_media_token: referenceImages[0].mediaToken,
|
||||
});
|
||||
|
||||
console.log("generateResponse", generateResponse);
|
||||
onEnqueuePressed?.();
|
||||
if (generateResponse.status === CommandSuccessStatus.Success) {
|
||||
const prefs = await GetAppPreferences();
|
||||
@@ -245,6 +248,7 @@ export const PromptBoxVideo = ({
|
||||
// }
|
||||
// toast.error(errorMessage);
|
||||
// }
|
||||
|
||||
setIsEnqueueing(false);
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user