Nano Studio is a web app that enables users to transform simple smartphone product photos into professional, culturally rich, and visually compelling marketing assets instantly. It uses Google's Gemini 3 Pro's Image model, dubbed as Nano Banana Pro to combine an uploaded product image with a detailed, text-based background prompt, to produce a high-quality, visually compelling image for marketing needs.
Transform simple smartphone product photos into studio-quality, culturally rich marketing assets β instantly. πΈβ¨
Nano Studio aims to democratize high-quality product photography for Small and Medium-sized Enterprises (SMEs), particularly those selling authentic traditional goods (e.g., kanga, kikoy, Swahili crafts, local packaged foods). We provide a tool that transforms simple smartphone product snapshots into professional, culturally rich, and visually compelling marketing assets instantly.
Nano Studio utilizes Google's "Nano Banana Pro" β the official Gemini 3 Pro's Image generation and editing model β to combine an uploaded product image with a detailed, text-based background prompt.
- You upload one or more product snapshots π·
- You describe the desired background or vibe using natural language π
- The model composes a studio-grade image that blends your product with an authentic, evocative backdrop in seconds β‘
"Nano Banana Pro" (Gemini 3 Pro's Image) uses conversational prompts to make consistent, high-quality edits to photos β changing colors, adding objects, altering textures, and more β while preserving realism and product integrity.
The core value proposition is the ability to generate studio-quality images with authentic, evocative backdrops in seconds, at minimal cost. This is especially impactful for SMEs and local artisans seeking:
- Professional-looking product photos without hiring a studio πΌ
- Fast turnarounds for campaigns and catalogs β±οΈ
- Context-rich visuals that reflect cultural authenticity π
- AI-Powered Image Generation: Utilizes Google's Gemini 3 Pro model to generate high-quality product images.
- Multi-Image Upload: Upload multiple product images at once β each image is sent to the AI model for richer, more accurate results.
- Prompt-Based Editing: Users can describe the desired background and style using natural language.
- Quick Prompts: Choose from preset styles (Studio, Soft, Noir, Vibrant) to instantly populate the prompt field.
- Authentication: Secure user authentication with Google, powered by Firebase Authentication.
- Prompt History: Saves and displays a history of user prompts, stored in Firestore.
- Generation Quota: Daily generation limits per user type (guests: 5, signed-in: 10) to manage API usage.
- Responsive UI: Built with Angular, ensuring a seamless experience across devices.
The application's core logic is split between the frontend (Angular) and the backend (Firebase Functions with Genkit).
The backend uses Genkit to define an AI flow that generates images and exposes it as a callable Firebase Function.
Genkit Flow Definition:
The _generateImageFlowLogic defines the AI workflow. It takes a prompt and an array of base64-encoded images, maps them into media parts, and passes all of them to the Gemini model alongside the text prompt.
// functions/src/index.ts
const ImageGenerationInputSchema = z.object({
prompt: z.string().describe('The prompt for the image generation'),
base64Images: z.array(z.string()).min(1).describe('The base64 encoded image data for one or more images'),
})
export const _generateImageFlowLogic = ai.defineFlow(
{
name: 'generateImageFlow',
inputSchema: ImageGenerationInputSchema,
outputSchema: ImageGenerationOutputSchema,
},
async({ prompt, base64Images }) => {
const payloadText = SYSTEM_PROMPT(prompt);
try {
// Generate image using the AI model β include all uploaded images
const mediaParts = base64Images.map(img => ({ media: { url: `data:image/jpeg;base64,${img}` } }));
const response = await ai.generate([
...mediaParts,
{text: payloadText}
]);
const base64ImageResult = response.media?.url?.split(',')[1];
if (!base64ImageResult) {
throw new HttpsError('internal', 'Could not extract base64 image data from the response.');
}
return { base64ImageResult };
} catch (e: any) {
logger.error("Error generating image:", e);
throw new HttpsError('internal', 'An error occurred while generating the image.', e.message);
}
}
);Firebase Function Wrapper: The Genkit flow is wrapped in a callable Firebase Function, making it accessible to the frontend.
// functions/src/index.ts
export const generateImageFlow = onCallGenkit(
{
secrets: [GEMINI_API_KEY],
region: 'africa-south1',
cors: isEmulated ? true : [/^https:\/\/nano-studios(--[a-z0-9-]+)?\.web\.app$/],
},
_generateImageFlowLogic
);AI Service (src/app/services/core/ai/ai.service.ts):
This service calls the generateImageFlow Firebase Function.
// src/app/services/core/ai/ai.service.ts
import { httpsCallable } from '@angular/fire/functions';
// ...
export class AiService {
// ...
async generateContent(prompt: string, base64Images: string[]): Promise<string> {
try {
const generateImage = httpsCallable<{ prompt: string, base64Images: string[] }, ImageGenerationOutput>(this.functions, 'generateImageFlow');
const response = await generateImage({ prompt, base64Images });
const base64ImageResult = response.data.base64ImageResult;
// ...
return `data:image/png;base64,${base64ImageResult}`;
}
// ...
}
}Authentication Service (src/app/services/core/auth/auth.service.ts):
Handles user authentication using Firebase, supporting sign-in with Google.
// src/app/services/core/auth/auth.service.ts
export class AuthService {
currentUser = signal<User | null>(null);
isAuthenticated = signal<boolean>(false);
constructor() {
onAuthStateChanged(this.auth, (user) => {
this.currentUser.set(user);
this.isAuthenticated.set(!!user);
});
}
signInWithGoogle(): Observable<User> {
const provider = new GoogleAuthProvider();
return from(signInWithPopup(this.auth, provider)).pipe(
switchMap(result => of(result.user))
);
}
}Home Component (src/app/pages/home/home.ts):
The Home component manages an array of uploaded files and passes all base64-encoded images to the AiService. Users can add or remove individual images before generating.
// src/app/pages/home/home.ts
export class Home {
aiService = inject(AiService);
readonly files = signal<File[]>([]);
readonly filePreviewUrls = signal<string[]>([]);
readonly base64Images = signal<string[]>([]);
readonly canGenerate = computed(() =>
this.base64Images().length > 0 &&
this.prompt().trim().length > 0 &&
!this.loading() &&
this.userDataService.canGenerateImage(this.authService.currentUser())
);
removeFile(index: number): void {
this.files.update(f => f.filter((_, i) => i !== index));
this.filePreviewUrls.update(u => u.filter((_, i) => i !== index));
this.base64Images.update(b => b.filter((_, i) => i !== index));
}
async generate(): Promise<void> {
if (!this.canGenerate()) return;
this.loading.set(true);
this.aiService.generateContent(this.prompt(), this.base64Images())
.then(async res => {
this.resultUrl.set(res);
// ...
})
.catch(error => {
// ...
})
}
}The fastest way to get Nano Studio running:
After launching:
- π Open Terminal - Navigate to the Terminal tab in Firebase Studio
- π¦ Install Dependencies - Run these commands one by one:
npm install cd functions npm install cd ..
π‘ Complete Setup Guide - Follow these steps to configure Firebase and required APIs for Nano Studio.
- π Open Firebase Console
- Navigate to Firebase Console
- β Create New Project
- Click "Create a new Firebase project"
- Enter project name:
nano-studio-app(or your preferred name) - Google Analytics is optional, so no need to enable it
- π³ Upgrade to Blaze Plan
β οΈ Required for AI Features
- Locate billing section in bottom-left sidebar
- Click "Upgrade" next to Spark plan
- Select "Pay as you Go - Blaze Plan"
- Choose "Google Cloud Platform Trial Billing Account"
- Set budget alert (e.g., $2 USD)
- Click "Link Cloud Billing Account"
Your Firebase project needs certain Google Cloud APIs enabled:
- Go to Google Cloud Console:
- Visit the Google Cloud Console
- Make sure your Firebase project is selected in the project dropdown
- Click on "Dashboard" to see the project's overview page
- Enable the Secret Manager API:
- In the left sidebar, go to "APIs & Services" > "Library"
- Search for "Secret Manager API"
- Click on it and press "Enable"
Note: Other APIs (Cloud Functions, Vertex AI, etc.) are automatically enabled when you deploy Firebase Functions.
π Note for Firebase Studio users: Skip the CLI installation step and go directly to logging in.
-
Install Firebase CLI (skip if using Firebase Studio):
npm install -g firebase-tools
-
Log in to Firebase:
firebase login
-
In the terminal, you will be prompted to enter to visit a URL to authenticate using an authorization code.
-
Open the URL, select the same Google account you used to create the Firebase project.
-
Click the "Yes, I just ran this command" button.
-
The second step shows you a session code that should tally with the one seen back in your project's terminal. Click "Yes".
-
In Step 3, copy the code and paste it into the terminal.
You need to make sure your project is linked correctly:
Method 1: Using Firebase CLI (Recommended)
Set your Firebase project as the default:
firebase use YOUR_PROJECT_IDReplace
YOUR_PROJECT_IDwith your actual Firebase project ID (you can find this in the Firebase Console URL or project settings).
Method 2: Manual Configuration
If the CLI method doesn't work, you can edit the .firebaserc file manually:
- Open
.firebasercin your project root directory - Update it to match your project ID:
{ "projects": { "default": "YOUR_PROJECT_ID" } }
π‘ Tip: You can verify your project is linked correctly by running
firebase projects:listto see your available projects.
firebase initConfigure Firebase services when prompted:
- Select services: Choose and "Firestore" (use space to select, enter to confirm)
- Select a location for your Firestore database: Choose a region closer to your users
- Firestore Rules: Accept the default
firestore.rulesfile - Firestore Indexes: Accept the default
firestore.indexes.jsonfile - Initialize or overwrite: When asked to either initialize or overwrite the codebase, select "Overwrite"
β οΈ Important: When asked to overwrite existing files, select "No" to preserve the project code- Install dependencies: Choose "Yes"
Now you need to register a web app in Firebase and get the configuration:
- Register your web app:
- Go to Firebase Console and select your project
- Click the gear icon (βοΈ) next to "Project Overview" β "Project settings"
- Scroll to "Your apps" section
- If you don't have a web app yet, click "Add app" β Web icon (
</>) - Give your app a name (e.g., "Nova Reel Web App")
- Check the Firebase Hosting box
- Click "Register app"
- Get your Firebase configuration:
- In the "Add Firebase SDK" step, copy the configuration object (it looks like this):
{
apiKey: "your-api-key-here",
authDomain: "your-project.firebaseapp.com",
projectId: "your-project-id",
storageBucket: "your-project.appspot.com",
messagingSenderId: "123456789",
appId: "your-app-id",
measurementId: "your-measurement-id"
}-
Update your environment files:
Open both environment files and replace the
firebaseConfigobject with your own:For
src/environments/environment.ts(production):export const environment = { production: true, firebaseConfig: { // Paste your Firebase config here apiKey: "your-api-key-here", authDomain: "your-project.firebaseapp.com", projectId: "your-project-id", storageBucket: "your-project.appspot.com", messagingSenderId: "123456789", appId: "your-app-id", measurementId: "your-measurement-id" } };
For
src/environments/environment.development.ts(development):export const environment = { production: false, firebaseConfig: { // Same Firebase config as above } };
Click "Continue to console" to continue.
- Click the "Build" dropdown in the sidebar
- Select "Authentication"
- Click "Get started"
- Select "Google"
- Toggle the "Enable" switch
- Provide a support email address
- Click "Save"
- Click the "Build" dropdown in the sidebar
- Select "Firestore Database"
- Click "Create database"
- Select "Standard Edition"
- You can leave the database ID as "default"
- Select the closest location to your users
- Click "Next"
- Select "Start in test mode"
- Click "Create"
-
Set Gemini API Key:
firebase functions:secrets:set GEMINI_API_KEY
When prompted, paste your Gemini API key.
π How to get Gemini API Key: Go to Google AI Studio, create an API key by attaching to a project, and copy it. The input is masked, so you won't see the pasted key, but it will be there. Just paste ONCE!
-
Create local environment file (for development):
echo "GEMINI_API_KEY=your_actual_gemini_api_key_here" > .env cd ..
Replace
your_actual_gemini_api_key_herewith your actual Gemini API key.
-
Deploy Firebase Functions:
firebase deploy --only functions
This will deploy your backend functions to Firebase.
-
Run the application locally:
cd .. ng serveYour app will be available at
http://localhost:4200. However, on Firebase Studio, hold Ctrl+Click on the localhost URL to open it in a new tab. -
Build for production (optional):
ng build firebase deploy --only hosting
π Congratulations! Your Nano Studio app should now be running with full AI-powered image editing capabilities!
This project is built with Angular. If youβre setting it up locally:
- Install dependencies
npm install
- Start the development server
npm start # or ng serve - Open the app
- Visit http://localhost:4200/ in your browser. The app reloads on file changes.
- Upload one or more clear JPG or PNG images (wellβlit, uncluttered works best)
- Remove any unwanted images using the β button on each preview thumbnail
- Try a quick prompt (Studio, Soft, Noir, Vibrant) or write your own, e.g.:
- "Soft natural light, wooden tabletop, cozy morning scene"
- "Vibrant kanga fabric backdrop, soft shadows, minimalist props"
- Click Generate image
- Download or share the result; refine the prompt and iterate
Notes
- Large or multiple images may take longer to process
- Guests can generate up to 5 images; signed-in users get 10 per day
- Prompt history shows your last 20 prompts and when they were generated
- "Nano Banana Pro" refers to Google's Gemini 3 Pro image generation and editing model.
- It enables conversational edits like color changes, adding objects, or texture adjustments.
- Supports multi-image input β all uploaded images are passed to the model simultaneously for richer context.
- Ideal for product scenarios where consistency, speed, and visual accuracy matter.
Common Angular CLI scripts:
- Development server
ng serve
- Build for production
ng build
- Unit tests
ng test
Preset prompt templates for common product categoriesβ DoneMulti-image upload supportβ Done- Batch processing for product catalogs
- Export presets for marketplaces (Shopify, Jumia, etc.)
- Fine-grained controls for lighting and shadow realism
This project is for educational and prototyping purposes. Consider reviewing licensing and API terms for any production deployment.