Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37ef8fd96a | ||
|
|
b1446916bb | ||
|
|
c1c1d694ab |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 564 KiB After Width: | Height: | Size: 297 KiB |
|
Before Width: | Height: | Size: 366 KiB After Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 452 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 337 KiB After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 378 KiB After Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 302 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 446 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 396 KiB After Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 521 KiB After Width: | Height: | Size: 272 KiB |
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 396 KiB After Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 316 KiB After Width: | Height: | Size: 183 KiB |
@@ -1,18 +1,92 @@
|
||||
.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 fadeInScale {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes background-animation-scrolling {
|
||||
.image-fade-in {
|
||||
animation: fadeInScale 0.8s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
@keyframes floatY {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
transform: translateY(0px) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-12px) scale(1.03);
|
||||
}
|
||||
100% {
|
||||
background-position: 512px 512px;
|
||||
transform: translateY(0px) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.image-float {
|
||||
animation: floatY 5s ease-in-out infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* Staggered delays for up to 10 images per column */
|
||||
.image-float:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
.image-float:nth-child(2) {
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
.image-float:nth-child(3) {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
.image-float:nth-child(4) {
|
||||
animation-delay: 1.5s;
|
||||
}
|
||||
.image-float:nth-child(5) {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
.image-float:nth-child(6) {
|
||||
animation-delay: 2.5s;
|
||||
}
|
||||
.image-float:nth-child(7) {
|
||||
animation-delay: 3s;
|
||||
}
|
||||
.image-float:nth-child(8) {
|
||||
animation-delay: 3.5s;
|
||||
}
|
||||
.image-float:nth-child(9) {
|
||||
animation-delay: 4s;
|
||||
}
|
||||
.image-float:nth-child(10) {
|
||||
animation-delay: 4.5s;
|
||||
}
|
||||
|
||||
@keyframes columnUp {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-40px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes columnDown {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(40px);
|
||||
}
|
||||
}
|
||||
|
||||
.column-marquee-up {
|
||||
animation: columnUp 8s linear infinite alternate;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.column-marquee-down {
|
||||
animation: columnDown 8s linear infinite alternate;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,70 @@
|
||||
import { useState } from "react";
|
||||
import "./Background.css";
|
||||
|
||||
function getStaticImages(count: number) {
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
id: i + 1,
|
||||
src: `resources/images/generate/image${i + 1}.png`,
|
||||
alt: `Generated image ${i + 1}`,
|
||||
}));
|
||||
}
|
||||
|
||||
export default function GalleryBackground() {
|
||||
const [frozen] = useState(false); // change this to true to make it static if it impacts pc performance - BFlat
|
||||
const [images] = useState(() => {
|
||||
const imgs = getStaticImages(20);
|
||||
for (let i = imgs.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[imgs[i], imgs[j]] = [imgs[j], imgs[i]];
|
||||
}
|
||||
return imgs;
|
||||
});
|
||||
// Distribute images into 5 columns
|
||||
const columns = [[], [], [], [], []] as Array<typeof images>;
|
||||
images.forEach((img, i) => {
|
||||
columns[i % 5].push(img);
|
||||
});
|
||||
|
||||
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="tile-background-animation fixed inset-0 z-0 overflow-hidden">
|
||||
<div
|
||||
className={`h-full w-full opacity-30 transition-opacity duration-1000`}
|
||||
>
|
||||
<div className="absolute inset-0 grid grid-cols-5 gap-6 px-6 opacity-35" />
|
||||
<div className="fixed inset-0 z-0 overflow-hidden">
|
||||
<div className="h-full w-full">
|
||||
<div className="pointer-events-none absolute inset-0 grid grid-cols-5 gap-6 px-6 opacity-15">
|
||||
{columns.map((col, colIdx) => {
|
||||
// Vertical offset classes for each column
|
||||
const offsetClasses = [
|
||||
"-mt-20", // col 0
|
||||
"mt-5", // col 1
|
||||
"-mt-48", // col 2
|
||||
"mt-3", // col 3
|
||||
"-mt-16", // col 4
|
||||
];
|
||||
// Alternate marquee direction
|
||||
const marqueeClass =
|
||||
colIdx % 2 === 0 ? "column-marquee-up" : "column-marquee-down";
|
||||
return (
|
||||
<div
|
||||
key={colIdx}
|
||||
className={`flex flex-col gap-6 ${offsetClasses[colIdx]} ${!frozen ? marqueeClass : ""}`}
|
||||
>
|
||||
{col.map((image) => (
|
||||
<div
|
||||
key={image.id}
|
||||
className="relative aspect-[4/5] w-full overflow-hidden rounded-lg shadow-lg"
|
||||
>
|
||||
<img
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
className="image-fade-in h-full w-full object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { JobContextType } from "libs/common/src/lib/types";
|
||||
import { PromptBoxImage } from "@storyteller/ui-promptbox";
|
||||
import BackgroundGallery from "./BackgroundGallery";
|
||||
import { PopoverMenu, type PopoverItem } from "@storyteller/ui-popover";
|
||||
import { faFilm, faClock } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { faClock, faImage } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
interface TextToImageProps {
|
||||
@@ -13,7 +13,9 @@ interface TextToImageProps {
|
||||
|
||||
const TextToImage = ({ imageMediaId, imageUrl }: TextToImageProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [selectedModel, setSelectedModel] = useState<string>("GPT Image 1 (GPT-4o)");
|
||||
const [selectedModel, setSelectedModel] = useState<string>(
|
||||
"GPT Image 1 (GPT-4o)",
|
||||
);
|
||||
const [useSystemPrompt, setUseSystemPrompt] = useState(false);
|
||||
const [isImageBeingProcessed, setIsImageBeingProcessed] = useState(false);
|
||||
const [selectedImage, setSelectedImage] = useState<File | null>(null);
|
||||
@@ -30,21 +32,21 @@ const TextToImage = ({ imageMediaId, imageUrl }: TextToImageProps) => {
|
||||
const modelList: PopoverItem[] = [
|
||||
{
|
||||
label: "GPT Image 1 (GPT-4o)",
|
||||
icon: <FontAwesomeIcon icon={faFilm} className="h-4 w-4" />,
|
||||
icon: <FontAwesomeIcon icon={faImage} className="h-4 w-4" />,
|
||||
selected: selectedModel === "GPT Image 1 (GPT-4o)",
|
||||
description: "Slow, ultra instructive model",
|
||||
badges: [{ label: "45 sec.", icon: <FontAwesomeIcon icon={faClock} /> }],
|
||||
},
|
||||
{
|
||||
label: "Flux Pro Ultra",
|
||||
icon: <FontAwesomeIcon icon={faFilm} className="h-4 w-4" />,
|
||||
icon: <FontAwesomeIcon icon={faImage} className="h-4 w-4" />,
|
||||
selected: selectedModel === "Flux Pro Ultra",
|
||||
description: "High quality model",
|
||||
badges: [{ label: "15 sec.", icon: <FontAwesomeIcon icon={faClock} /> }],
|
||||
},
|
||||
{
|
||||
label: "Recraft 3",
|
||||
icon: <FontAwesomeIcon icon={faFilm} className="h-4 w-4" />,
|
||||
icon: <FontAwesomeIcon icon={faImage} className="h-4 w-4" />,
|
||||
selected: selectedModel === "Recraft 3",
|
||||
description: "Fast and high-quality model",
|
||||
badges: [{ label: "15 sec.", icon: <FontAwesomeIcon icon={faClock} /> }],
|
||||
|
||||