npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@avis-ai/tryout

v1.0.6

Published

React components and hooks for Avis AI virtual try-on (reference images, generate, optional local persistence).

Downloads

772

Readme

Avis Tryout (@avis-ai/tryout)

React components and hooks for virtual try-on: upload or import garment and face reference images, optional body measurements, and generate a composed look using the same project API key and billing model as AvisChat. Reference images are stored on the API host (S3); only public https URLs are sent to the image model (no huge base64 payloads).

Headless option: use AvisTryoutClient from this package (same REST calls as the UI). It builds on @avis-ai/sdk-js for Authorization: Bearer requests and error parsing.

Contents


Getting your API key

Same project key as chat — create a project in the dashboard and use its API key on every tryout request.

  1. Log in to the Dashboard
  2. Create a project (or open an existing one)
  3. Copy the API key — shown once; store it securely

Use the key as apiKey on <AvisTryout /> / AvisTryoutClient, or keep it on your server and proxy tryout routes (see Proxy / production).


Allowed domains (browser)

If the project has allowed domains configured in the dashboard, browser calls must send a valid Origin header that matches one of those domains. Otherwise the API responds with 403 (DOMAIN_NOT_ALLOWED). Server-to-server calls (no Origin) are not restricted by that list.


Installation

Peer dependencies: React 18+ and React DOM 18+ (React DOM is required for optional full-screen zoom, which uses createPortal).

npm install @avis-ai/tryout @avis-ai/sdk-js
pnpm add @avis-ai/tryout @avis-ai/sdk-js
yarn add @avis-ai/tryout @avis-ai/sdk-js

Quick start (embedded UI)

"use client";

import { AvisTryout } from "@avis-ai/tryout";

export function MyTryout() {
  return (
    <AvisTryout
      apiKey={process.env.NEXT_PUBLIC_AVIS_API_KEY!}
    />
  );
}

You get gender chips, optional face/top/bottom/accessory image URL + file upload, measurements panel, generate button, Reset all, and recent results with Edit & generate / Regenerate actions. baseUrl defaults to https://api-ai.avi-s.in if omitted.


Headless: client + hook

AvisTryoutClient

import { AvisTryoutClient } from "@avis-ai/tryout";

const client = new AvisTryoutClient({
  apiKey: process.env.AVIS_API_KEY!,
});

const { url } = await client.uploadTryoutImage(file);
const out = await client.generate({
  sessionId: "my-session",
  person: { faceImageUrl: url, gender: "female" },
  outfit: {
    top: { imageUrl: topUrl, color: "navy" },
    bottom: { imageUrl: bottomUrl }
  }
});
console.log(out.imageUrl);

useAvisTryout

Same defaults as <AvisTryout />, plus local profile + history. On the web, persistence defaults to localStorage plus IndexedDB for mirrored result blobs when available. Pass persistence to use AsyncStorage (or in-memory) on React Native — see React Native / mobile.

import { useAvisTryout } from "@avis-ai/tryout";

function CustomTryout() {
  const { profile, setProfile, history, isLoading, error, generateTryout, resetTryout } = useAvisTryout({
    apiKey: "your-api-key"
  });

  return (
    <div>
      <button type="button" disabled={isLoading} onClick={() => generateTryout()}>
        Generate
      </button>
      <button type="button" onClick={() => void resetTryout()}>
        Reset
      </button>
      {error && <p>{error.message}</p>}
      {history.map((h) => (
        <img key={h.id} src={h.displayUrl ?? h.imageUrl} alt="" width={200} />
      ))}
    </div>
  );
}

REST API overview

All routes use Authorization: Bearer <project_api_key> and Content-Type: application/json except POST /v1/tryout/upload (multipart form field file).

| Method | Path | Purpose | |--------|------|--------| | POST | /v1/tryout/upload | Multipart image → stored file → returns { url } (public https). | | POST | /v1/tryout/import-image | JSON { "url" } → server fetches image (rules apply) → returns { url }. | | POST | /v1/tryout/generate | JSON tryout payload → returns { imageUrl, sessionId, ... }. | | POST | /v1/tryout/mirror-result-image | JSON { "imageUrl" } → returns raw image bytes (allowlisted hosts); used to persist results locally without CORS issues. |

Default API origin: https://api-ai.avi-s.in (strip trailing slash when overriding).


Images: upload, import, generate

  1. Upload (uploadTryoutImage) or import (importTryoutImageFromUrl) each reference image so you receive a stable https URL on your storage (e.g. S3).
  2. Put those URLs in person.faceImageUrl, outfit.top.imageUrl, outfit.bottom.imageUrl, outfit.accessories[].imageUrl as needed.
  3. Call generate with that JSON. data: URLs are rejected — always host first.

