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-3d@latest
Associating a bundle with the preview service
Once you have your reference to the preview service, associate it with your Bundle by calling setPreviewService. Every workflow experience in the bundle is injected into the preview service, and experiences you add to or remove from the bundle later are injected and ejected automatically. A preview service can only be associated with one bundle at a time.
Calling setPreviewService with no arguments ejects every workflow experience from the preview service.
import { SpiffCommerce3DPreviewService } from "@spiffcommerce/preview-3d";
// Construct the preview service, this should generally be singleton.
const previewService = new SpiffCommerce3DPreviewService();
// Inject every workflow experience in the bundle into the preview service.
await bundle.setPreviewService(previewService);
// Register the canvas element to render into. You must register a view before the preview can be used.
previewService.registerView(canvas);
// 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...
// Stop rendering to the canvas, for example when your component unmounts.
previewService.unregisterView(canvas);
// Eject all workflow experiences from the preview service.
await bundle.setPreviewService();
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.
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);