Skip to main content

Virtual Try-On

Customers can upload a face photo and see themselves wearing any design they've created in the Design Editor. The feature uses the /store/ai/tryon backend endpoint.

Architecture

Design Editor (Konva stage)
↓ toDataURL() ← garment image (base64)
TryOnModal
↓ FileReader.readAsDataURL() ← face photo (base64)
generateTryOn() server action
↓ POST /store/ai/tryon
Backend → AI Provider → result_url

<img> + Download link

Backend

Route: POST /store/ai/tryon

Request body:

{
"garment_image_base64": "data:image/png;base64,...",
"face_image_base64": "data:image/jpeg;base64,...",
"cloth_type": "upper_body" | "lower_body" | "dress",
"gender": "female" | "male"
}

Response:

{
"result": {
"result_url": "https://...",
"media_id": "optional-saved-media-id"
}
}

Requires auth (Authorization: Bearer <token>). Returns 401 if unauthenticated.

Frontend Files

FileRole
src/lib/data/ai-tryon.tsNext.js server action — POSTs to /store/ai/tryon
src/modules/products/components/design-editor/components/try-on-modal.tsxThe modal UI
src/modules/products/components/design-editor/hooks/use-design-editor.tsshowTryOnModal state
src/modules/products/components/design-editor/components/top-bar.tsxDesktop "Try On" button
src/modules/products/components/design-editor/components/editor-sidebar.tsxMobile "Try On" button
src/modules/products/components/design-editor/index.tsxWires everything together

Server Action

generateTryOn() in src/lib/data/ai-tryon.ts returns errors in the response object (never throws). This is intentional — Next.js Server Actions suppress thrown errors in production for security reasons, which would hide AUTH_REQUIRED errors from the client.

// Good ✓
return { error: { code: "AUTH_REQUIRED", message: "..." } }

// Bad ✗ — message stripped in production
throw new Error("AUTH_REQUIRED")

State Management

showTryOnModal / setShowTryOnModal live in useDesignEditor(), consistent with the checkout modal pattern:

const [showTryOnModal, setShowTryOnModal] = useState(false)

Returned from the hook, consumed by index.tsx.

Cloth Type Options

ValueLabel
upper_bodyUpper Body
lower_bodyLower Body
dressFull Dress

Default: upper_body

Unauthenticated State

If customer prop is null/undefined, the modal shows a sign-in prompt instead of the upload controls. No API call is made.

Generation Time

The backend AI model typically takes ~20 seconds. A hint is shown during loading:

"This takes ~20 seconds…"