Skip to content

Building a Product Customiser

Hey there! 👋
In this tutorial we'll build a simple product configurator — let users pick colours, add text, and switch between material variants. It's the kind of thing you'd see in a sneaker builder or merch customiser.

We'll be using the Customiser Plugin, which adds a handful of powerful methods to the viewer.

This tutorial builds off the Basic implementation tutorial.

Let's build!


1. Load the Plugin

Start with the basic viewer boilerplate, but this time we also load the Customiser plugin script and tell the viewer to use it via data-270-plugins:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Product Customiser</title>
  <style>
    body {
      font-family: sans-serif;
    }
    main {
      display: flex;
      flex-wrap: wrap;
      gap: 1rem;
    }
    #viewer-container {
      width: 500px;
      height: 500px;
    }
    .customiser {
      max-width: 500px;
      margin-top: 1rem;
      display: flex;
      flex-direction: column;
      gap: .75rem;
    }
    .swatches {
      display: flex;
      gap: .5rem;
    }
    .swatches button {
      width: 36px;
      height: 36px;
      border: 2px solid #ccc;
      border-radius: 4px;
      cursor: pointer;
    }
    .customiser label {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 1rem;
    }
    .customiser input[type="text"] {
      padding: .3rem .5rem;
      font-size: .9rem;
    }
  </style>
</head>
<body>
  <h1>Product Customiser</h1>
  <main>
    <div id="viewer-container">
      <div class="js-270viewer"
           data-270-model="lunchbox"
           data-270-background="#eeeeee"
           data-270-plugins="customiser">
      </div>
    </div>

    <div class="customiser">
      <div>
        <strong>Colour</strong>
        <div class="swatches">
          <button style="background:#e74c3c" data-color="#e74c3c"></button>
          <button style="background:#3498db" data-color="#3498db"></button>
          <button style="background:#2ecc71" data-color="#2ecc71"></button>
          <button style="background:#f1c40f" data-color="#f1c40f"></button>
          <button style="background:#1a1a1a" data-color="#1a1a1a"></button>
          <button style="background:#ffffff" data-color="#ffffff"></button>
        </div>
      </div>

      <label>Text
        <input type="text" id="custom-text" placeholder="Your name here" maxlength="20" />
      </label>
    </div>
  </main>

  <script>window.TSDAPIKEY = 'rest-of-the-owl';</script>
  <script src="https://api.270degrees.nl/api/script/latest/viewer.js"></script>
  <script src="https://api.270degrees.nl/api/script/latest/customiser.js"></script>

  <script>
    // We'll fill this in next
  </script>
</body>
</html>

Notice:

  • We load customiser.js after viewer.js
  • We pass data-270-plugins="customiser" on the viewer element to attach it automatically

Use the el.getObjectNames() method to see the available objects to pass in your methods.
We'll use the objects trommel and text in this example.

Important: Wait for the Model to Load

Before we start changing colours or adding text, the model and plugin need to be fully loaded. We'll use onLoadComplete via TSDViewer.create() to make sure everything is ready:

<script>
  const $viewer = document.querySelector('.js-270viewer');

  TSDViewer.create($viewer, {
    onLoadComplete: () => {
      // The model and Customiser plugin are ready.
      // We'll add our controls here.
    }
  });
</script>

Everything from here on goes inside that onLoadComplete callback.


2. Add Colour Swatches

Now let's wire up those colour buttons using setColor:

const targetObject = 'trommel';

document.querySelectorAll('.swatches button').forEach(btn => {
  btn.addEventListener('click', () => {
    $viewer.setColor({
      name: targetObject,
      color: btn.dataset.color
    });
  });
});

Click a swatch and the object changes colour on the spot. The method accepts any valid CSS colour — hex, rgb(), or named colours like red.


3. Add Custom Text

Let's let users stamp their name on the product using setText:

document.querySelector('#custom-text').addEventListener('input', (ev) => {
  $viewer.setText({
    name: 'text',
    text: ev.target.value,
    color: 'grey',
    size: 72
  });
});

Type in the text field and watch it appear on the model in real time.

You can tweak font, fontStyle, fontWeight, and size — check the full setText reference for all options.

If you want to clear the text, use removeText: $viewer.removeText({ name: targetObject }).


4. End Result

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Product Customiser</title>
  <style>
    body {
      font-family: sans-serif;
    }
    main {
      display: flex;
      flex-wrap: wrap;
      gap: 1rem;
    }
    #viewer-container {
      width: 500px;
      height: 500px;
    }
    .customiser {
      max-width: 500px;
      margin-top: 1rem;
      display: flex;
      flex-direction: column;
      gap: .75rem;
    }
    .swatches {
      display: flex;
      gap: .5rem;
    }
    .swatches button {
      width: 36px;
      height: 36px;
      border: 2px solid #ccc;
      border-radius: 4px;
      cursor: pointer;
    }
    .customiser label {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 1rem;
    }
    .customiser input[type="text"] {
      padding: .3rem .5rem;
      font-size: .9rem;
    }
  </style>
</head>
<body>
  <h1>Product Customiser</h1>

  <main>
    <div id="viewer-container">
      <div class="js-270viewer"
           data-270-model="lunchbox"
           data-270-background="#eeeeee"
           data-270-plugins="customiser">
      </div>
    </div>

    <div class="customiser">
      <div>
        <strong>Colour</strong>
        <div class="swatches">
          <button style="background:#e74c3c" data-color="#e74c3c"></button>
          <button style="background:#3498db" data-color="#3498db"></button>
          <button style="background:#2ecc71" data-color="#2ecc71"></button>
          <button style="background:#f1c40f" data-color="#f1c40f"></button>
          <button style="background:#1a1a1a" data-color="#1a1a1a"></button>
          <button style="background:#ffffff" data-color="#ffffff"></button>
        </div>
      </div>

      <label>Text
        <input type="text" id="custom-text" placeholder="Your name here" maxlength="20" />
      </label>
    </div>
  </main>

  <script>window.TSDAPIKEY = 'rest-of-the-owl';</script>
  <script src="https://api.270degrees.nl/api/script/latest/viewer.js"></script>
  <script src="https://api.270degrees.nl/api/script/latest/customiser.js"></script>

  <script>
    const $viewer = document.querySelector('.js-270viewer');

    TSDViewer.create($viewer, {
      onLoadComplete: () => {
        const targetObject = 'trommel';

        // Colour swatches
        document.querySelectorAll('.swatches button').forEach(btn => {
          btn.addEventListener('click', () => {
            $viewer.setColor({
              name: targetObject,
              color: btn.dataset.color
            });
          });
        });

        // Custom text
        document.querySelector('#custom-text').addEventListener('input', (ev) => {
          $viewer.setText({
            name: 'text',
            text: ev.target.value,
            color: 'grey',
            size: 72
          });
        });
      }
    });
  </script>
</body>
</html>

What's Next?

You've got a working product customiser! Users can pick colours and add their own text right on the 3D model.
A few ideas to take it further:

💬 Ask AI