3D Spins Integration Guide

3D Spins are non-configurable WebGL 3D models designed for a client’s product page to enable shoppers to manipulate and investigate a product. Shoppers may spin the product on any axis and zoom in to see greater levels of detail. The target audience for 3D spins is e-commerce shoppers. The product increases customer engagement with an average 1-2 minute session time, improves the shopping experience and increases conversion rates through 10-30% lift in Add-To-Cart rates.

Among the major features of 3D Spins includes:

  • Spin and rotate of products
  • Zoom in and out
  • Direct download of product image (with resolution options)
  • Ability to Add to Cart (ATC)
  • Displaying product measurements (optional)
  • Offering preset camera views
  • Product filter support
  • Social sharing
  • Web AR support if viewed from a mobile phone (optional)

3D Spins File Creation

3D Cloud™ by Marxent will create all 3D Spins assets as part of the licensing agreement for the product. Among the requested inputs and specifications include:

  • Recommended total polygon count of below 100K
  • Any relevant photography references and dimensions for each product
  • Identification and photos of any unique properties of each product
  • Recommended references to any High-resolution materials
  • If applicable, conversion from CAD, DAE, 3D Max, Obj, FBX, STL is supported
  • Any product business and assembly rules

3D Spins API

CDNS

3D Cloud employs content delivery networks (CDNS) to enable geographically dispersed caching of content to reduce latency that can exist with rich content. 3D Cloud’s taxonomy for the CDNs are as follows:
https://cdn.3dcloud.io/mxt-3d-spin-viewer//Mxt3dSpin-.min.js
https://cdn.3dcloud.io/mxt-3d-spin-viewer//Mxt3dSpin-.js
https://cdn.3dcloud.io/mxt-3d-spin-viewer//Mxt3dSpin-.css

Examples of how 3DSpins version 5.3.3-build.1 would be represented as CDNS:
https://cdn.3dcloud.io/mxt-3d-spin-viewer/5.3.3-build.1/Mxt3dSpin-5.3.3-build.1.min.js
https://cdn.3dcloud.io/mxt-3d-spin-viewer/5.3.3-build.1/Mxt3dSpin-5.3.3-build.1.js
https://cdn.3dcloud.io/mxt-3d-spin-viewer/5.3.3-build.1/Mxt3dSpin-5.3.3-build.1.css

If using from CDN, this creates a global object Mxt3dSpin that has the Mxt3dSpinViewer and MxtAssetEnvironment on it, so basic setup would be new Mxt3dSpin.Mxt3dSpinViewer

NPM

3D Cloud’s private npm registry is located here: https://nexus.3dcloud.io/repository/npm-group/
Our repository is here: @mxt/mxt-3d-spin-viewer

We will set you up with credentials that give you read access to necessary repositories. Syntax for access is as follows:

import {Mxt3dSpinViewer} from '@mxt/mxt-3d-spin-viewer/lib/Mxt3dSpinViewer';

Build Requirements for usage from NPM

  • Scss is provided and must be converted to CSS
  • Default icon assets are provided in assets folder and if using webpack, must be bundled in appropriately using file-loader
  • By default, other assets, such as assets for i18n, shaders, and SQLite readers are stored in our CDN and read from there.
  • Must be built in an environment that handles process.env (webpack, gulp, react, etc), otherwise use CDN
  • In buildPlugins folder of @mxt/mxt-3d-spin-viewer there is a Mxt3dSpinWebpackPlugin. We will add Gulp/Grunt plugins as requested. Simply add this plugin to your webpack plugins. No options required for 3d spins.

Demo page

https://wla-spins.3dcloud.io/
i.e.
https://wla-spins.3dcloud.io/5.3.3

BrowserSupported VersionSupport Version Earliest Date
Chrome51+May 2016
Firefox54+June 2017
Edge14+August 2016
Safari10+ (Note: 15.0 not supported, 15.1+ Is supported)September 2016
Opera38+June 2016
Internet ExplorerNot Supported
Edge iOSNot Supported

Basic Usage

ApiKey, appId, and endpoint will be provided to you by 3D Cloud to provide secure access to a single-tenant cloud function.

If you have multiple selectable sku on a page, can re-use the spin viewer like so:

const spinViewer = new Mxt3dSpinViewer();
await spinViewer.init({
    apiKey: "yourCustomApiKey",
    appId: "yourCustomAppId",
    clientId: "yourCustomClientId",
    assetEnvironment: MxtAssetEnvironment.TEST or MxtAssetEnvironment.STAGING or MxtAssetEnvironment.PRODUCTION,
    element: document.getElementById('my-3d-spin-element'),
    icons: {
        close: yourCustomIcon,
        collapse: yourCustomIcon,
        download: yourCustomIcon,
        expand: yourCustomIcon,
        rotateLeft: yourCustomIcon,
        rotateRight: yourCustomIcon,
        zoomIn: yourCustomIcon,
        zoomOut: yourCustomIcon
    },
    expandButton: {
        position: 'right',
        onExpand: putYourDesiredCallbackHere,
        onCollapse: putYourOtherDesiredCallbackHere
    },
});
try {
  await spinViewer.load(sku);
  //then on selection of a different sku, 
  //await spinViewer.load(otherSku);
} catch(e) {
  if(e.status == 404) {
      //invalid sku
  }
  else if(e.status == 403) {
      //bad API key
  }
}

