Skip to main content

Add a 3D preview to a theme

In this tutorial you'll render a live 3D preview of a product and update it as the customer chooses a material. You'll attach the Spiff Commerce 3D preview service to a bundle, draw it on a canvas, and select a material variant from a list of buttons.

Before you begin​

You'll need:

1. Install the preview package​

yarn add @spiffcommerce/preview-3d@latest

2. Create the preview service​

Create a single SpiffCommerce3DPreviewService and keep it for the life of the page. Creating one per render is expensive, and a preview service can only be associated with one bundle at a time.

import { SpiffCommerce3DPreviewService } from "@spiffcommerce/preview-3d";

const previewService = new SpiffCommerce3DPreviewService();

3. Add a canvas​

The preview draws into a canvas element. Give it a size, because the canvas is what determines the size of the preview.

<div style="position: relative; width: 100%; height: 480px;">
<canvas id="preview" style="position: absolute; width: 100%; height: 100%; outline: none;"></canvas>
</div>
<div id="materials"></div>

4. Add a workflow experience to your bundle​

Request a workflow experience for the product and add it to the bundle. Always use the list-based functions, even for one item, and await both calls.

const experiences = await client.getWorkflowExperiences([
{
type: "integration",
integrationProductId: "<Your integration product ID>",
workflowId: "<Your workflow ID>",
},
]);
await bundle.addWorkflowExperiences(experiences);
const workflowExperience = experiences[0];

5. Associate the bundle with the preview service​

Call setPreviewService on the bundle. Every workflow experience in the bundle is injected into the preview service, and experiences you add or remove later are injected and ejected for you.

await bundle.setPreviewService(previewService);

6. Register the canvas and wait for the model​

Register the canvas with the preview service. Nothing is drawn until a view is registered. Then wait for both the scene and the model to finish loading before showing the preview.

const canvas = document.getElementById("preview") as HTMLCanvasElement;
previewService.registerView(canvas);

await Promise.all([
previewService.getInitializationPromise(),
workflowExperience.getWorkflowManager().getModelContainer()?.getInitializationPromise(),
]);

// Frame the model once everything has loaded.
await previewService.animateToLastCameraFocus();

You should now see the product rendered on the canvas, and be able to orbit around it.

7. Let the customer pick a material​

A material step lets the customer choose between texture assets. Find the material steps with getStepsByType, read the variants the customer can choose from, and call selectVariant when one is clicked. The preview updates by itself, because the workflow experience is already attached to it.

import { StepType } from "@spiffcommerce/core";

const materialStep = workflowExperience.getStepsByType(StepType.Material)[0];
const variants = await materialStep.getAvailableVariants();

const container = document.getElementById("materials")!;
variants.forEach((variant) => {
const button = document.createElement("button");
button.textContent = variant.getName();
button.addEventListener("click", async () => {
await materialStep.selectVariant(variant);
});
container.appendChild(button);
});

Click a button and the material on the model changes. A model step works the same way: get the steps with StepType.Model, then call selectVariant.

note

Only render steps that are currently active. Conditions in the workflow can show and hide steps as the customer makes choices. See Getting Active Steps.

8. Clean up​

When your experience closes, unregister the canvas and eject the workflow experiences from the preview service.

previewService.unregisterView(canvas);
await bundle.setPreviewService();

Next steps​