3D configurator integration overview

This quick overview demonstrates how an Apviz 3D configurator can be integrated on any website.

Release

After having setup your 3D configurator using studio.apviz.io (or the GraphQL API) you will have to create an immutable snapshot of your 3D configurator using the release feature.

The integration URL associated with your release can then be copy/pasted right before the </body> closing tag of your HTML page:

<!-- Non-blocking async script that will call "apvizShowcaseReady" once fully loaded. -->
<script
  src="https://public.apviz.io/showcases/U0hPVzoxTFVNSVRkNGNx/releases/UkVMUzpHbUd5eHpXNmpV/main.js"
  integrity="sha384-Q0wk+t3O4LoH4UzM4rqhSLXnsDilYprJJ9tdCr6TKgg8hTWcZljFmmQUVo1xu04W"
  defer
  crossorigin="anonymous"
  data-apviz-callback="apvizShowcaseReady"
></script>

ℹ️ Note that integration URL may change for future release, so consider this URL as opaque and don't try to parse it or build it dynamically.

Basic integration (simple viewer)

This example shows you how to integrate a 3D viewer with no configuration menu.

<!DOCTYPE html>
<html>
  <head>
    <title>Apviz - Demo Ring</title>
  </head>
  <body>
    <!-- Apviz 3D viewer. -->
    <div id="apviz-3d-viewer"></div>

    <!-- Your custom initialization script. -->
    <script>
      async function apvizShowcaseReady(showcase) {

        // Initialize a 3D viewer and bind it to the <div>.
        const viewer = await showcase.createViewer({
          divId : "apviz-3d-viewer"
        });

        // Initial configuration that MUST explicitly include ALL the fields.
        // This will start displaying 3D.
        await viewer.update({
          fields : {
            "carat" : "1ct",
            "gem" : "diamond",
            "gold" : "yellow"
          }
        });

      }
    </script>

    <!-- Non-blocking async script that will call "apvizShowcaseReady" once fully loaded. -->
    <script
      src="https://public.apviz.io/showcases/U0hPVzoxTFVNSVRkNGNx/releases/UkVMUzpHbUd5eHpXNmpV/main.js"
      integrity="sha384-Q0wk+t3O4LoH4UzM4rqhSLXnsDilYprJJ9tdCr6TKgg8hTWcZljFmmQUVo1xu04W"
      defer
      crossorigin="anonymous"
      data-apviz-callback="apvizShowcaseReady"
    ></script>
  </body>
</html>

Integration with a menu

If you want to make your 3D configurable directly within your website you bind your own menu to the Viewer.update method:

<!DOCTYPE html>
<html>
  <head>
    <title>Apviz - Demo Ring</title>
  </head>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    #my-menu { position: absolute; top: 0; left: 0; padding: 10px; background-color: #ffffff; }
  </style>
  <body>
    <!-- Apviz 3D viewer. -->
    <div id="apviz-3d-viewer"></div>

    <!-- Your custom configuration menu. -->
    <div id="my-menu">
      <label for="carat">carat:</label>
      <select id="carat">
        <option>1ct</option>
        <option>0.5ct</option>
      </select>
      <label for="gem">gem:</label>
      <select id="gem">
        <option>diamond</option>
        <option>ruby</option>
      </select>
      <label for="gold">gold:</label>
      <select id="gold">
        <option>yellow</option>
        <option>white</option>
      </select>
    </div>

    <!-- Your custom initialization script. -->
    <script>
      async function apvizShowcaseReady(showcase) {

        // Initialize a 3D viewer and bind it to the <div>.
        const viewer = await showcase.createViewer({
          divId : "apviz-3d-viewer"
        });

        // Initial configuration that MUST explicitly include ALL the fields.
        // This will start displaying 3D.
        await viewer.update({
          fields : {
            "carat" : "1ct",
            "gem" : "diamond",
            "gold" : "yellow"
          }
        });

        // Menu initialization.
        document.querySelectorAll("#my-menu select").forEach((select) =>
          select.addEventListener("change", () =>
            viewer.update({
              fields: {
                // After initialization, fields can be updated separately.
                [select.id]: select.value
              }
            })
          )
        );
      }
    </script>

    <!-- Non-blocking async script that will call "apvizShowcaseReady" once fully loaded. -->
    <script
      src="https://public.apviz.io/showcases/U0hPVzoxTFVNSVRkNGNx/releases/UkVMUzpHbUd5eHpXNmpV/main.js"
      integrity="sha384-Q0wk+t3O4LoH4UzM4rqhSLXnsDilYprJJ9tdCr6TKgg8hTWcZljFmmQUVo1xu04W"
      defer
      crossorigin="anonymous"
      data-apviz-callback="apvizShowcaseReady"
    ></script>
  </body>
