<p align="center">
  <a href="https://myaifitting.com">
    <img src="https://cdn.jsdelivr.net/npm/@primestyleai/tryon/logo.svg" alt="PrimeStyle AI" width="180" />
  </a>
</p>

<h1 align="center">@primestyleai/tryon</h1>

<p align="center">
  <strong>AI-Powered Virtual Try-On for React & Next.js</strong>
</p>

<p align="center">
  Add a virtual try-on button to your product pages in 3 steps. Customers upload a photo and see how clothes look on them — powered by PrimeStyle AI.
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/@primestyleai/tryon"><img src="https://img.shields.io/npm/v/@primestyleai/tryon?color=D6BA7D&label=npm" alt="npm version" /></a>
  <a href="https://www.npmjs.com/package/@primestyleai/tryon"><img src="https://img.shields.io/npm/dm/@primestyleai/tryon?color=D6BA7D" alt="npm downloads" /></a>
  <a href="https://github.com/primestyleai/tryon-sdk/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@primestyleai/tryon?color=D6BA7D" alt="license" /></a>
  <img src="https://img.shields.io/badge/gzip-5.5kB-green" alt="bundle size" />
</p>

<p align="center">
  <a href="https://myaifitting.com/developer/demo">Live Demo</a> &bull;
  <a href="https://myaifitting.com/docs">Documentation</a> &bull;
  <a href="https://myaifitting.com/developer/dashboard/keys">Get API Key</a> &bull;
  <a href="https://myaifitting.com/pricing">Pricing</a>
</p>

---

## How It Works

1. Customer clicks the **"Virtual Try-On"** button on your product page
2. They upload a photo of themselves
3. PrimeStyle AI generates a realistic try-on image in ~15 seconds
4. Customer sees how the garment looks on them before buying

The entire flow happens inside a beautiful modal — no redirects, no iframes.

---

## Quick Start

### 1. Install

```bash
npm install @primestyleai/tryon
```

### 2. Set Your API Key

