{"id":50903776,"url":"https://github.com/hatimhtm/virtual-tryon-poc","last_synced_at":"2026-06-16T05:05:28.654Z","repository":{"id":357130208,"uuid":"1195156455","full_name":"hatimhtm/virtual-tryon-poc","owner":"hatimhtm","description":"Free public AI virtual try-on demo. Upload a selfie + a clothing photo, Gemini 3 Flash Image composites the garment onto your body. Next.js 16 · Tailwind 4 · rate-limited · no storage. MIT.","archived":false,"fork":false,"pushed_at":"2026-05-11T12:08:16.000Z","size":116,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T14:13:29.796Z","etag":null,"topics":["ai","fashion-tech","gemini","generative-ai","nextjs","open-source","poc","tailwindcss","vercel","virtual-try-on"],"latest_commit_sha":null,"homepage":"https://virtual-tryon-poc-two.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hatimhtm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-29T09:56:19.000Z","updated_at":"2026-05-11T12:08:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hatimhtm/virtual-tryon-poc","commit_stats":null,"previous_names":["hatimhtm/virtual-tryon-poc"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hatimhtm/virtual-tryon-poc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hatimhtm%2Fvirtual-tryon-poc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hatimhtm%2Fvirtual-tryon-poc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hatimhtm%2Fvirtual-tryon-poc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hatimhtm%2Fvirtual-tryon-poc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hatimhtm","download_url":"https://codeload.github.com/hatimhtm/virtual-tryon-poc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hatimhtm%2Fvirtual-tryon-poc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34391761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","fashion-tech","gemini","generative-ai","nextjs","open-source","poc","tailwindcss","vercel","virtual-try-on"],"created_at":"2026-06-16T05:05:27.738Z","updated_at":"2026-06-16T05:05:28.647Z","avatar_url":"https://github.com/hatimhtm.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"assets-readme/hero-banner-dark.svg\" /\u003e\n    \u003cimg src=\"assets-readme/hero-banner.svg\" alt=\"Atelier Virtuel — AI virtual try-on\" width=\"100%\" /\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://virtual-tryon-poc-two.vercel.app\"\u003e\u003cimg src=\"https://img.shields.io/badge/▶_TRY_THE_DEMO-CCFF00?style=for-the-badge\u0026labelColor=1A1A1A\" alt=\"Try the demo\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/hatimhtm/virtual-tryon-poc/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/hatimhtm/virtual-tryon-poc/ci.yml?branch=main\u0026style=for-the-badge\u0026label=CI\u0026labelColor=1A1A1A\u0026color=CCFF00\" alt=\"CI\" /\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Next.js-16-1A1A1A?style=for-the-badge\u0026logo=nextdotjs\u0026logoColor=CCFF00\" alt=\"Next.js 16\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Gemini_3-1A1A1A?style=for-the-badge\u0026logo=googlegemini\u0026logoColor=CCFF00\" alt=\"Gemini 3\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Tailwind_v4-1A1A1A?style=for-the-badge\u0026logo=tailwindcss\u0026logoColor=CCFF00\" alt=\"Tailwind v4\" /\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/LICENSE-MIT-1A1A1A?style=for-the-badge\u0026labelColor=1A1A1A\u0026color=CCFF00\" alt=\"MIT\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eA free public AI virtual try-on demo. Upload a selfie, drop in a clothing photo, and Gemini 3 Flash Image composites the garment onto your body in ~30–45 seconds with realistic fit, fabric, and lighting. Two API routes, ~750 LOC, no database, no account, no photo storage. Built as a POC to validate the AI flow before going into a native app.\u003c/em\u003e\n\u003c/p\u003e\n\n---\n\n### `/// THE FLOW`\n\n```\n       upload selfie  +  upload clothing photo  +  pick background\n                                  │\n                                  ▼\n                  ┌──────────────────────────────┐\n                  │ GEMINI 2.5 FLASH validates   │\n                  │ the selfie  (single person,  │   ~3s\n                  │  face visible, body framed)  │\n                  └──────────────────────────────┘\n                                  │\n                                  ▼\n                  ┌──────────────────────────────┐\n                  │ GEMINI 3.1 FLASH IMAGE       │\n                  │ composites the garment onto  │   ~30–45s\n                  │ the body with the chosen     │\n                  │ background + lighting        │\n                  └──────────────────────────────┘\n                                  │\n                                  ▼\n                       download · share · retry\n```\n\n---\n\n### `/// FEATURES`\n\n| | |\n|---|---|\n| **2-stage AI pipeline** | A cheap validation pass (Gemini 2.5 Flash) before the expensive image-gen call (Gemini 3.1 Flash Image). Cuts cost and bad-input failures. |\n| **5 background presets** | Studio white · studio gray · urban · minimal beige · outdoor nature — each one rendered into the Gemini prompt as a lighting + composition cue. |\n| **Multiple input methods** | File picker · drag-and-drop · paste from clipboard (⌘V) — the clipboard listener is global so it works at any step. |\n| **Client-side compression** | All images are resized to max 1024px and re-encoded as JPEG quality 0.7 before upload, so we never hit Vercel's `413 Payload Too Large` limit. |\n| **Rate limiting** | In-memory IP rate limiter — 5 generations / hour / IP, 20 validations / hour / IP. Echoes `X-RateLimit-*` and `Retry-After` headers. Imperfect (resets on cold start) but enough to deter drive-by abuse. |\n| **No storage** | Images flow base64 → API → Gemini → base64 back. Nothing is persisted anywhere. The session ends when you close the tab. |\n| **Brutalist UI** | Sharp corners, hard offset shadows, mono-font labels, acid-yellow accent. Cream-and-ink palette in light mode, ink-and-cream in dark mode. |\n| **Health endpoint** | `GET /api/health` returns `200` if `GOOGLE_GENAI_API_KEY` is wired up. Doesn't burn quota on each call. |\n| **Bilingual ready** | UI copy is French; technical docs are English. Easy to swap with one i18n library if you want. |\n\n---\n\n### `/// STACK`\n\n```\nNEXT.JS 16          App Router · server routes for API\nTAILWIND 4          OKLCH-style tokens, light+dark via prefers-color-scheme\nGEMINI 3.1 FLASH    image generation via @google/genai\nGEMINI 2.5 FLASH    image validation (single-person + framing check)\nFRAMER MOTION       step transitions\nLUCIDE ICONS        the usual\nZERO DEPS BEYOND    Next, React, Tailwind, Framer Motion, Lucide,\n                    @google/genai. No DB, no auth, no analytics.\n```\n\n---\n\n### `/// LOCAL DEV`\n\n```bash\ngit clone https://github.com/hatimhtm/virtual-tryon-poc.git\ncd virtual-tryon-poc\ncp .env.example .env.local        # fill in GOOGLE_GENAI_API_KEY\nnpm install\nnpm run dev                       # http://localhost:3000\nnpm run build                     # production bundle\nnpm run lint                      # ESLint\n```\n\nRequires **Node 20+** and a [Google AI Studio API key](https://aistudio.google.com/apikey) (free tier is plenty).\n\n---\n\n### `/// PROJECT LAYOUT`\n\n```\nvirtual-tryon-poc/\n├── src/\n│   ├── app/\n│   │   ├── page.tsx                  4-step flow — upload, upload, pick, result\n│   │   ├── layout.tsx                fonts + metadata + OG/Twitter cards\n│   │   ├── globals.css               brutalist tokens + scan animation\n│   │   └── api/\n│   │       ├── validate-image/       POST → Gemini 2.5 Flash (selfie check)\n│   │       ├── generate-tryon/       POST → Gemini 3.1 Flash Image (try-on)\n│   │       └── health/               GET  → liveness probe\n│   └── lib/\n│       └── rate-limit.ts             in-memory IP bucket + header helpers\n├── public/                           static assets\n├── .github/workflows/ci.yml          npm ci · lint · build on every push\n├── assets-readme/                    brutalist hero banners (light + dark)\n└── LICENSE                           MIT\n```\n\n---\n\n### `/// V2 — THE OVERHAUL`\n\nThe 1.0 build shipped working but unpolished. v2 takes it from POC-on-a-Vercel-link to public-facing demo:\n\n- **Brutalist UI** matching the rest of my portfolio — cream + ink + acid yellow, sharp corners, hard offset shadows, monospace labels, scan-bar loader.\n- **Real metadata** in `layout.tsx` — title is no longer \"Create Next App\". OG cards, Twitter cards, inline SVG favicon, theme-color meta.\n- **IP rate limiting** on both API routes (5 gen/hour, 20 validations/hour) with `X-RateLimit-*` headers so a friendly client can react gracefully.\n- **`/api/health`** liveness probe.\n- **`.env.example`** + negated `.gitignore` so the example actually ships.\n- **CI workflow** runs `lint + build` on every push.\n- **LICENSE** — MIT, because this is a POC people should be free to fork and learn from.\n- **README** rewritten from the `create-next-app` boilerplate into something readable.\n\n---\n\n### `/// PRIVACY`\n\nThis demo doesn't store, log, or transmit your photos to anywhere except Google's Gemini API, and only for the duration of the single request. There is no database, no analytics SDK, no telemetry. Your images live in browser memory and Vercel function memory for the time it takes to generate the result, and that's it.\n\nGemini's own privacy terms apply for what they do with the request payloads — read [their docs](https://ai.google.dev/gemini-api/terms) for specifics.\n\n---\n\n### `/// LICENSE`\n\n[MIT](LICENSE) — fork it, learn from it, rebuild it. Just keep the copyright line.\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://hatimelhassak.is-a.dev\"\u003e\u003cimg src=\"https://img.shields.io/badge/PORTFOLIO-1A1A1A?style=for-the-badge\u0026logo=vercel\u0026logoColor=CCFF00\" alt=\"Portfolio\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://cal.com/hatimelhassak/engineering-discovery\"\u003e\u003cimg src=\"https://img.shields.io/badge/BOOK_A_CALL-CCFF00?style=for-the-badge\u0026logo=googlecalendar\u0026logoColor=1A1A1A\" alt=\"Book a call\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.linkedin.com/in/hatim-elhassak/\"\u003e\u003cimg src=\"https://img.shields.io/badge/LINKEDIN-1A1A1A?style=for-the-badge\u0026logo=linkedin\u0026logoColor=CCFF00\" alt=\"LinkedIn\" /\u003e\u003c/a\u003e\n  \u003ca href=\"mailto:hatimelhassak.official@gmail.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/EMAIL-1A1A1A?style=for-the-badge\u0026logo=gmail\u0026logoColor=CCFF00\" alt=\"Email\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ccode\u003e///\u0026nbsp;\u0026nbsp;OPEN FOR NEW WORK\u0026nbsp;\u0026nbsp;///\u0026nbsp;\u0026nbsp;CONTRACT \u0026amp; FREELANCE\u0026nbsp;\u0026nbsp;///\u0026nbsp;\u0026nbsp;REMOTE WORLDWIDE\u0026nbsp;\u0026nbsp;///\u003c/code\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhatimhtm%2Fvirtual-tryon-poc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhatimhtm%2Fvirtual-tryon-poc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhatimhtm%2Fvirtual-tryon-poc/lists"}