</html>

Marking image

When your product handles web-to-print capabilities such as flocking, printing, you can dynamically display an image on a predefined marking zone using Viewer.update with the markingZones parameter.

The image you want to set must be nested within the markingZones parameter object using the marking zone key you want to target. If you need to update multiple zones at the same time, you can set multiple marking zone keys.

The provided image.color.source value:

  • Supports PNG, JPEG, GIF, SVG, BMP, and ICO image formats.
  • May be any of those JavaScript types:
<!DOCTYPE html>
<html>
  <head>
    <title>Apviz - Demo T-Shirt</title>
  </head>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    #my-image-input { position: absolute; top: 10px; left: 10px; }
  </style>
  <body>
    <!-- Apviz 3D viewer. -->
    <div id="apviz-3d-viewer"></div>

    <!-- Your image input button. -->
    <input id="my-image-input" type="file" accept=".png,.jpg,.jpeg,.bmp,.gif,.ico,.svg">

    <!-- Your custom initialization script. -->
    <script>
      async function apvizShowcaseReady(showcase) {

        // Initialize a 3D viewer and bind it to the <div>.
        const viewer = await showcase.createViewer({
          divId : "apviz-3d-viewer"
        });

        // Initial configuration that MUST explicitly include ALL the fields.
        // This will start displaying 3D.
        await viewer.update({
          fields : {
            "Shirt" : "Fabric Blue",
            "Chest" : "Fabric White"
          }
        });

        // File input event handler.
        document.querySelector("#my-image-input").addEventListener("change", e => {
          viewer.update({
            markingZones : {
              // Targets a specific marking zone via it's key.
              "ChestZone" : {
                image : {
                  color : { source: e.target.files[0] }
                }
              }
            }
          })
        });

      }
    </script>

    <!-- Non-blocking async script that will call "apvizShowcaseReady" once fully loaded. -->
    <script
      src="https://public.apviz.io/showcases/U0hPVzo5cHBEUDBtaEFM/releases/UkVMUzpTVWpTY0RhdXNm/main.js"
      integrity="sha384-/2CFXQjxUdSwUw8dys+n0Yq+kY3ts3TwGZOiJc7R6L6PBq8PIUGGRBE38i1P2g5Q"
      defer
      crossorigin="anonymous"
      data-apviz-callback="apvizShowcaseReady"
    ></script>
  </body>
</html>

The provided image is displayed with the following rules:

  • Image is stretched within the underlying marking zone according to the provided brick UV mapping.
  • RGB(A) are blended in multiply mode with the underlying marking zone material.
Basic marking image samples

More real world samples to better undertand how the marking surface mixes with the image:

Real world marking image samples

ℹ️ To remove the marking image, you can update the viewer with the marking zone key set to null.

🔐 Note that Apviz does not store the provided images on any server by itself.

Marking text

This realistic engraving simulation feature is useful if you have text engraving, stamping, or embossing available for your products whether it is for jewelry, watches, leather goods, shoes, etc.

You can dynamically display a text (with optional embossing/debossing relief) on a predefined marking zone using Viewer.update with the markingZones parameter.

The text you want to set must be nested within the markingZones parameter object using the marking zone key you want to target. If you need to update multiple zones at the same time, you can set multiple marking zone keys.