If you have an initial sku to load with your page, then you can provide that like so:

const spinViewer = new Mxt3dSpinViewer();
try {
  await spinViewer.init({
    initialSku: sku,
    clientId: "yourCustomClientId",
    apiKey: "yourCustomApiKey",
    appId: "yourCustomAppId",
    assetEnvironment: MxtAssetEnvironment.TEST or MxtAssetEnvironment.STAGING or MxtAssetEnvironment.PRODUCTION,
    element: document.getElementById('my-3d-spin-element'),
    icons: {
        close: yourCustomIcon,
        collapse: yourCustomIcon,
        download: yourCustomIcon,
        expand: yourCustomIcon,
        rotateLeft: yourCustomIcon,
        rotateRight: yourCustomIcon,
        zoomIn: yourCustomIcon,
        zoomOut: yourCustomIcon
    },
    expandButton: {
        position: 'right',
        onExpand: putYourDesiredCallbackHere,
        onCollapse: putYourOtherDesiredCallbackHere
    },
  });
} catch(e) {
  if(e.status == 404) {
      //invalid sku
  }
  else if(e.status == 403) {
      //bad API key
  }
}

Support

See Minimum System Requirements
Note that to see if rendering is supported, use spinViewer.isRenderingSupported() prior to init to see. Returns {supported:boolean, reason?:string}

A Note on Initializing

If you notice that the content appears blurry at first, and you are initializing the spin viewer in a hidden context (display: none), it is because the renderer has a hard time knowing how to size the content when it initially loads in a hidden context. To remedy this, whenever the content is shown, make sure you call: spinViewer.rendererResize() after showing the content to allow the renderer to correctly resize the content to the screen.

Styling

The spin viewer will take up the full amount of space that its container allows it. So in the example above, style document.getElementById('my-3d-spin-element') to be at the position and of the appropriate size that you want the mxt spin viewer to be

API - Init

Mxt3dSpin.Mxt3dSpinViewer
init
Only needs to be called once. Loads the renderer.

Due to current renderer limitations, the element that you load the renderer onto must NOT be display:none. It can be visibility:hidden. Next minor update of the renderer should fix this. Renderer loads very fast, so not much performance loss in initializing on demand. However, do not need to re-initialize once initialized once.

https://forum.babylonjs.com/t/babylon-does-not-load-properly-when-loaded-onto-display-none-div/14043/3

API - Options

export interface Mxt3dSpinViewerOptions {
    /** private access key to spins */
    apiKey:string;
    /** private app id for spins */
    appId:string;
    /** private client id for spins */
    clientId:string;
    /** @deprecated Services endpoint to retrieve spin data; this was never needed by product configurator, and is no longer needed by 3d spins as there is a single client endpoint now baked into application */
    endpoint?: string;
    /** The environment to pull assets from */
    assetEnvironment:MxtAssetEnvironment;
    /** Element to place the rendering canvas inside of */
    element: HTMLElement;
    /** Log level; defaults to WARN (3) */
    logging?: log.LogLevel;
    /** Zoom Delta - in meters; defaults to .3 */
    zoomDelta?: number;
    /** Rotate Delta - in radians; defaults to .3 */
    rotateDelta?: number;
    /** Multiplier; amount of space product takes up in screen by default; defaults to .75. */
    fitToScreenMultiplier?: number;
    /** Multiplier; How much you can zoom out past the initial zoom. Defaults to 1.33. A value of 1 would mean that the initial zoom distance is the farthest you can zoom out */
    maxDistanceMultiplier?: number;
    /** If an initial sku is provided, will auto load that sku after loading renderer */
    initialSku?:string;
    /** If initial child skus is provided (along with initial sku), will auto load those children sku after loading renderer */
    initialChildSkus?:string[]
    /** Used to override default app config lighting values */
    lighting?: Lighting;
    /** Size in pixels */
    loadingIconSize?: number;
    /** provide a CSS string */
    loadingIconColor?: string; 
    /** provide a CSS string 6.3+*/
    loadingIconBackgroundColor?: string; 
    /** provides a client-specific way of resolving skus from products, and vice-versa */
    skuResolver?: IMxtSkuResolver; 
    /** provides client-specific way of modifying the load of a product */
    loadModifiers?: IProductLoadModifierPlugin[];
    /** @deprecated Endpoint to retrieve web AR assets from; deprecated and legacy behavior that gets usdz and GLTF. Use webArOnDemandEndpoint now */
    webArEndpoint?:string;
    /** Endpoint to retrieve usdz on demand */
    webArOnDemandEndpoint?:string;
    /** Url to check and see if an AR asset exists so that if it does we don't need to request one generated */
    webArAssetExistsEndpoint?: string;
    webArOptions?: {
        //by default, both USDZ and GLTF are turned on, this allows forcing USDZ off
        disableUsdz?:boolean,
        //by default, both USDZ and GLTF are turned on, this allows forcing GLTF off
        disableGltf?:boolean
        /** @deprecated - only for use with deprecated webArEndpoint; by default, web ar uses sku to query; however can force to use product id instead for some internal uses*/
        useProductId?:string

    };
    presetViews?: {
        /** Enabled by default, but can be turned off */
        enabled?: boolean;
        views?: IMxtPresetView[]
    };
    screenshot?: {
        /** Enabled by default, but can be turned off */
        enabled?: boolean;
        /** By default, screenshot 1024x1024. May specify a different width, or set to -1 to use size on screen */
        width?: number;
        /** By default, screenshot 1024x1024. May specify a different height, or set to -1 to use size on screen */
        height?: number;
        /** By default, hi res screenshot 4096x4096. May specify a different width, or set to -1 to use size on screen */
        hiResWidth?: number;
        /** By default, hi res screenshot 4096x4096. May specify a different height, or set to -1 to use size on screen */
        hiResHeight?: number;
        imageFilename?: string;
        waterMarkPlugin?: IMxtImageWatermarkPlugin;
        downloadImagePlugins?: IMxt3dSpinDownloadImagePlugin[];
    };
    downloadBomPlugin?: IBomPlugin;

