AI-powered furniture discovery. Upload a photo of your room, describe what you want, and swipe through real products from real stores — placed directly into your space.
- You upload a room photo
- You describe what you're looking for ("Add a sofa", "Make it cozy", etc.)
- Gemini AI analyzes your room — style, colors, dimensions, lighting
- Products from our database are matched, scored, and ranked
- Each product is composited into your room photo (background removal + placement)
- You swipe through results Tinder-style — right to save, left to pass
Products link directly to real stores (Blueprint Home, Elte, IKEA, CB2, etc.) so you can buy what you like.
- React 18 + TypeScript + Vite
- Tailwind CSS + shadcn/ui + Framer Motion
- Google Gemini 2.5 (room analysis, intent extraction, product ranking)
- Supabase (product catalog, stores, attributes, dimensions)
- Netlify Functions (serverless API)
- @imgly/background-removal (client-side bg removal for compositing)
- Node.js 18+
- A Google AI Studio API key (Gemini)
- A Supabase project with the furniture catalog schema
npm install
cp .env.example .envFill in .env:
GEMINI_API_KEY=AIzaSy...
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=eyJ...You need two processes — the Vite frontend and the local API server:
# Terminal 1: API server (port 8888)
npm run dev:api
# Terminal 2: Frontend (port 8080)
npm run devApply the migration to set up tables:
# Using Supabase CLI
supabase db push
# Or manually run:
# supabase/migrations/20240001_furniture_catalog.sqlSeed data is in supabase/seed/mock_ontario_furniture.sql.
src/
├── components/ # UI components
│ ├── SwipeResultsPage # Main swipe interface (AI results)
│ ├── RoomUploadPage # Room photo + prompt input
│ ├── TrenderSwipeScreen # Tinder-style card deck (sample data)
│ ├── LandingPage # Hero + entry points
│ └── ui/ # shadcn primitives
├── lib/
│ ├── gemini/ # Gemini client, prompts, parsers
│ ├── room-overlay/ # Pipeline: analyze → query → score → rank
│ ├── compositor/ # Background removal + image stitching
│ └── ingestion/ # Product data ingestion providers
├── services/ # Legacy API services
├── types/ # TypeScript interfaces
└── data/ # Static sample furniture data
server/
└── index.ts # Local dev API server (mirrors Netlify Functions)
netlify/functions/ # Serverless endpoints (production)
scripts/ # Scraping, ingestion, DB utilities
User prompt → extractIntent → translateUserPrompt → analyzeRoomWithGemini
→ buildProductCandidates (Supabase query)
→ scoreAndRankCandidates (structured scoring)
→ rankProductsWithGemini (Gemini rerank, optional)
→ return top candidates + placement guidance
Product image → background removal (@imgly) → scale + position → composite onto room photo
| Command | Description |
|---|---|
npm run dev |
Vite dev server (port 8080) |
npm run dev:api |
Local API server (port 8888) |
npm run build |
Production build |
npm run test |
Run tests (vitest) |
npm run scrape:furniture |
Run furniture scraper |
npm run scrape:shopify |
Scrape Shopify stores |
The app is configured for Netlify with netlify.toml. Functions in netlify/functions/ are deployed automatically.
Set environment variables in the Netlify dashboard:
GEMINI_API_KEYSUPABASE_URLSUPABASE_SERVICE_ROLE_KEY
npm run build
# Output: dist/MIT