Building a Custom UI

Your Share link and embed give shoppers the built-in configurator interface. If you want your own interface instead — matching your storefront exactly, in your own framework — you can keep Simplio3D’s 3D renderer and replace only the controls around it.

Which route is yours?

Embed the Share view

Paste the iframe from the Share dialog. Fastest, and you get everything — but the interface is ours. Style it with Project Settings → Branding.

Clean viewer embed

Add ?ui=viewer to your Share URL. You get the 3D viewport and the floating tools with all your settings already applied; you add the option buttons, price and cart. Display-only for now.

Your UI, our renderer

Install @simplio3d/viewer. You build every control; we draw the product exactly as it looks in Preview. This page.

Full walkthrough →

Write your own renderer

Read the API and draw the scene yourself. Total control, and you take on every rendering rule the payload does not describe.

The simplest route: the clean viewer embed

Before installing anything, check whether this is enough. Adding ?ui=viewer to your Share URL renders the 3D viewport and the floating tools with every setting you already configured — lighting, camera, branding, watermark, loading animation, AR, the pinned language — and hides the options sidebar, the price and the buttons, so you can add your own around it. Copy it from Project → Share → Embed.

<iframe src="https://YOUR_APP_DOMAIN/share/PROJECT_ID/SHARE_TOKEN?ui=viewer" width="100%" height="600" frameborder="0" allowfullscreen allow="accelerometer; autoplay; camera; clipboard-write; encrypted-media; gyroscope; picture-in-picture; xr-spatial-tracking" ></iframe> <!-- Your own UI, on your page --> <div id="my-options"></div> <div id="my-price"></div> <button id="my-cart">Add to cart</button>

Today the clean viewer embed is display-only. It shows the product with your settings and working floating tools, but your buttons cannot change a selection in it yet — the two-way messaging bridge is still to come. If you need your controls to drive the 3D now, use @simplio3d/viewer below, which trades the floating tools and most project settings for a real API.

What you need

Only two values, both from your project’s Share tab: the project ID and the share token in the share URL. Turn sharing on first. There is no API key to create and nothing to keep secret — the same values are already public in your embed code.

Never put an API token in a web page or an app binary. It works across every project on your account, it stops working if billing lapses, and it is rotated automatically 90 days after that. The share token is the credential designed to be public.

A complete example

This is a working page — no build step, no npm. Replace the two values and open it.

The package is not on npm yet, so the jsDelivr URL returns 404. Copy packages/viewer/dist/simplio3d-viewer.standalone.js next to your HTML file and import it by relative path, as shown below. Everything after that import line works exactly as written. Serve the page over http:// — ES modules and fetch are blocked on file://.

<div id="stage" style="height: 70vh"></div> <div id="options"></div> <script type="module"> // Vendored next to this file. Once the package ships to npm this becomes: // https://cdn.jsdelivr.net/npm/@simplio3d/viewer/dist/simplio3d-viewer.standalone.js import { createViewer } from './simplio3d-viewer.standalone.js'; const viewer = await createViewer({ el: '#stage', projectId: 'YOUR_PROJECT_ID', shareToken: 'YOUR_SHARE_TOKEN', }); // Build your own controls from the project's option blocks. function renderOptions() { const ui = document.getElementById('options'); ui.innerHTML = ''; const state = viewer.getState(); for (const block of viewer.blocks) { // Respect conditional logic — a hidden block must not be shown. if (viewer.visibility[block.id] === false) continue; for (const variant of block.dropdownVariants ?? []) { const button = document.createElement('button'); button.textContent = variant.label; button.disabled = state[block.id] === variant.value; button.onclick = () => viewer.select(block.id, variant.value); ui.append(button); } } } renderOptions(); // Re-render whenever a rule shows or hides a block. viewer.on('applied', renderOptions); </script>

Things worth knowing

  • The product looks exactly as it does in Preview. Lighting, materials, reflections and camera framing all come from your project settings — you are not approximating them.
  • Conditional logic still applies. viewer.visibility tells you which blocks a rule has hidden, so your UI stays in step with the 3D.
  • Render your controls in the order viewer.blocks gives them. That is the order you authored in the editor.
  • You can take a screenshot. await viewer.snapshot() returns a high-resolution image with a transparent background — useful for attaching to your own quote or order.
  • Pricing stays on the server. The viewer does not price; send the selections to the pricing endpoint so the total is always authoritative.
  • Modular projects render their base scene, but shopper drag-and-drop module placement is not part of this package yet — use the Share view or embed for those.

If the configurator says it is unavailable

The share endpoint returns 402 when the project owner’s subscription has lapsed, and every Share link and embed goes offline at the same time. Show a neutral message and reactivate the plan in Dashboard → Billing — nothing needs to be re-published afterwards.

Next steps

Ready to build? The Headless Integration Walkthrough takes this from a snippet to a shipped page — install, wiring your controls, failure handling, and the traps that break silently.

Full API reference, both build variants, the import-map setup and the three.js escape hatch are in SDK → Headless Renderer. For a native app, see Mobile & Native Apps.

More in Integrations