The text object allows passing extra formatting properties:

Property Description
text.value Single line text from 0 to 128 characters. Note that new line \n and carriage return \r characters are not supported.
text.fontkey Unique font key identifier as defined during showcase setup.

Font resources are automatically segmented so that the browser only needs to download font subsets of unicode ranges that are actually used in the text. This is particularly relevant with large fonts (Japanese, Chinese, etc.) in order to save bandwidth.
text.heightMode How text height is determined:
  • "font": Static text height based on the maximum font height, regardless of the characters.
  • "characters": Dynamic text height that perfectly fits the characters bounding box.
"font" "characters"
Font height mode Characters height mode
text.horizontalAlignment "left", "center" or "right" horizontal alignment.
text.verticalAlignment "top", "middle" or "bottom" vertical alignment.

You can also provide your marking zone key with a text.relief object to handle embossing and debossing (e.g. for engraving, stamping, flocking, etc.):

Property Description
text.relief.direction "up" (embossing) or "down" (debossing) direction.
text.relief.depth Embossing/debossing depth in meters. Value must be greater than 0.
Down Up
Depth behaviour with a down direction Depth behaviour with an up direction
text.relief.angle Slope value in degrees (bevel). Value must be between 1 and 90 inclusive.
Down Up
Angle behaviour with a down direction Angle behaviour with an up direction
An example with a debossed text:
<!DOCTYPE html>
<html>
  <head>
    <title>Apviz - Ring Engraving</title>
  </head>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    #my-text-input { position: absolute; top: 10px; left: 10px; }
  </style>
  <body>
    <!-- Apviz 3D viewer. -->
    <div id="apviz-3d-viewer"></div>

    <!-- Your text input. -->
    <input id="my-text-input" type="text">

    <!-- Your custom initialization script. -->
    <script>
      async function apvizShowcaseReady(showcase) {

        // Initialize a 3D viewer and bind it to the <div>.
        const viewer = await showcase.createViewer({
          divId : "apviz-3d-viewer"
        });

        // Initial configuration that MUST explicitly include ALL the fields.
        // This will start displaying 3D.
        await viewer.update({
          fields : {
            "Gem" : "Diamond",
            "Ring" : "Gold Pink"
          }
        });

        // Text input event handler.
        document.querySelector("#my-text-input").addEventListener("input", e => {
          viewer.update({
            markingZones : {
              // Targets a specific marking zone via it's key.
              "Engraving" : {
                text : {
                  value : e.target.value,
                  fontKey : "Arial",
                  heightMode : "characters", // or "font"
                  horizontalAlignment : "center", // "left" or "right"
                  verticalAlignment : "middle", // "top", or "bottom"
                  relief : {
                    direction : "down", // or "up"
                    depth : 0.000002, // In meters.
                    angle : 80 // Between 1° and 90°.
                  }
                }
              }
            }
          })
        });

      }
    </script>

    <!-- Non-blocking async script that will call "apvizShowcaseReady" once fully loaded. -->
    <script
      src="https://public.apviz.io/showcases/U0hPVzo1ajlKbGQxOFpN/releases/UkVMUzp4d2ZkWUJIZ05k/main.js"
      integrity="sha384-2ISKoDKUTeYNOan0wGIAa8m8l31DCbrJABE78g1Hu8xNnlAXp7UFNhNNMV5s5aPY"
      defer
      crossorigin="anonymous"
      data-apviz-callback="apvizShowcaseReady"
    ></script>
  </body>
</html>

The provided text is displayed with the following rules:

  • Text takes as much height as possible.
  • Text height decreases to fit in width.
  • Texts is displayed using the material associated with the marking zone.

Basic marking text samples

ℹ️ To remove the marking text, you can update the viewer with the marking zone key either set to null or with an empty text.value string.

Progress events

You can use Viewer.addUpdatingListener to subscribe to update progress events. This is specially useful to display a progress bar:

