Skip to main content

3D Product Previews

The 3D product preview is a feature that allows you to display a 3D model of a product in your application. This is a great way to give your customers a better understanding of the product they are purchasing. The 3D preview interface has been designed to be configurable and customizable to fit your needs. We provide a 3D solution out of the box, but you can also use your own 3D solution. As long as your solution adheres to the interface that we have built any 3D solution suitable for the web can be plugged into a workflow experience. Read further to learn more about the interface and how you use it.

Using the Spiff Commerce 3D solution

Our in-house solution for 3D is published as a convenient npm package that you can plug straight into our platform. This solution adheres to the ThreeDPreviewService interface just as any bespoke solution would. The only difference being that you don't have to build it yourself.

yarn add @spiffcommerce/preview@latest

Injecting a Workflow Experience into the preview service

Once you have your reference to the preview service, you can also inject an existing workflow experience into the preview service. This is useful if you have a workflow experience that you have already loaded and want to use the preview service with it. Workflow experiences can only be injected into one preview service at a time. This can be achieved by calling injectIntoPreviewService on the workflow manager of the workflow experience.

When you're done with a particular workflow experience you can remove it from the preview service by calling the ejectFromPreviewService method.

import { SpiffCommerce3DPreviewService } from "@spiffcommerce/preview";
// COnstruct the preview service, this should generally be singleton.
const previewService = new SpiffCommerce3DPreviewService();
// Inject a workflow experience into the preview service.
await workflowExperience.getWorkflowManager().injectIntoPreviewService(previewService);

// To know when to render there are two components to await. The preview load and the model load.
await Promise.all([
previewService.getInitializationPromise(),
workflowExperience.getWorkflowManager().getModelContainer()?.getInitializationPromise(),
]);
// Once the load is complete you can frame and animate to the desired position.
previewService.animateToLastCameraFocus();

// Later...
// Eject a workflow experience from the preview service.
workflowExperience.getWorkflowManager().ejectFromPreviewService();

Model Animations

In order to play animations on a loaded model, you'll need to get a reference to a ModelContainer instance. There are a few ways you can do this:

const modelContainer = workflowExperience.getWorkflowManager().getModelContainer();

You can use the getAnimations() function on a loaded ModelContainer to retrieve a list of available animations.

note

This function will return an empty array if the model has not been loaded yet.

interface ModelAnimation {
name: string;
from: number;
to: number;
loop: boolean;
}
// If you pass true to this function, the returned array will include animations for all loaded variants.
const animations: ModelAnimation[] = modelContainer.getAnimations(false);

You can use the executeAnimation() function on a loaded ModelContainer to play an animation. If you are already aware of the animation parameters prior to the model loading, you can safely call this function and the animation will be played once the model has loaded.

All fields on the input object are optional.

modelContainer.executeAnimation({
name: "animationName", // If this is not provided, all animations will be played
from: 0, // Defaults to the first frame of the animation
to: 1, // Defaults to the end of the animation
loop: true, // Defaults to the animation's loop property
});

Enabling material highlighting

To enable material highlighting, and event hooks for when a material is hovered over, you can pass the following options to the preview service:

const previewService = new SpiffCommerce3DPreviewService({
highlightOnMaterialHover: true,
highlightColor: "#ff0000", // Defaults to #fafafa
});

Once you have retrieved a reference to a modelContainer, you can then use the registerMaterialSelectedCallback and unregisterMaterialSelectedCallback functions to register callbacks for when a material is hovered over.

const materialSelectedCallback = (materialHandle: MaterialHandle) => {
const {
id, // Raw material id.
name, // Human readable material name.
} = materialHandle;
// Do something with the material handle.
};

modelContainer.registerMaterialSelectedCallback(materialSelectedCallback);
// Later on...
modelContainer.unregisterMaterialSelectedCallback(materialSelectedCallback);