Partner integrations (URLs vs upload)

  • Multipart upload — best when you already have file bytes (browser or your backend).
  • Import by URL — best when partners expose direct CDN image URLs (image/jpeg, etc.). Product HTML pages are a poor source; the server may try to resolve og:image / twitter:image for HTML responses, but direct asset URLs are what you want in production.

Body measurements

Optional person.bodyMeasurements uses US-style retail units:

| Field | Unit | |-------|------| | heightInches | inches | | weightLbs | pounds | | chestInches, waistInches, hipInches, shoulderInches, inseamInches | inches |

Omit any field you do not need.


<AvisTryout /> props

Required: apiKey. All other props are optional.

| Prop | Type | Default | Description | |------|------|---------|-------------| | apiKey | string | — | Project API key (Bearer). | | baseUrl | string | https://api-ai.avi-s.in | API origin (no trailing slash). Optional if you use the hosted API. | | sessionId | string | auto in hook | Passed through to generate; hook persists session id in localStorage. | | quality | "low" \| "medium" \| "high" | provider/default behavior | Optional integration-level override for generation quality (no built-in UI selector). When set, each generate call uses this quality. | | theme | "light" \| "dark" | "dark" | | | title / subtitle | string | defaults | Header copy. | | className / style | — | — | Outer container. | | styles | AvisTryoutStyleOverrides | — | Inline style overrides per region (see source types). | | maxAccessories | number | 10 | Cap for accessory rows. | | showImagePreviews | boolean | true | Toggle inline previews for selected images. | | zoomableGeneratedImages | boolean | false | When true, tap result for full-screen zoom (wheel + drag). Off for API-only / custom layouts. | | persistence | TryoutPersistence | web default | Pluggable storage for profile/history/session (e.g. createAsyncStorageTryoutPersistence on native). | | uploadLoader | ReactNode \| (section) => ReactNode | AVIS branded loader | Custom loader for active upload section. Only the in-progress section is disabled; other sections stay interactive. | | labels | object | — | generateButton, resetButton, regenerateButton, editButton, recentTitle, addAccessory, removeAccessory, noHistory, tapToZoomHint. |


Custom upload loader

uploadLoader controls what is shown while a section upload/import is in progress.

Behavior:

  • Loader appears only for the active section that is uploading.
  • Only that section's upload controls are disabled; other sections remain usable.
  • If uploadLoader is omitted, AvisTryout uses the default AVIS-branded animated loader.

You can pass either:

  • ReactNode: one shared loader UI for every section.
  • (section: string) => ReactNode: dynamic loader based on section id.

Section ids passed to the function:

  • face
  • top
  • bottom
  • acc-<index> (for accessories, e.g. acc-0, acc-1)

Example (single shared loader):

<AvisTryout
  apiKey={API_KEY}
  uploadLoader={<span style={{ fontSize: 12 }}>Uploading to AVIS…</span>}
/>

Example (custom per section):

<AvisTryout
  apiKey={API_KEY}
  uploadLoader={(section) => (
    <span style={{ fontSize: 12 }}>
      {section.startsWith("acc-") ? "Uploading accessory…" : `Uploading ${section}…`}
    </span>
  )}
/>

useAvisTryout hook

Options: apiKey, baseUrl?, sessionId?, quality? (same as component/client), plus:

  • persistence? — see TryoutPersistence and createAsyncStorageTryoutPersistence in the package exports.
  • persistHistoryBySession? (boolean, default true) — stores/loads recent history under a session-scoped key so refresh keeps the same session's recents.

Quality behavior

  • If you pass quality, the hook/component applies it on every generate request.
  • Supported values: low, medium, high.
  • In Replicate mode, server maps quality to resolution before upstream call:
    • low -> 1K
    • medium -> 2K
    • high -> 4K

Returns:

| Field | Type | Description | |-------|------|-------------| | profile | TryoutGenerateInput | Form state; synced to localStorage. | | setProfile | (patch) => void | Merge patch into profile and persist. | | history | TryoutHistoryItem[] | Recent generations; displayUrl may be a blob: from IndexedDB. | | isLoading | boolean | true while generate (+ mirror) runs. | | error | Error \| null | Last error. | | generateTryout | (input?) => Promise<TryoutGenerateOutput> | Merges profile, calls API, updates history, mirrors result for offline-friendly thumbnails. | | resetTryout | () => Promise<void> | Clears profile, history, mirrored local blobs, and persisted tryout sessionId for a fresh start. |

Use the embedded component's history actions to speed iteration:

  • Edit & generate: loads a previous item's input back into the form so users can tweak and regenerate.
  • Regenerate: reruns generation with that item's exact previous input.

Result preview & zoom (optional)

Set zoomableGeneratedImages to enable an e-commerce style tap → full-screen preview: scroll to zoom, drag when zoomed, double-click to reset, Esc / backdrop / Close to dismiss. Partners who only consume generate JSON can leave this false.