async function apvizShowcaseReady(showcase) {

  // Initialize a 3D viewer and bind it to the <div>.
  const viewer = await showcase.createViewer({
    divId : "apviz-3d-viewer"
  });

  // Handles the progress bar.
  const myLoader = document.getElementById("myLoader");
  await viewer.addUpdatingListener(progress => {
    myLoader.innerHTML = `${progress} %`;
    myLoader.style.display = progress === 100 ? "none" : "block";
  });

  // Set initial configuration.
  // This will display 3D elements accordingly.
  await viewer.update({
    fields : { ...  }
  });

}

The progress event is specially designed not to bloat your UI. Progress event only triggers:

  • When appropriate (HTTP requests > 500ms)
  • With a minimum 500ms resolution

You can unsubscribe your callback from update events using Viewer.removeUpdatingListener.

ℹ️ Note that if you only need to do things before/after 3D has been loaded (without progress), you only have to add asynchronous code before or after Viewer.update.

Dispose

One important aspect in order to improve performance and avoid memory leaks in your application is the disposal of unused 3D viewer. Whenever you create an instance of a 3D viewer, you allocate a certain amount of GPU memory that is necessary for rendering. It's important to highlight that GPU memory is not released automatically. Instead, your application has to use Viewer.dispose() in order to free such resources.

await viewer.dispose();

This is specially useful if you integrate Apviz within a Single-page application (SPA) or if you show/hide 3D multiple times within the same HTML page.

If you use a Multiple-page application (MPA) and the 3D viewer is only showed once, you can skip disposal.

ℹ️ Note that Viewer.dispose() will also unbind the 3D viewer from your <div> making it possibly available for another 3D viewer.

Get fields

If you need to get all configurable field values at runtime you can call the static getFields method:

async function apvizShowcaseReady(showcase) {
  // getFields returns an object with the following structure:
  // {
  //   fields : [
  //    { key: "carat", values: [{ value: "0.5ct" }, { value: "1ct" }] },
  //    { key: "gem", values: [{ value: "diamond" }, { value: "ruby" }] },
  //    { key: "gold", values: [{ value: "yellow" }, { value: "white" }] }
  //   ]
  // }
  const { fields } = await showcase.getFields();
}

ℹ️ This method is intended to ease debugging or fast prototyping. Keep in mind that Apviz is not designed to handle human readable UI menu items.

Get marking zones

If you need to get all configurable marking zones at runtime you can call the static getMarkingZones method:

async function apvizShowcaseReady(showcase) {
  // Returns an object with the following structure:
  // {
  //   markingZones : [
  //    { key: "Engraving", fonts: [{ key: "Arial" }, { key: "EnglischeSchTDemBol" }] }
  //   ]
  // }
  const { markingZones } = await showcase.getMarkingZones();
}

ℹ️ This method is intended to ease debugging or fast prototyping. Keep in mind that Apviz is not designed to handle human readable UI menu items.

Content Security Policy

Content Security Policies are delivered as a header to your users' browser by your web-server and they are used to declare which dynamic resources are allowed to load on your page.

For many websites, this is often as straightforward as declaring that only scripts/styles from your own domain and that of any tools that you are using is allowed, but this can become more involved when complex setups are in play.

If you identify CSP errors on your site, you will need to work with your development team or hosting provider to adjust your CSP settings by adding the following rules:

connect-src https://public.apviz.io;
img-src https://public.apviz.io blob:;
prefetch-src https://public.apviz.io;
script-src https://public.apviz.io;

Compatibility

Apviz 3D configurator is standard HTML and JavaScript making it compatible with all CMS and e-commerce platforms like:

Apviz allows importing 3D bricks from an OBJ file which is supported by a wide variety of 3D/CAD softwares. We have strong support and experience for the following ones:

More features

This was just a quick overview of how to integrate a basic Apviz 3D configurator to a website. But we have many more features available like:

  • Multi viewpoint with camera animation
  • Virtual try-on (augmented reality)
  • Batch packshot
  • Etc.

More documentation is avaible on studio.apviz.io.

Start now!

Request a free access and start building and integrating your own 3D configurators on your website today!