Get your key from the [Developer Dashboard](https://myaifitting.com/developer/dashboard/keys) and add it to your `.env.local`:

```env
NEXT_PUBLIC_PRIMESTYLE_API_KEY=ps_live_your_key_here
```

### 3. Use the Component

```jsx
import { PrimeStyleTryon } from '@primestyleai/tryon/react';

function ProductPage({ product }) {
  return (
    <div>
      <h1>{product.name}</h1>
      <img src={product.image} alt={product.name} />

      <PrimeStyleTryon
        productImage={product.image}
        buttonText="Try It On"
      />
    </div>
  );
}
```

That's it. No API key prop needed — the component reads it from your environment automatically.

---

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `productImage` | `string` | **required** | URL of the garment image |
| `buttonText` | `string` | `"Virtual Try-On"` | Text on the trigger button |
| `apiUrl` | `string` | `NEXT_PUBLIC_PRIMESTYLE_API_URL` or production | API endpoint override |
| `showPoweredBy` | `boolean` | `true` | Show "Powered by PrimeStyle AI" in modal |
| `buttonStyles` | `ButtonStyles` | `{}` | Customize button via style props |
| `modalStyles` | `ModalStyles` | `{}` | Customize modal via style props |
| `classNames` | `PrimeStyleClassNames` | `{}` | Override element classes (Tailwind, CSS) |
| `className` | `string` | — | Additional CSS class on wrapper |
| `style` | `CSSProperties` | — | Inline styles on wrapper |
| `onOpen` | `() => void` | — | Modal opened |
| `onClose` | `() => void` | — | Modal closed |
| `onUpload` | `(file: File) => void` | — | User uploaded a photo |
| `onProcessing` | `(jobId: string) => void` | — | Try-on generation started |
| `onComplete` | `(result) => void` | — | Result ready: `{ jobId, imageUrl }` |
| `onError` | `(error) => void` | — | Error occurred: `{ message, code? }` |

---

## Customization

### Button Styles

```jsx
<PrimeStyleTryon
  productImage={product.image}
  buttonStyles={{
    backgroundColor: '#000000',
    textColor: '#ffffff',
    borderRadius: '50px',
    padding: '16px 32px',
    fontSize: '16px',
    fontWeight: '700',
    width: '100%',
    border: '2px solid #333',
    hoverBackgroundColor: '#222',
    iconSize: '20px',
    boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
  }}
/>
```

**All ButtonStyles properties:**

| Property | Description |
|----------|-------------|
| `backgroundColor` | Button background color |
| `textColor` | Button text color |
| `borderRadius` | Corner rounding |
| `fontSize` | Text size |
| `fontFamily` | Font stack |
| `fontWeight` | Font weight |
| `padding` | Inner spacing |
| `border` | Border style |
| `width` | Button width (e.g. `"100%"`) |
| `height` | Button height |
| `hoverBackgroundColor` | Background on hover |
| `hoverTextColor` | Text color on hover |
| `iconSize` | Camera icon size |
| `iconColor` | Camera icon color |
| `boxShadow` | Shadow effect |

### Modal Styles

```jsx
<PrimeStyleTryon
  productImage={product.image}
  modalStyles={{
    backgroundColor: '#ffffff',
    textColor: '#111111',
    overlayColor: 'rgba(0,0,0,0.7)',
    borderRadius: '16px',
    maxWidth: '520px',
    headerBackgroundColor: '#f5f5f5',
    headerTextColor: '#111111',
    primaryButtonBackgroundColor: '#000000',
    primaryButtonTextColor: '#ffffff',
    loaderColor: '#000000',
  }}
/>
```

**All ModalStyles properties:**

| Property | Description |
|----------|-------------|
| `overlayColor` | Background overlay color |
| `backgroundColor` | Modal background |
| `textColor` | Modal text color |
| `borderRadius` | Modal corner rounding |
| `width` / `maxWidth` | Modal dimensions |
| `fontFamily` | Modal font stack |
| `headerBackgroundColor` | Header section background |
| `headerTextColor` | Header title color |
| `closeButtonColor` | Close (X) button color |
| `uploadBorderColor` | Upload drop zone border |
| `uploadBackgroundColor` | Upload zone background |
| `uploadTextColor` | Upload zone text |
| `uploadIconColor` | Upload icon color |
| `primaryButtonBackgroundColor` | Submit / download button background |
| `primaryButtonTextColor` | Submit / download button text |
| `primaryButtonBorderRadius` | Submit button rounding |
| `loaderColor` | Loading spinner color |
| `resultBorderRadius` | Result image corner rounding |

### Tailwind CSS / Custom Classes

Use the `classNames` prop to style any element with Tailwind utilities or your own CSS classes:

```jsx
<PrimeStyleTryon
  productImage={product.image}
  classNames={{
    button: "bg-black text-white rounded-full px-8 py-4 hover:bg-gray-800",
    modal: "bg-white rounded-2xl shadow-2xl",
    header: "bg-gray-50 border-b border-gray-200",
    title: "text-gray-900 text-lg",
    closeButton: "text-gray-400 hover:text-gray-600",
    body: "p-6",
    uploadZone: "border-2 border-dashed border-gray-300 rounded-xl p-10 hover:border-blue-400",
    uploadText: "text-gray-700",
    submitButton: "bg-blue-600 text-white rounded-lg hover:bg-blue-700",
    downloadButton: "bg-green-600 text-white rounded-lg",
    retryButton: "bg-gray-100 text-gray-700 border border-gray-300",
  }}
/>
```

**All classNames keys:**

| Key | Element |
|-----|---------|
| `root` | Root wrapper `<div>` |
| `button` | Trigger button |
| `overlay` | Modal backdrop overlay |
| `modal` | Modal container |
| `header` | Modal header bar |
| `title` | Modal title text |
| `closeButton` | Close (X) button |
| `body` | Modal body area |
| `uploadZone` | Upload drop zone |
| `uploadText` | "Drop your photo..." text |
| `uploadHint` | File type hint text |
| `preview` | Preview image container |
| `previewImage` | Preview `<img>` element |
| `removeButton` | Remove preview button |
| `submitButton` | "Try It On" / "Try Again" button |
| `spinner` | Loading spinner |
| `processingText` | "Generating..." text |
| `processingSubText` | "This usually takes..." text |
| `result` | Result container |
| `resultImage` | Result `<img>` element |
| `resultActions` | Download/retry button row |
| `downloadButton` | Download button |
| `retryButton` | "Try Another" button |
| `error` | Error container |
| `errorText` | Error message text |
| `poweredBy` | Footer text |

### Normal CSS

All elements use `ps-tryon-*` class names that you can target directly in your CSS:

```css
/* Override the trigger button */
.ps-tryon-btn {
  background: #000;
  color: #fff;
  border-radius: 50px;
  padding: 16px 32px;
}

/* Override the modal */
.ps-tryon-modal {
  background: #fff;
  color: #111;
  border-radius: 16px;
}

/* Override the submit button */
.ps-tryon-submit {
  background: #2563eb;
  color: #fff;
}
```

### Combining Approaches

You can mix all three styling methods — they layer on top of each other:

```jsx
<PrimeStyleTryon
  productImage={product.image}
  // 1. Style props (CSS variables)
  buttonStyles={{ width: '100%' }}
  // 2. Tailwind classes
  classNames={{ button: "rounded-full font-bold" }}
  // 3. Normal CSS targets .ps-tryon-btn automatically
/>
```

Priority: Tailwind/classNames classes > CSS variables (buttonStyles/modalStyles) > default styles.

---

## Callbacks

```jsx
<PrimeStyleTryon
  productImage={product.image}
  onOpen={() => {
    analytics.track('tryon_opened');
  }}
  onUpload={(file) => {
    console.log('Photo uploaded:', file.name);
  }}
  onProcessing={(jobId) => {
    console.log('Processing:', jobId);
  }}
  onComplete={(result) => {
    console.log('Result ready:', result.imageUrl);
    analytics.track('tryon_completed', { jobId: result.jobId });
  }}
  onError={(error) => {
    console.error('Try-on failed:', error.message);
    // error.code: 'INSUFFICIENT_TOKENS' | 'API_ERROR' | etc.
  }}
  onClose={() => {
    console.log('Modal closed');
  }}
/>
```

---

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `NEXT_PUBLIC_PRIMESTYLE_API_KEY` | Yes | — | Your PrimeStyle API key |
| `NEXT_PUBLIC_PRIMESTYLE_API_URL` | No | `https://myaifitting.com` | Custom API endpoint |

The component reads these automatically — no need to pass them as props.

---

## Tokens & Pricing

Each virtual try-on consumes **tokens** from your account balance.

| | |
|---|---|
| **Free trial** | Tokens included on signup |
| **Token packs** | Pay-as-you-go, never expire |
| **Monthly plans** | Volume discounts for high-traffic stores |

Manage your balance and purchase tokens at [primestyleai.com/developer/dashboard/billing](https://myaifitting.com/developer/dashboard/billing).

If a try-on fails, tokens are **automatically refunded** to your account.

The `onComplete` callback includes token info:

```jsx
onComplete={(result) => {
  // result.jobId — the job ID
  // result.imageUrl — the result image URL
}}
```

---

## API Key Management

Create and manage your API keys at the [Developer Dashboard](https://myaifitting.com/developer/dashboard/keys).

- Keys start with `ps_live_` and are shown **once** at creation
- Set **allowed domains** to restrict where your key can be used
- **Revoke** keys instantly if compromised
- Maximum 10 active keys per account

---

## Full Example

```jsx
// app/product/[id]/page.tsx (Next.js App Router)

import { PrimeStyleTryon } from '@primestyleai/tryon/react';

export default function ProductPage({ product }) {
  return (
    <div className="product-page">
      <div className="product-gallery">
        <img src={product.image} alt={product.name} />
      </div>

      <div className="product-info">
        <h1>{product.name}</h1>
        <p className="price">${product.price}</p>

        {/* Virtual Try-On — reads API key from env */}
        <PrimeStyleTryon
          productImage={product.image}
          buttonText="Try It On"
          buttonStyles={{
            width: '100%',
            padding: '14px 24px',
            borderRadius: '10px',
            fontSize: '15px',
          }}
          onComplete={(result) => {
            // Show success toast, track analytics, etc.
            toast.success('Your try-on is ready!');
          }}
          onError={(error) => {
            toast.error(error.message);
          }}
        />

        <button className="add-to-cart">Add to Cart</button>
      </div>
    </div>
  );
}
```

---

## Requirements

- React 18+
- Next.js 13+ (App Router or Pages Router)

---

## Need Help?

- [Live Demo](https://myaifitting.com/developer/demo) — See it in action
- [Documentation](https://myaifitting.com/docs) — Full API reference
- [Dashboard](https://myaifitting.com/developer/dashboard/keys) — Manage keys & tokens
- [Contact](mailto:support@primestyleai.com) — We're here to help

---

<p align="center">
  Built with care by <a href="https://myaifitting.com">PrimeStyle AI</a>
</p>