Session & local history

  • sessionId in the generate payload groups usage on the server; the hook generates and persists one under the key avis-tryout-session-id (in the active persistence adapter) unless you pass sessionId.
  • History is JSON under avis-tryout-history and (by default) also under avis-tryout-history:<sessionId>. Session-scoped history is what enables recent items to survive refresh for the same session in the demo.
  • On the web, mirrored result thumbnails use IndexedDB when persistence.canMirror is true; otherwise history items use the remote imageUrl only (URLs may expire).
  • Old saved profiles with cm/kg measurements are migrated to inches/lb on load when possible.
  • resetTryout() clears profile/history/session keys and mirrored local images for complete reset flows.

React Native / mobile

  • <AvisTryout /> is built for React DOM (react-dom, file inputs, createPortal). Use it inside a WebView if you want the stock UI on mobile, or build your own screen with the primitives below.
  • AvisTryoutClient is fetch-only — safe to use in React Native and native shells for upload, import, generate, and mirror.
  • useAvisTryout works in RN when you pass persistence: use createAsyncStorageTryoutPersistence(AsyncStorage) from @react-native-async-storage/async-storage (you add that dependency in your app; this package does not depend on it). Mirroring to a local blob cache stays off on that adapter (canMirror: false), so history[].displayUrl is usually undefined and you should render imageUrl (or download/cache images yourself if you need offline thumbnails).
import AsyncStorage from "@react-native-async-storage/async-storage";
import {
  useAvisTryout,
  createAsyncStorageTryoutPersistence
} from "@avis-ai/tryout";

const persistence = createAsyncStorageTryoutPersistence(AsyncStorage);

function TryoutScreen() {
  const { profile, setProfile, history, isLoading, error, generateTryout } = useAvisTryout({
    apiKey: YOUR_KEY,
    persistence
  });
  // … your RN UI; images: <Image source={{ uri: h.displayUrl ?? h.imageUrl }} />
}

For tests or SSR with no storage, use createMemoryTryoutPersistence().


Embedding without React (script widget)

If your site is not React-based, load the hosted tryout iframe widget script from your API origin.

<script
  src="https://api-ai.avi-s.in/tryout-widget.js"
  data-api-key="sk_live_xxx"
  data-embed-url="https://demo-ai.avi-s.in/tryout-embed"
  data-floating="true"
  data-width="420px"
  data-height="760px"
></script>

Supported attributes:

  • data-api-key (required): project API key used by the embedded tryout UI.
  • data-embed-url (optional): hosted embed page URL. Defaults to http://localhost:3002/tryout-embed for local development.
  • data-floating (optional, default true): floating launcher mode (true) vs always-visible panel (false).
  • data-width, data-height, data-bottom, data-right, data-border-radius, data-z-index (optional): iframe layout tuning.
  • data-launcher-size, data-launcher-label, data-launcher-emoji (optional): floating launcher appearance.

For production, host your own public embed page (or use your demo host), then point data-embed-url to that URL.


Proxy / production

For production, avoid exposing a live project secret in the browser if your policy forbids it. Proxy /v1/tryout/* from your origin and attach the key on the server, or issue short-lived tokens your BFF exchanges for upstream calls.

<AvisTryout
  apiKey={process.env.NEXT_PUBLIC_AVIS_API_KEY!}
  baseUrl={process.env.NEXT_PUBLIC_AVIS_BASE_URL}
/>

NEXT_PUBLIC_* keys are visible to clients — use only for dev/staging or public keys you accept rotating.


TypeScript types

Re-exported from @avis-ai/tryout:

import type {
  AvisTryoutProps,
  AvisTryoutStyleOverrides,
  TryoutPersistence,
  TryoutGenerateInput,
  TryoutGenerateOutput,
  TryoutClientOptions,
  TryoutHistoryItem,
  TryoutPerson,
  TryoutOutfit,
  TryoutRender,
  BodyMeasurements,
  GarmentInput,
  AccessoryInput,
  UseAvisTryoutOptions,
  UseAvisTryoutReturn
} from "@avis-ai/tryout";

Styling

<AvisTryout /> uses inline styles by default. Pass styles (AvisTryoutStyleOverrides) to merge React CSSProperties over regions such as container, form, buttonPrimary, historyCard, imagePreview, etc. (see AvisTryout.tsx).


Errors

  • Failed uploads/imports/generate throw from AvisTryoutClient using parseErrorResponse from @avis-ai/sdk-js.
  • <AvisTryout /> shows the last error.message under the form.
  • 401 / 403 — bad key, or origin not in allowed domains.

Next.js notes

  • Add "use client" to any file that imports AvisTryout or useAvisTryout.
  • Do not read localStorage for sessionId on the server render; follow the same hydration pattern as AvisChat README Session persistence (initialize ids in useEffect after mount).

Related packages

| Package | Role | |---------|------| | @avis-ai/avischat | Chat UI + useAvisChat | | @avis-ai/sdk-js | Avis client, parseErrorResponse, chat APIs |