    room?: RoomOptions;


    /** Advanced camera options */
    camera?: {
        defaultBeta?: number,
        defaultAlpha?: number,
        fieldOfView?: number,
        lowerBetaLimit?: number,
        upperBetaLimit?: number,
        lowerAlphaLimit?: number,
        upperAlphaLimit?: number,
        embeddedReflectionCubeTextureUrls?: {
            nx:string,
            ny:string,
            nz:string,
            px:string,
            py:string,
            pz:string
        },
        /** Lighting app config; only applicable when using spins in a stand-alone context; from within product config or other application, use manifest app config to set lighting config */
        lighting?: Lighting
    };

    /** Custom Icons to override defualts */
    icons?: {
        close?: string,
        collapse?: string,
        presetView?: string,
        download?: string,
        expand?: string,
        rotateLeft?: string,
        rotateRight?: string,
        zoomIn?: string,
        zoomOut?: string
    };

    /** The position of this optional button is determined by accepted values, 'left' or 'right' */
    expandButton?: {
        onExpand?: any,
        onCollapse?: any,
        position?: string
    };

    customText?: {
        /** language should be an language ISO code (https://www.metamodpro.com/browser-language-codes)*/
        [language:string]: any
    };
    disableProgressiveLoad?:boolean;    // bool to disable the progressive loading if true
}

API - expandButton

You may add an expand button to the 3D spin viewer.

  • Position
    -- The expand/collapse button will appear on the far left of the button bar, by default. You may change its position to the far right side of the button bar by setting this to “right“.
  • onExpand
    -- Provide a callback function, to be executed upon clicking the expand button.
  • onCollapse
    -- Provide a callback function, to be executed upon clicking the collapse button.

API - Lighting

You may pass in configurations to affect lighting in the viewer. These values will overwrite the default values in the appConfig.

  • _BackFaceCullingDisabled : boolean
    -- default value : false

API - Load

load
Loads the given sku into the renderer. Will automatically delete anything previously loaded into renderer

API - Additional Helper Methods

/**
 * Show renderer debug panels
 */
showDebug():void;

/**
 * Clear what is currently rendered
 */
clearView(): void;

/**
 * Show camera controls
 */
showControls():void;

/**
 * Hide camera controls
 */
hideControls(): void;

/**
 * Hide expand button (pass in false to unhide)
 */
hideExpand(hide: boolean=true): void;

/**
 * Reset camera to initial position 
 */
resetCamera():void;

/**
 * Set the cubemap textures for reflections off of the object
 * See order below; its very important
 * @param cubemapUrls PX/NY/PZ/NX/PY/NZ
 */
setEmbeddedReflectionCubemap(cubemapUrls:string[]): void;

/**
 * Update the endpoint/api key (if implementing a multi tenant system)
 */
setNewEndpoint(endpoint:string, apiKey:string, clientId:string, appId:string, webArEndpoint?:string):void;

Note on Lighting

As of version 5.6 of 3DSpins, the application defaults to a standard three point lighting setup. This can be heavily customized, but the parameters are quite advanced. If you would like to tweak the lighting, please contact us.