shopar-plugin
Version:
Plugin for the Web that seamlessly integrates into your webpage to create embedded virtual try-on and 3D preview capabilities.
620 lines (612 loc) • 21 kB
TypeScript
type SkuData = {
category?: AssetCategory;
arUrl?: string;
arEnvUrl?: string;
arDiamondEnvUrl?: string;
arToneMapping?: ToneMapping;
arToneMappingExposure?: number;
arBloomEnabled?: boolean;
arBloomStrength?: number;
arBloomRadius?: number;
arBloomThreshold?: number;
arKey?: string;
arPromptEnabled?: boolean;
arPromptText?: string;
arPromptImage?: string;
previewUrl?: string;
previewEnvUrl?: string;
previewDiamondEnvUrl?: string;
previewToneMapping?: ToneMapping;
previewToneMappingExposure?: number;
previewBloomEnabled?: boolean;
previewBloomStrength?: number;
previewBloomRadius?: number;
previewBloomThreshold?: number;
previewPosterUrl?: string;
cameraErrorText?: string;
qrPromptText?: string;
};
declare const ASSET_CATEGORIES: readonly ["Glasses", "Shoes", "Watches", "Bracelets", "Handbags", "Rings", "Bottles", "Scarves", "Hats", "Necklaces", "Earrings"];
type AssetCategory = typeof ASSET_CATEGORIES[number];
declare const TONE_MAPPINGS: readonly ["ACES", "Linear", "Neutral"];
type ToneMapping = typeof TONE_MAPPINGS[number];
declare const strings_: {
'loading.ar': string;
'prompt.ar.shoes': string | undefined;
'prompt.ar.glasses': string | undefined;
'prompt.ar.watches': string | undefined;
'prompt.ar.bracelets': string | undefined;
'prompt.ar.scarves': string | undefined;
'prompt.ar.hats': string | undefined;
'prompt.ar.necklaces': string | undefined;
};
type Strings = typeof strings_;
/**
* Truescale output measurements
*/
type FaceMeasurement = {
/**
* Face width in millimeters.
*/
faceWidth: number;
/**
* Interpupillary distance in millimeters.
*/
IPD: number;
};
/**
* Type that wraps face position and orientation.
*/
type FacePose = {
/**
* Face position in uncalibrated 3D space.
*/
translation: number[];
/**
* Face rotation represented as Tait-Bryan angles (nautical angles).
*
* Sequence of fields in this array is yaw, pitch, roll (heading, elevation, bank).
*/
rotation: number[];
};
/**
* Plugin controller.
*/
type Plugin = {
/**
* Launches the AR view.
* Set to `undefined` if AR is not supported for given SKU.
*
* @returns A promise that resolves when AR is launched.
*/
launchAR?: () => Promise<void>;
/**
* Launches the 3D view.
* Set to `undefined` if 3D is not supported for given SKU.
*
* @returns A promise that resolves when 3D is launched.
*/
launch3D?: () => Promise<void>;
/**
* Closes the AR view.
* Set to `undefined` if AR is not supported for given SKU.
*
* @returns A promise that resolves when AR is closed.
*/
closeAR?: () => Promise<void>;
/**
* Closes the 3D view.
* Set to `undefined` if 3D is not supported for given SKU.
*
* @returns A promise that resolves when 3D is closed.
*/
close3D?: () => Promise<void>;
/**
* Closes the AR or 3D view.
* Set to `undefined` if neither AR nor 3D are supported for given SKU.
*
* @returns A promise that resolves when AR or 3D is closed.
*/
close?: () => Promise<void>;
/**
* Returns the current user interactivity value.
*
* @returns `true` is user interactivity is enabled and `false` otherwise.
*/
isInteractive: () => boolean;
/**
* Sets user interactivity to the provided value. Set to `false` to ignore input events.
*
* @param value The provided value.
*/
setInteractive: (interactive: boolean) => void;
/**
* Zooms the 3D view in.
* The magnification is multiplied by `2^power`, so a power of 1 doubles the magnification.
* Has no effect if the 3D view is not currently active.
* Set to `undefined` if 3D is not supported for given SKU.
*
* @param power The exponent applied to the zoom. Each unit doubles the magnification.
*/
zoomIn3D?: (power: number) => void;
/**
* Zooms the 3D view out.
* The magnification is divided by `2^power`, so a power of 1 halves the magnification.
* Has no effect if the 3D view is not currently active.
* Set to `undefined` if 3D is not supported for given SKU.
*
* @param power The exponent applied to the zoom. Each unit halves the magnification.
*/
zoomOut3D?: (power: number) => void;
/**
* Rotates the 3D model horizontally by the specified number of degrees.
* The initial animation is stopped on the first call.
* Has no effect if the 3D view is not currently active.
* Set to `undefined` if 3D is not supported for given SKU.
*
* @param degrees The rotation angle in degrees. Positive values rotate the model right, negative values rotate left.
*/
rotateHorizontally3D?: (degrees: number) => void;
/**
* Rotates the 3D model vertically by the specified number of degrees.
* The initial animation is stopped on the first call.
* Has no effect if the 3D view is not currently active.
* Set to `undefined` if 3D is not supported for given SKU.
*
* @param degrees The rotation angle in degrees. Positive values rotate the model up, negative values rotate down.
*/
rotateVertically3D?: (degrees: number) => void;
};
/**
* Vision plugin controller
*/
type VisionPlugin = {
/**
* Register a face pose callback which will be called if face is detected.
*/
registerFacePoseListener?: (facePoseListener: (facePose: FacePose) => void) => void;
/**
* Register a face measurement callback which will be called if face is detected.
*/
registerFaceMeasurementListener?: (faceMeasurementListener: (faceMeasurement: FaceMeasurement) => void) => void;
/**
* Switch the AR effect for preview
*
* This call is a thin wrapper around DeepAR.switchEffect API.
*
* @param arUrl A path to the AR effect file
* @returns Promise that resolves when an effect start rendering
*/
switchEffect?: (arUrl: string) => Promise<void>;
/**
* Clear the AR effect
*
* Call this after switchEffect to clear the loaded effect.
* @returns void
*/
clearEffect?: () => void;
/**
* Closes the vision plugin and releases the camera.
*
* @returns A promise that resolves when AR is closed.
*/
close?: () => void;
};
type ArVideoConfig = {
video: HTMLVideoElement;
mirror: boolean;
};
/** Preview state values. */
declare const PREVIEW_STATES: readonly ["AR", "3D"];
/** Preview state type. */
type PreviewState = typeof PREVIEW_STATES[number];
/**
* Configuration of an animation key frame at the specified time point.
*/
type KeyFrameConfig = {
/** Timestamp (in ms). */
time: number;
/** Vertical angle of rotation (in degrees). */
pitch?: number;
/** Horizontal angle of rotation (in degrees). */
yaw?: number;
/** Camera's field of view (in degrees). */
fov?: number;
/**
* Easing function used for interpolating the values between this and the next key frame.
*
* Supported options are:
* - `'hold'`: maintain the current value without interpolation.
* - `'linear'`: linear interpolation.
* - `'sine'`: sine wave interpolation.
* - `'ease'`: starts slowly, accelerates sharply and slows gradually towards the end.
* - `'ease-in'`: starts slowly, progressively speeds up until the end, at which point it stops abruptly.
* - `'ease-out'`: starts abruptly and progressively slows down towards the end.
* - `'ease-in-out'`: smooth start and end with gradual acceleration and decceleration.
*
* Additionally, it's possible to specify a custom Bézier function:
* - `'cubic-bezier(x1, y1, x2, y2)'`: define two 2D points for a custom interpolation curve.
*
* @default 'ease-in-out'
*/
interpolation?: string;
};
/**
* Options used for the plugin setup.
*/
type SetupOptions = {
/** API key found in the ShopAR dashboard. */
apiKey: string;
/** Product identifier. */
sku: string;
/**
* If provided, the API call is skipped and this SKU data is used instead.
*/
skuData?: SkuData;
/**
* The element to inflate with ShopAR UI.
*
* @remarks If using default UI, its CSS position property must be either 'static' or 'relative'.
*/
targetElement: HTMLElement;
/**
* If provided, defines which preview type the plugin initializes to.
*/
initialState?: PreviewState;
/**
* If provided, defines where the additional ShopAR plugin files are fetched from.
*
* @default `https://cdn.jsdelivr.net/npm/shopar-plugin@${version}/`
*/
baseUrl?: string;
/**
* If provided and set to `false`, disables the default UI such as buttons, loading and error views.
*
* When the default UI is disabled, use the returned object as a controller:
* ```js
* const shopAR = await ShopAR.plugin.setup({
* // ...
* defaultUI: false,
* });
* shopAR.launchAR();
* ```
*
* @default true
*/
defaultUI?: boolean;
/**
* If provided and set to `false`, disables user interactivity by ignoring input events.
*
* @default true
*/
interactive?: boolean;
/**
* If provided, the corresponding touch scroll behavior will be used in 3D.
*
* Supported values are:
* - `none`: Touch gestures are never interpreted as scrolling. This might be useful if 3D occupies the whole viewport.
* - `pan-x`: Touch gestures that start horizontally are interpreted as scrolling.
* - `pan-y`: Touch gestures that start vertically are interpreted as scrolling.
*
* @default 'pan-y'
*/
touchAction?: 'none' | 'pan-x' | 'pan-y';
/**
* If provided and set to `false`, disables zoom in 3D by ignoring mouse scroll or pinch touch events.
*
* @default true
*/
zoomEnabled?: boolean;
/**
* If provided, it will be used as the minimum zoom level in 3D.
*
* @default 0.625
*/
minZoom?: number;
/**
* If provided, it will be used as the maximum zoom level in 3D.
*
* @default 5
*/
maxZoom?: number;
/**
* If provided and set to `true`, transparent background will always be used in 3D.
*
* This overrides the default behaviour which uses the transparent background only for models **without** transmissive materials.
*
* WARNING:
* Opaque background is intentionally used for models with transmission to avoid the associated rendering issues.
* When using this feature, please make sure that the transmissive parts of the model look as desired.
*
* @default false
*/
alwaysTransparentBackground?: boolean;
strings?: Partial<Strings>;
/**
* If provided, replaces the default interactivity animation in 3D with a custom one.
*
* Two formats are supported: `KeyFrameConfig[]` and `string`.
* For more information on the `KeyFrameConfig[]` format, see {@link KeyFrameConfig}.
*
* The `string` format is interpreted as a plain-text table. Empty lines and comments are ignored.
* First line defines the columns and all subsequent lines define data per key frame.
*
* Supported columns are:
* - `time`: timestamp of the key frame.
* - `pitch`: vertical angle of rotation.
* - `yaw`: horizontal angle of rotation.
* - `fov`: camera's field of view.
* - `interpolation`: easing function used for interpolating the values between this and the next key frame.
* See {@link KeyFrameConfig.interpolation} for supported options.
*
* Timestamps are specified with or without a unit (`ms` or `s`). When not specified, milliseconds are used.
*
* Angles are specified with or without a unit (`deg` or `rad`). When not specified, degrees are used.
*
* @example
* `
* # Empty lines and comments are ignored.
*
* time pitch yaw fov interpolation
* 0s 45deg 60deg 25deg hold
* 1s 45deg 60deg 25deg ease-in-out
* 2s 60deg -60deg 20deg hold
* 3s 60deg -60deg 20deg ease-in-out
* 4s 90deg 90deg 40deg hold
* 5s 90deg 90deg 40deg ease-in-out
* 6s 45deg 420deg 25deg hold
* `
*
* @example
* [
* { time: 0, pitch: 45, yaw: 60, fov: 25, interpolation: 'hold' },
* { time: 1000, pitch: 45, yaw: 60, fov: 25, interpolation: 'ease-in-out' },
* { time: 2000, pitch: 60, yaw: -60, fov: 20, interpolation: 'hold' },
* { time: 3000, pitch: 60, yaw: -60, fov: 20, interpolation: 'ease-in-out' },
* { time: 4000, pitch: 90, yaw: 90, fov: 40, interpolation: 'hold' },
* { time: 5000, pitch: 90, yaw: 90, fov: 40, interpolation: 'ease-in-out' },
* { time: 6000, pitch: 45, yaw: 420, fov: 25, interpolation: 'hold' },
* ]
*/
initialAnimation?: KeyFrameConfig[] | string;
/**
* If provided, it will be called the first time the user's subject is detected in AR (e.g. face, feet, wrist).
* It fires only once per setup.
*/
onFirstAREngagement?: () => void;
/**
* If provided, it will be called the first time the user engages with the 3D view (rotate, pan or zoom).
* It fires only once per setup.
*/
onFirst3DEngagement?: () => void;
/**
* If provided, it will be used as the debounce duration for debounced AR engagement tracking.
*
* @default 2000
* @see onDebouncedAREngagement
*/
debounceAREngagementMs?: number;
/**
* If provided, it will get called with the engagement duration on every (debounced) AR engagement.
*
* AR engagement is measured as the time spent by the user virtually trying out the product in AR.
* The callback is called after engagement stops for the specified debounce duration.
* Additionally, any outstanding engagement duration is flushed when AR is closed.
*
* @param durationMs Engagement duration in milliseconds.
* @see debounceAREngagementMs
*/
onDebouncedAREngagement?: (durationMs: number) => void;
/**
* If provided, it will be used as the debounce duration for debounced 3D engagement tracking.
*
* @default 2000
* @see onDebounced3DEngagement
*/
debounce3DEngagementMs?: number;
/**
* If provided, it will be called with the engagement duration on every (debounced) 3D engagement.
*
* 3D engagement is measured as the time spent by the user rotating, panning or zooming the product in 3D.
* The callback is called after engagement stops for the specified debounce duration.
* Additionally, any outstanding engagement duration is flushed when 3D is closed.
*
* @param durationMs Engagement duration in milliseconds.
* @see debounce3DEngagementMs
*/
onDebounced3DEngagement?: (durationMs: number) => void;
/**
* If provided, it will be called when the maximum zoom level (`maxZoom`) is reached in 3D.
*/
onMaxZoomEnter?: () => void;
/**
* If provided, it will be called when the zoom level moves away from the maximum (`maxZoom`) in 3D.
*/
onMaxZoomLeave?: () => void;
/**
* If provided, it will be called when the minimum zoom level (`minZoom`) is reached in 3D.
*/
onMinZoomEnter?: () => void;
/**
* If provided, it will be called when the zoom level moves away from the minimum (`minZoom`) in 3D.
*/
onMinZoomLeave?: () => void;
/**
* If provided, it will be called when the minimum vertical angle is reached in 3D.
* This corresponds to the camera being positioned at the top of the orbit, looking down at the object.
*/
onMinVerticalAngleEnter?: () => void;
/**
* If provided, it will be called when the vertical angle moves away from the minimum in 3D.
* The camera is no longer at the top of the orbit.
*/
onMinVerticalAngleLeave?: () => void;
/**
* If provided, it will be called when the maximum vertical angle is reached in 3D.
* This corresponds to the camera being positioned at the bottom of the orbit, looking up at the object.
*/
onMaxVerticalAngleEnter?: () => void;
/**
* If provided, it will be called when the vertical angle moves away from the maximum in 3D.
* The camera is no longer at the bottom of the orbit.
*/
onMaxVerticalAngleLeave?: () => void;
/**
* If provided, it will be used as the video source for AR instead of the default camera used by plugin.
*
* Example of loading HTMLVideoElement:
* ```js
* function loadVideo(src) {
* const video = document.createElement('video');
* video.src = src;
* video.muted = true;
* video.setAttribute("playsinline", "playsinline");
* video.load();
* video.onloadedmetadata = () => {
* video.play();
* };
*
* return video;
* }
* ```
*/
customArVideo?: ArVideoConfig;
/**
* If provided, it will be used as the true scale face width, in millimeters, for AR glasses.
*
* If not provided, the value is determined by ShopAR True Scale technology.
*/
customTrueScaleFaceWidth?: number;
_internalOptions?: any;
};
/**
* Options used for the vision plugin setup.
*/
type VisionOptions = {
/** API key found in the ShopAR dashboard. */
apiKey: string;
/**
* The element to inflate with camera canvas.
*/
targetElement: HTMLElement;
/**
* If provided, defines where the additional ShopAR plugin files are fetched from.
*
* @default `https://cdn.jsdelivr.net/npm/shopar-plugin@${version}/`
*/
baseUrl?: string;
};
/**
* Base error class for all ShopAR plugin errors.
*/
declare class PluginError extends Error {
constructor(message: string);
}
/**
* Error thrown when setup or option validation fails.
*/
declare class ValidationError extends PluginError {
constructor(message: string);
}
/**
* Error thrown when the ShopAR API call fails.
*/
declare class ApiError extends PluginError {
status: number | undefined;
constructor(message: string, status?: number);
}
/**
* Error thrown when SKU data sanitization fails.
*/
declare class SanitizationError extends PluginError {
constructor(message: string);
}
/**
* Error thrown when 3D fails to launch.
*/
declare class Launch3DError extends PluginError {
constructor(message?: string);
}
/**
* Error thrown when AR fails to launch.
*/
declare class LaunchARError extends PluginError {
constructor(message?: string);
}
/**
* Error thrown when the user denies camera permissions.
*/
declare class CameraPermissionDeniedError extends LaunchARError {
constructor(message?: string);
}
/**
* Error thrown when QR code launch fails.
*/
declare class QRError extends LaunchARError {
constructor(message?: string);
}
/**
* ShopAR vision plugin.
*
* @example
* Using CDN:
* ```html
* <script src="../../shopar-plugin/shopar-plugin.js"></script>
* <script>
* const vision = ShopAR.vision.setup({ ... });
* </script>
* ```
*
* @example
* Using a module bundler:
* ```js
* import { ShopAR } from 'shopar-plugin';
*
* const vision = ShopAR.vision.setup({ ... });
* ```
*/
declare const vision: {
/**
* Initializes vision modules and renderes deepar canvas.
*
* If successful, function returns a handle to the VisionPlugin. This component alows for lower level control
* over DeepAR and truescale components.
*
* @param options Setup options.
*/
setup: (options: VisionOptions) => Promise<VisionPlugin>;
};
/**
* The ShopAR plugin.
*
* @example
* Using CDN:
* ```html
* <script src="../../shopar-plugin/shopar-plugin.js"></script>
* <script>
* ShopAR.plugin.setup({ ... });
* </script>
* ```
*
* @example
* Using a module bundler:
* ```js
* import { ShopAR } from 'shopar-plugin';
*
* ShopAR.plugin.setup({ ... });
* ```
*/
declare const plugin: {
/**
* Fetches the specified product from the ShopAR API and renders the ShopAR UI.
*
* Optionally, you can provide a `skuData` object to bypass the API call and use the provided SKU data directly.
*
* @param options Setup options.
*/
setup: (options: SetupOptions) => Promise<Plugin>;
/** Plugin version. */
version: string;
};
export { ApiError, CameraPermissionDeniedError, Launch3DError, LaunchARError, PREVIEW_STATES, PluginError, QRError, SanitizationError, ValidationError, plugin, vision };
export type { ArVideoConfig, FaceMeasurement, FacePose, KeyFrameConfig, Plugin, PreviewState, SetupOptions, SkuData, VisionOptions, VisionPlugin };