Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

## Features

- 🎨 **13+ AI Models** — Choose from Nano Banana Pro, GPT 1.5, Seedream, Veo 3.1, Seedance and more
- ⚡ **Generous Limits** — 5000~ Z-image turbo generations per day
- 🎨 **6 AI Models** — Choose from Flux Schnell, Z-Image Turbo, GPT Image, FLUX.2 Klein, and Seedance
- ⚡ **Generous Limits** — Up to 900,000 Flux Schnell generations per month (180 high-quality images)
- 📐 **Full Dimension Control** — Create logos, banners, or any custom image size
- 💾 **Cloud History** — Access your generated images from any device
- 🔐 **Secure Auth** — Powered by Clerk with SSO support
Expand Down
6 changes: 3 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const metadata: Metadata = {
template: "%s | Bloom Studio",
},
description:
"Bloom Studio, a cheap and powerful AI image generator and video generator studio. Featuring Nano Banana Pro, Veo, GPT 1.5, Seedream 4.5 and more. Try for free.",
"Bloom Studio, a cheap and powerful AI image generator and video generator studio. Featuring Flux Schnell, Z-Image Turbo, GPT Image, FLUX.2 Klein, and Seedance. Try for free.",
metadataBase: new URL(process.env.NEXT_PUBLIC_APP_URL || "https://bloomstudio.fun"),
applicationName: "Bloom Studio",
authors: [{ name: "Bloom Studio Team" }],
Expand Down Expand Up @@ -85,7 +85,7 @@ export const metadata: Metadata = {
url: "/",
title: "Bloom Studio - Cheap and Powerful AI Image & Video Generator",
description:
"Bloom Studio, a cheap and powerful AI image generator and video generator studio. Featuring Nano Banana Pro, Veo, GPT 1.5, Seedream 4.5 and more. Try for free.",
"Bloom Studio, a cheap and powerful AI image generator and video generator studio. Featuring Flux Schnell, Z-Image Turbo, GPT Image, FLUX.2 Klein, and Seedance. Try for free.",
siteName: "Bloom Studio",
images: [
{
Expand All @@ -100,7 +100,7 @@ export const metadata: Metadata = {
card: "summary_large_image",
title: "Bloom Studio - Cheap and Powerful AI Image & Video Generator",
description:
"Bloom Studio, a cheap and powerful AI image generator and video generator studio. Featuring Nano Banana Pro, Veo, GPT 1.5, Seedream 4.5 and more. Try for free.",
"Bloom Studio, a cheap and powerful AI image generator and video generator studio. Featuring Flux Schnell, Z-Image Turbo, GPT Image, FLUX.2 Klein, and Seedance. Try for free.",
images: ["/branding/bloom-studio_logo.png"],
creator: "@bloomstudio",
},
Expand Down
38 changes: 2 additions & 36 deletions app/pricing/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default function PricingPage() {
"@context": "https://schema.org",
"@type": "Product",
name: "Bloom Studio Pro",
description: "Professional AI image and video generation subscription. Includes 180 images/month, all models (Flux, Veo, etc), and private generations.",
description: "Professional AI image and video generation subscription. Includes 180 images/month, all active models (Flux, GPT Image, Z-Image, Klein, Seedance), and private generations.",
image: "https://bloomstudio.fun/branding/bloom-studio_logo.png",
offers: {
"@type": "Offer",
Expand Down Expand Up @@ -121,26 +121,7 @@ export default function PricingPage() {
</div>

<div className="mb-6">
<p className="text-sm text-muted-foreground">
{tier.description.includes("Nano Banana Pro") ? (
<span className="flex items-center gap-1 flex-wrap">
{tier.description.split("Nano Banana Pro")[0]}
<span className="inline-flex items-center gap-1 font-semibold text-foreground/90">
<Image
src="/image-models/google.svg"
alt="Gemini"
width={12}
height={12}
className="opacity-80 contrast-125"
/>
Nano Banana Pro
</span>
{tier.description.split("Nano Banana Pro")[1]}
</span>
) : (
tier.description
)}
</p>
<p className="text-sm text-muted-foreground">{tier.description}</p>
{tier.poweredBy && tier.name !== "Pro" && (
<div className="flex items-center gap-1.5 mt-2.5 text-[10px] uppercase tracking-wider font-bold text-muted-foreground bg-muted/50 py-1 px-2 rounded-md border border-border/50 w-fit">
<Image
Expand Down Expand Up @@ -200,21 +181,6 @@ export default function PricingPage() {
{feature}
<ArrowRight className="h-3.5 w-3.5 text-green-600" />
</span>
) : feature.includes("Nano Banana Pro") ? (
<span className="flex items-center gap-1 flex-wrap">
{feature.split("Nano Banana Pro")[0]}
<span className="inline-flex items-center gap-1 font-semibold text-foreground/90">
<Image
src="/image-models/google.svg"
alt="Gemini"
width={12}
height={12}
className="opacity-80 contrast-125"
/>
Nano Banana Pro
</span>
{feature.split("Nano Banana Pro")[1]}
</span>
) : (
feature
)}
Expand Down
14 changes: 7 additions & 7 deletions app/pricing/pricing-data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export const pricingTiers: PricingTier[] = [
name: "Pro",
description: "Access to every feature and model",
poweredBy: {
name: "Nano Banana Pro",
logo: "/image-models/google.svg",
name: "Flux Schnell",
logo: "/image-models/flux.svg",
},
price: 3,
icon: Crown,
Expand All @@ -46,9 +46,9 @@ export const pricingTiers: PricingTier[] = [
cta: "Upgrade to Pro",
ctaVariant: "default",
features: [
"180 Nano Banana Pro images/month",
"180 high-quality images/month",
"Daily resets",
"13+ AI models included",
"6 AI models included (Flux, GPT Image, Z-Image, Klein, Seedance)",
"Advanced prompt enhancement",
"Custom prompt library",
"1,000 image batch queue",
Expand Down Expand Up @@ -79,7 +79,7 @@ export const pricingFaqs = [
{
question: "How does the free plan work?",
answer:
"Sign up and get 180 Nano Banana Pro images every month for free. Your quota resets daily (approx. 6 images/day). No credit card required.",
"Sign up and get 180 high-quality images every month for free. Your quota resets daily (approx. 6 images/day). No credit card required.",
},
{
question: "What happens if I need more images?",
Expand All @@ -90,7 +90,7 @@ export const pricingFaqs = [
question: "What AI models are included?",
answer: (
<span>
We offer 13+ cutting-edge and popular models including Flux, GPT-4 Image, Seedream, and more. Both Free and Pro users get access to all models.{" "}
We offer 6 high-quality AI models including Flux Schnell, GPT Image, Z-Image Turbo, FLUX.2 Klein, and Seedance. Both Free and Pro users get access to all active models.{" "}
<Link href="/#models" className="text-primary hover:underline font-medium">
View the full list of supported models here.
</Link>
Expand Down Expand Up @@ -128,7 +128,7 @@ export const featureComparison = [
},
},
{ feature: "Batch queue size", starter: "1,000", pro: "1,000", competitors: "10-20" },
{ feature: "AI Models", starter: "13+", pro: "13+", competitors: "13+" },
{ feature: "AI Models", starter: "6", pro: "6", competitors: "Varies" },
{ feature: "Prompt library", starter: true, pro: true, competitors: false },
{ feature: "Prompt enhancement", starter: true, pro: true, competitors: "Basic" },
{ feature: "Private gallery", starter: true, pro: true, competitors: "Varies" },
Expand Down
15 changes: 15 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"files": {
"ignore": ["convex/_generated/**", ".next/**", "node_modules/**"]
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"formatter": {
"enabled": true
}
}
2 changes: 1 addition & 1 deletion components/gallery/history-filters.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ if (!global.PointerEvent) {
this.isPrimary = params.isPrimary || false
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
global.PointerEvent = PointerEvent as any
}

Expand Down
22 changes: 4 additions & 18 deletions components/gallery/history-filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,39 +44,25 @@ interface HistoryFiltersProps {
const IMAGE_MODELS: ModelDefinition[] = Object.values(MODEL_REGISTRY).filter(
(model): model is ModelDefinition => model.type === "image",
);

// Get all video models from the registry
const VIDEO_MODELS: ModelDefinition[] = Object.values(MODEL_REGISTRY).filter(
(model): model is ModelDefinition => model.type === "video",
);

/**
* Legacy models that are no longer available for generation but may exist in user history.
* These are shown separately in the filter dropdown so users can still filter by them.
*/
const LEGACY_FILTER_MODELS: { id: string; displayName: string }[] = [
// Currently empty - 'flux' was moved back to MODEL_REGISTRY as an active model
];

/** Combined list of all filterable models (image + video + legacy), sorted alphabetically */
/** Combined list of all filterable models (image + video), sorted alphabetically */
const ALL_FILTERABLE_MODELS = [
...IMAGE_MODELS.map((m) => ({
id: m.id,
displayName: m.displayName,
isLegacy: false,
isLegacy: m.isLegacy ?? false,
type: "image" as const,
})),
...VIDEO_MODELS.map((m) => ({
id: m.id,
displayName: m.displayName,
isLegacy: false,
isLegacy: m.isLegacy ?? false,
type: "video" as const,
})),
...LEGACY_FILTER_MODELS.map((m) => ({
...m,
isLegacy: true,
type: "image" as const,
})),
].sort((a, b) =>
a.displayName.localeCompare(b.displayName, undefined, { numeric: true }),
);
Expand Down Expand Up @@ -294,7 +280,7 @@ export function HistoryFiltersDropdown({
<CommandItem
key={model.id}
onSelect={() => handleModelToggle(model.id)}
className="gap-2"
className={cn("gap-2", model.isLegacy && "opacity-60")}
>
<Checkbox
checked={isSelected}
Expand Down
2 changes: 1 addition & 1 deletion components/gallery/image-history.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ vi.mock("@/hooks/mutations/use-delete-image", () => ({
// Mock Next.js Image
vi.mock("next/image", () => ({
default: ({ src, alt, ...props }: React.ImgHTMLAttributes<HTMLImageElement> & { fill?: boolean }) => {
// eslint-disable-next-line @next/next/no-img-element
return <img src={src} alt={alt} {...props} />
},

Expand Down
Loading