# iJewel3D Documentation (Full) > Complete developer documentation for iJewel3D. Source: https://developer.ijewel3d.com --- # What is iJewel? ![iJewel 3D](../assets/images/intro_banner.webp) iJewel3D is a suite of tools for creating, rendering, and hosting 3D models of jewelry and fashion accessories. It is designed to be easy to use and to provide high-quality results in realtime across all devices and platforms. iJewel3D includes a fully customizable web SDK for rendering 3D models in the browser, a cloud service and APIs for model hosting and management, augmented reality virtual try-on toolkit for interactive shopping experiences, tools for quick batch rendering and a viewer and editor for 3D models that can be embedded in websites or apps. Check out https://ijewel3d.com for more details and our complete suite of products and services. ::: tip You can now [Book a Free Demo](https://ijewel3d.zohobookings.in/#/209816000000031082) for any of iJewel products. ::: This portal is aimed at developers and designers who want to integrate iJewel3D into their projects. It provides detailed documentation on how to use the SDK, APIs, and tools, along with examples and best practices for creating interactive 3D experiences for jewelry and fashion accessories. Read on to learn more about the features and capabilities of iJewel3D. ::: tip Email us at [dev@ijewel3d.com](mailto:dev@ijewel3d.com) to quickly get answers to any technical queries, or get connected for support. ::: ## Rendering ![iJewel Photo-realistic Rendering](../assets/images/ijewel_rendering.webp) All the iJewel3D tools and services are built on top of a high-performance rendering engine that is optimized for jewelry and fashion accessories. The engine is based on WebGL(threejs/threepipe) and provides realistic lighting, reflections, shadows and post-processing effects to create a lifelike experience for the user. It is designed to be fast and efficient, so that even complex models can be rendered in realtime on any device. For Diamonds and Gemstones, we use custom pipelines and algorithms to optimise the models and simulate the refraction and dispersion of light through the stones(All at runtime). This creates a realistic and accurate representation of the stones. Along with careful attention to the environment maps, materials and textures, this ensures that the jewelry looks as close to real life as possible. For metals like Gold, Silver, Platinum, etc, we use fast PBR rendering with tonemapping and LUT color correction to create a realistic and accurate representation of the metals. Out playground and editor provides carefully designed material presets for precious metals, to get the best results with just a few clicks. In most cases, it won't be required to preprocess the 3d models using any special software, as the SDK can handle most of the rendering and optimisation at runtime. PBR materials from any software can be used directly in iJewel, and the SDK provides a way to create custom materials and shaders for advanced use-cases. Using the SDK, it's possible to render 100s of diamonds in at once, even on mobile devices, while maintaining a smooth and interactive experience. This makes it easy to create interactive shopping experiences that allow customers to view and customize jewelry in realtime. While the rendering engine is based on three.js for web browsers, we have several ports custom custom shaders that can be used to elevate the jewelery rendering capabilities for engines like [Unity](https://unity.com/), [PlayCanvas](https://playcanvas.com/), and more. > The core of the Web SDK is completely open source as [Threepipe](https://threepipe.org), and can be used for free in any project(even commercially). iJewel SDK provides several modules and plugins over threepipe for luxury products, and can be licensed for commercial use. ## Configurators ![Interactive E-commerce Configurators](../assets/images/configurator_banner.webp) One of the key features of iJewel3D is the ability to create custom configurators for jewelry and fashion accessories. Configurators allow customers to customize the design of a piece of jewelry by selecting different options for the metal, stones, engraving and other details. The configurator then generates a 3D model of the customized piece in realtime, allowing the customer to see exactly what the finished product will look like. The iJewel3D SDK includes tools for creating and embedding custom configurators in websites and apps. The models and configurators can be created using both code and no-code methods, making it easy for both designers and developers to experiment, prototype and automate the creation of new experiences. Along with object and material configurators, ijewel editor components provide a way to create custom UIs for editing and manipulating 3D models. These components can be used to create custom workflows for designers, customers and sales teams to interact with the models and create new designs. ![iJewel Editor](../assets/images/mini_editor.webp) ## Hosting ![Hosting 3D Assets](../assets/images/hosting_generic_banner.webp) iJewel SDK is an open platform which is fully configurable. It can be added to projects using NPM packages or directly from the our CDN. The SDK is designed to be easy to integrate with existing websites and apps, and can be completely hosted on your own servers or any cloud service. For web rendering, since it's frontend only, it can be hosted on any static hosting service like AWS S3, GCS, Github Pages, etc. The 3D models and assets used by the SDK can be hosted on any server or cloud service, and are loaded dynamically by the SDK as needed by URLs. We recommend using a block storage service like Amazon S3 or Google Cloud Storage to host the models, connected to a CDN as this provides fast and reliable access to the files. ::: info HTTP Protocol Note that HTTP(S) is required for loading the models on websites, so the server must support this protocol. ::: ::: warning When using AWS S3, or GCS for hosting the models, check the egress costs for the region where the models are being loaded. Cloudflare R2 can also be considered to reduce the costs, but it might have its own limitations. ::: It is also possible to host the models directly in the git repository of the project, and use the SDK to load the models by relative paths. While this is useful for projects with just a couple models or for quick prototyping, is not recommended for apps with many models. ## Hosting on iJewel Drive ![iJewel Drive](../assets/images/hosting_on_drive.webp) iJewel Drive, our cloud service, provides a simple way to upload, manage and share 3D models and assets. It works similar to other content management systems, like Dropbox or Google Drive, but is optimized for 3D models. Models can be uploaded in bulk, previewed in realtime, and shared with team members or customers. Along with bundled iJewel Playground and Editor, the models can be edited, configured and finally embedded on the website or app. ## License and Pricing Using the iJewel SDK, TryOn, Drive, all included assets, templates, and plugins in commercial projects requires a license. We offer licenses for individual products, as well as bundles for multiple products. License Keys for SDK, BatchX, TryOn can be purchased directly through [iJewel License Portal](https://license.ijewel3d.com/) Email us at [sales@ijewel3d.com](mailto:sales@ijewel3d.com) or [book a call](https://ijewel3d.zohobookings.in/#/209816000000031082) for bulk licenses, discounts, and to get access to complete pricing documents. Get more details and learn about license terms for different products on the [License Page](./license) --- # iJewel Products iJewel3D is a suite of tools for creating, rendering, and hosting 3D models of jewelry and fashion accessories. It is designed to be easy to use and to provide high-quality results in realtime across all devices and platforms. ![iJewel Products](../assets/images/ijewel_products_hero.webp) Check out the different sections below to learn about developing state of the art applications with iJewel3D products. ## iJewel Viewer ![iJewel Viewer and Editor](../assets/images/mini_viewer_editor.webp) iJewel Viewer is a standalone web component that allows you to easily embed and render 3D models directly within your web pages. It includes a built-in material configurator and quick 3d actions. It's possible to create a ready-to-use viewer/configurator for your e-commerce website with just a few lines of code. Check out the [iJewel Viewer documentation](../viewer/introduction), or [contact us](mailto:dev@ijewel3d.com) to learn more. The viewer comes with a compatible editor that can be used to create configurators, setup model lighting and other settings etc. The iJewel Editor is also fully embeddable and can be used on your websites. For advanced usage of embedding 3d models, rendering plugins and full playground customisation, checkout the [full Web SDK below](#web-3d-sdk). ## iJewel Drive ![iJewel Drive.webp](../assets/images/drive_hero.webp) iJewel Drive is a cloud service for hosting, managing and sharing 3D jewelery models. It allows you to upload, catalog, and collaborate on 3D models with your team. The files can then be shared with retailers, customers as links or embedded on custom websites or apps using the iJewel Viewer. Check out the [iJewel Drive documentation](../viewer/connect-to-drive), or [contact us](mailto:dev@ijewel3d.com) to learn more. ::: tip If you are looking for uploading and sharing jewelery 3d models as an individual or a small team, check out [iJewel Design](https://ijewel.design) to quickly create your personal 3d portfolio and connect with fellow designers and jewelers. ::: ## iJewel Playground ![iJewel Playground](../assets/images/playground_banner.webp) [iJewel3D Playground](https://playground.ijewel3d.com) is a free to use online tool for editing, configuring and rendering 3D models of jewelry and fashion accessories. It includes a library of materials, environment maps, and presets to quickly create realistic renders of your models. Playground serves as a companion tool to the iJewel Viewer and Editor, and can be used to quickly create and test new models and configurations. ::: info License Using the presets and outputs generated from the playground can be used commercially, but it requires a license to any other iJewel3D product. ::: ## iJewel BatchX ![BatchX](../assets/images/batchx_banner.webp) BatchX is a downloadable app for Windows and MacOS, to quickly render images and models 3D models in bulk, applying various combinations of materials, camera views, models etc. All rendering happens on your local machine, using state of the art rendering algorithms to reduce render-times by 100-500x. With BatchX, it's possible to render a `2048x2048` size, `10 sec` turn-table video in under `20 sec` on simple laptop. With a GPU desktop, it's realtime. You can try BatchX with a free 30 Day trial on every device (with no credit card or commitments) - [iJewel BatchX](https://batchx.ijewel3d.com/). ## iJewel TryOn AR ![TryOn](../assets/images/tryon_banner.webp) iJewel TryOn AR (VTO) is a toolkit for creating augmented reality virtual try-on experiences for jewelry and fashion accessories. It allows customers to see how a piece of jewelry looks on them in realtime using their smartphone or tablet. TryOn works across iOS, Android, MacOS and Windows, with real-time 3d rendering, depth-estimation and hand, face tracking for accurate placement of the jewelry on the user. ## Web 3D SDK ![iJewel3D SDK](../assets/images/sdk_banner_dark.webp) iJewel provides a full frontend SDK(built on [threepipe](https://threepipe.org) and [three.js](https://threejs.org)) that can be used to create advanced interactive applications for custom use-cases like - Advanced configurators with custom UIs - Deep Integrations with e-commerce platforms like shopify, magento etc - Creating Interactive 3D walk-through and tours - Custom 3D rendering pipelines and shaders - 3D Interactive Scrollable Landing pages (like Apple) - Advanced customisations of lighting, materials and environment maps. ## Unity 3D Diamond Rendering Module for Unity for custom apps and websites. [Contact us](mailto:dev@ijewel3d.com) to learn more. ## PlayCanvas Diamond Rendering Module for PlayCanvas for custom apps and websites. [Contact us](mailto:dev@ijewel3d.com) to learn more. ## iJewel Design ![iJewel Design](../assets/images/ijewel_design_info.webp) [iJewel Design](https://ijewel.design) is a platform for designers to showcase their 3D models, connect with other designers and jewelers, and get feedback on their designs. Its a great place to get started with 3D rendering and showcase, and to learn about the latest trends in the industry. iJewel Design is completely start and connect with other designers and jewelers. ## HDR Editor ![HDR Editor](../assets/images/hdr_editor_banner.webp) We provide a free to use HDR Editor for quickly creating and editing HDR environment maps for your 3D models and web rendering. Check out live in our editor how light maps interact with your diamonds and gemstones to create accurate cuts and realistic reflections and refractions. [Know more](https://hdrmap.com/), or just get started at [HDR Editor](https://editor.hdrmap.com/). --- # License and Pricing Using the iJewel SDK, TryOn, Drive, all included assets, templates, and plugins in commercial projects requires a license. We offer licenses for individual products, as well as bundles for multiple products. ::: details Contact Email us at [sales@ijewel3d.com](mailto:sales@ijewel3d.com) or [book a call](https://ijewel3d.zohobookings.in/#/209816000000031082) to get access to any pricing document. ::: ::: tip License Keys for SDK, BatchX, TryOn can now be purchased directly through [iJewel License Portal](https://license.ijewel3d.com/) ::: ## SDK ![SDK](../assets/images/sdk_banner.webp) The SDK is available under a per-project(and per-domain) license, which allows you to use the SDK in a single project and production domain. One license can only be used by one organization or individual, and cannot be transferred to another party. By default, the license is locked to one production domain (and unlimited development) but can be extended to multiple domains depending on requirements. Checkout the [pricing page](https://webgi.dev/pricing#jewellery-rendering-plugins) for more details. ## TryOn ![TryOn](../assets/images/tryon_banner.webp) iJewel AR TryOn is is a separate package along with the SDK, and requires a separate license. It allows you to use the TryOn toolkit in a single project and production domain. The license is locked to one production domain (and unlimited development) but can be extended to multiple domains depending on requirements. ::: info With the SDK and TryOn license, there are no restrictions on the number or size of models that can be used. Anything that's technically possible with the SDK can be done with the license. (there are exceptions like reverse-engineering, check the terms). ::: ## Drive ![Drive](../assets/images/drive_banner_ui.webp) For products that are hosted or managed by iJewel3D, like Drive, that provide embeddable configurators/viewers, the license is already included in the subscription. The subscription is based on the number of models, storage, and usage of the service, and can be upgraded or downgraded at any time. All the assets like models, materials, scene settings(other than those provided as templates by iJewel3d) etc are owned by the user, and can be downloaded and used in other projects. No license is required to use the files generated/exported with the tools. ::: info We do not use AI to generate images/videos or user-provided data to train any AI models. ::: ## Editor, Playground, BatchX ![TryOn](../assets/images/editor_playground_concept.webp) iJewel Editor and Playground are free to use(and openly accessible) tools for designers and developers. They can be used for any purpose for free. BatchX is a paid app for MacOS and Windows, with a free 30 day trial and yearly license. The assets(3D models, environment maps, materials, presets etc), and other resources provided by iJewel3D in the editor are not free to use, and require a license or subscription to any iJewel3d product for commercial use. This also applies to any images, videos, assets exported with the editor/playground/batchx-trial that use iJewel3D assets/presets. Any images, videos, other assets exported with the editor/playground/batchx-trial can be used commercially if none of the iJewel3D assets are used while creating the content. ## iJewel Design (ijewel.design) ![iJewel Design](../assets/images/ijewel_design_banner.webp) iJewel Design is a separate platform for designers and jewelers to create and share 3D models. It is free to use for individuals and small teams, and does not require any license. Checkout the pricing plans on [ijewel.design/pricing](https://ijewel.design/pricing) for more details. Any files uploaded by you on ijewel.design should belong to you and will be shown under your profile. It's not allowed to upload any files that you don't own or have the rights to use. Any images, videos exported of these files from ijewel.design can be used commercially without any restrictions. --- # YouTube Tutorials Welcome! Here you'll find tutorials categorized by product for easy navigation. --- ## iJewel3D - ▶ [Intro | Professional 3D Jewelry Visualization & Sharing](https://youtu.be/r3VK5tX14VA?si=7pfVBeWZn9keaevd) - ▶ [How to Upload 3D Jewelry Models](https://youtu.be/Fsdk1LirFDY?si=lgI-KRPQeZfMPe_i) - ▶ [Editor Tutorial | Materials, Lighting, Scenes & Sharing](https://youtu.be/_r-LYQCx8fw?si=KWutTm9xtolR2_IC) ## Playground - ▶ [QuickStart](https://www.youtube.com/watch?v=P0R38Y2S-b0) - ▶ [Resolution & Export](https://www.youtube.com/watch?v=FAqfTMBAaBA) - ▶ [Export and import materials](https://www.youtube.com/watch?v=59dNYczASqU) - ▶ [Fixing brushed textures](https://www.youtube.com/watch?v=4zqofmJTq64) - ▶ [How to Create Custom Materials](https://youtu.be/VJOqR2cY8lc?si=4N14kUE5Itzfo5vF) - ▶ [Fixing Diamond Rendering Issues](https://www.youtube.com/watch?v=UT4p-IFrbjI) - ▶ [Video Rendering](https://www.youtube.com/watch?v=O1HE_Tu3RZw) - ▶ [Creating a camera path](https://www.youtube.com/watch?v=9-e0PZaU4ls) - ▶ [Perfect 360° Turntable in 2 mins](https://www.youtube.com/watch?v=304Hzog-7bg) - ▶ [Instant soft edges - SSBevel](https://www.youtube.com/watch?v=4VxhYAJTJQk) - ▶ [Auto Pose Ring in a Laid Position](https://www.youtube.com/watch?v=tTYhANCgepo) - ▶ [Changing background and ground color](https://www.youtube.com/watch?v=q989o_dq7yo) - ▶ [How to make pure white and transparent background](https://www.youtube.com/watch?v=GCJIOmcEaPo) - ▶ [How to Create Custom Shadows](https://youtu.be/269LnNYZDh0?si=WSeTh83g1kXecN6Z) - ▶ [VJSON Scene Setup](https://www.youtube.com/watch?v=WqCdMken924) - ▶ [Interactive 3D Configurator](https://www.youtube.com/watch?v=8sfDdlF4F9I) - ▶ [Transfer Your Configurator](https://www.youtube.com/watch?v=c_cph8q_vA8) - ▶ [How to Create and Apply Custom LUTs](https://youtu.be/2_AlgEg_Q74?si=5kAPjwGPiJfF4Lc3) - ▶ [How to Create Custom Engraving](https://youtu.be/SIZOhaCpqKk?si=RnHImVWzJG_SlaDj) - ▶ [UV Mapping for Engraving](https://youtu.be/9-tDRhu4HK0?si=WG34Dd81w-nGflQ4) ## Drive - ▶ [QuickStart](https://www.youtube.com/watch?v=W-jdD5n3pOU) - ▶ [Complete Tutorial](https://youtu.be/JEqP6jij0h8?si=GgKarfaeu8C_ZxC9) ## Design - ▶ [QuickStart](https://www.youtube.com/watch?v=9xpptNYtgzs) - ▶ [3 Ways to Secure Your 3D Projects](https://www.youtube.com/watch?v=t7-NxhL6z-w) - ▶ [AR Try-On](https://www.youtube.com/watch?v=bZ5ZQQyvPoI) - ▶ [Project Visibility](https://www.youtube.com/watch?v=ZTYrM2BaqH8) - ▶ [How to Export Images](https://youtu.be/v059v9oyW20?si=r0NqJRH0lr_NbyaO) - ▶ [AR Try-On](https://youtu.be/bZ5ZQQyvPoI?si=sMaIcVFesutNTuZZ) ## BatchX - ▶ [BatchX Tutorial 1 | introduction](https://youtu.be/o1TSttCXonI?si=Uefx3ztlj3IyaX4q) - ▶ [BatchX Tutorial 2 | Organizing Models, Applying Materials & Export Settings](https://youtu.be/i1ikwtPEPrA?si=AmbZbWowrKj0BBjJ) - ▶ [BatchX Tutorial 3 | Scene Settings & Smart Naming](https://youtu.be/svb9uetnzJE?si=nyMwjQyNGwXKGNSk) ## Tutorial Animation - ▶ [How to Create Beautiful Pendant Swing Animation | Blender + iJewel Playground Tutorial](https://youtu.be/VQa6D33y8IA?si=9SZ02zwT3ygVU-RD) - ▶ [Professional Diamond Ring Animation | Blender + iJewel Playground Tutorial](https://youtu.be/RiOxKTiDtQI?si=0MP7znClAp8Ht9em) ## iJewel3D Webinar 2025 - ▶ [Episode 1: Real-Time Brilliance](https://youtu.be/V4rHK9ntqUk?si=Rb8VcF5jQe2BUJaU) - ▶ [Episode 2: Mastering Materials](https://youtu.be/WnI1nud2xtk?si=u2YLL7KctQsNBMtQ) - ▶ [Episode 3: Scene Crafting](https://youtu.be/TV4v0OpV2DE?si=iyD88UyIzWfyRKh5) - ▶ [Episode 4: Post-Processing Magic](https://youtu.be/bTzMlF1toYw?si=d5Pg9NtAlsdasbdN) - ▶ [Episode 5: Content Creation](https://youtu.be/ogdN3WIMwx8?si=vwmX1wmTQjh3nndt) - ▶ [Episode 6: Animations in Jewellery](https://youtu.be/oTNLUwrkWK8?si=T0849zV5dkTC1GsP) - ▶ [Episode 7: TryOn and On body Jewelry experience](https://youtu.be/AHjwzKnNPBY?si=KdhYGDukmK1oi9Se) - ▶ [Episode 8: Designer Spotlight](https://youtu.be/8arHiW2LePs?si=aweAxDEGo-bUJ4WH) --- # Introduction to iJewel Viewer ![iJewel Viewer](../assets/images/configurator_banner.webp) `ijewelViewer` allows you to easily embed and render 3D models directly within your web pages. This guide will help you get started with integrating the viewer into your project, configuring it, and displaying 3D content. ## Getting Started To get started with the iJewel3D Viewer, you'll need to include the necessary scripts and create an HTML container for the viewer. Let's dive into the setup process! ### Including the Viewer Script First, include the iJewel3D Viewer script in your HTML file. You can use the following link: ```html ``` ::: info We regularly update the version numbers of the packages. Make sure to check the latest version back on this page when updating. Latest version: [0.6.18](https://releases.ijewel3d.com/libs/mini-viewer/0.6.18/bundle.nowebgi.iife.js) ::: ### Creating the HTML Container Next, create a container element in your HTML where the viewer will be rendered. Here's a basic HTML structure: ```html
``` ### Initializing the Viewer With the container set up, you can now initialize the Viewer and render your 3D project. Here’s an example of how to do it: ```html ``` :::tip For more details on how to connect to iJewel Drive and retrieve the model URL and base path, check out our [Connect to iJewel Drive](./connect-to-drive.html) section. ::: ## Standalone Model Embedding In addition to connecting to iJewel Drive, you can also directly load models into the Viewer without needing a base path. This is useful if you have a 3D model file that you want to embed directly into your webpage without configuration files or additional assets. ### Embedding a Standalone Model Check out this sample of embedding a model from any source directly into the Viewer: --- # Add an iJewel3D Drive Viewer to Your Website ![Connect iJewel Viewer and Drive](../assets/images/viewer_drive_connect.webp) ::: details Docs for old iJewel Drive The documentation for iJewel Drive instances created before March 2025 is available [here](deprecated/connect-to-drive). ::: ## Choose an integration method | Requirement | Recommended method | | --- | --- | | Add a self-contained viewer with minimal code | Iframe embed | | Select public models by a product tag or file name | Tag or name iframe embed | | Control the viewer from your page or application | Mini Viewer SDK | ## Option 1: Iframe embed An iframe is the quickest way to add a model with its configured viewer settings. Replace `{MODEL_ID}` with the model's iJewel Drive file ID. ```html ``` The base URL in the example is for the standard iJewel3D instance. Enterprise customers must use their instance URL. ::: tip For more control over the embedded viewer's appearance, open the model in the editor, select the **Embed (``)** tool, choose the available branding and control settings, preview the viewer, and copy the generated iframe. See [Create an iJewel Viewer Embed](../integrations/embedding.md) for the complete flow. ::: ## Option 2: Embed by tag or name Use this method when your website identifies products by a stable tag or file name. The viewer resolves the matching public file. Tag and name embeds do not send an authentication token. The selected file must be public. ### Prepare the file and scope 1. Open the folder that contains the model in iJewel3D. 2. Make sure that the model file is public. 3. For a tag embed, right-click the model and select **Edit Tags**. 4. Add a unique product tag, such as `pid-12345`. 5. Copy the folder ID from the address bar. The folder URL has the format `https://ijewel3d.com/drive/folders/FOLDER_ID`. Copy the value after `/folders/`. Use a folder ID that contains only one matching public file. The lookup returns the first matching file in that folder tree. ### Embed by tag Replace `{TAG}` and `{FOLDER_ID}` in this example: ```html ``` For example, a product tagged `pid-12345` can use this URL: ```text https://ijewel3d.com/drive/files/embedded?tag=pid-12345&scope=FOLDER_ID ``` ### Embed by name Use the exact file name, including its extension. Replace `{FILE_NAME}` and `{FOLDER_ID}` in this example: ```html ``` For example, a file named `wedding-ring.glb` can use this URL: ```text https://ijewel3d.com/drive/files/embedded?name=wedding-ring.glb&scope=FOLDER_ID ``` You can add material parameters after `scope`. For example, add `&Metal=Gold` to select the Gold variation. ## Option 3: Mini Viewer SDK Use the Mini Viewer SDK when your page needs to control the viewer, respond to viewer events, or coordinate it with other UI. - Standard iJewel Drive users should keep the basename as `drive`. - Enterprise customers should use the basename supplied by iJewel3D. - Give the viewer container an explicit width and height. - See [Connect to iJewel Drive](./connect-to-drive.md) for the complete API. ```html iJewel3D Viewer
``` ::: info Domain authorization Iframe embeds from Options 1 and 2 generally work without authorizing every destination domain. The Mini Viewer SDK requires each hosting domain to be authorized by iJewel3D. See [Host and domain setup](#host-and-domain-setup). ::: ## Find the model ID Option 1 and ID-based SDK calls require the model's unique **Model ID**, also called its **File ID**: 1. Open your iJewel Drive and find the model. 2. Right-click the model and select **Share**. 3. Find the viewer link, which has a format similar to `https://.../files/MODEL_ID/view`. 4. Copy the value between `/files/` and `/view`. ::: tip A store with many models can use a tag embed instead of an ID. Tag each file with its product ID, then build every URL from one pattern. See [Option 2: Embed by tag or name](#option-2-embed-by-tag-or-name). ::: ## Applying Materials via URL Apply specific materials automatically when the viewer loads by adding parameters to the URL. This works for both the iframe `src` and the direct link. Use either query parameters (`?`) or hash parameters (`#?`). The format is `key=value` where: - `key` is the **Layer Name** (e.g., `Metal`, `Gem Stone`). - `value` is the **Variation Name** (e.g., `White Gold`, `ruby`). **Examples:** - `https://ijewel3d.com/drive/files/{MODEL_ID}/embedded?Metal=Gold` - `https://ijewel3d.com/drive/files/{MODEL_ID}/embedded#?Band=Rose-Gold&Gem=Ruby` - `https://ijewel3d.com/drive/files/embedded?tag=pid-12345&scope=FOLDER_ID&Metal=Gold` - `https://ijewel.design/embedded?slug=d8c22bf&Metal=Gold` ### Finding Layer and Option Names To find the correct names to use in the URL: 1. Layer Name is the left side (key) of query parameter. It is same as the tab's name at the bottom of the configurator. Right click on the name at the bottom of the editor and select `Edit`. ![Layer Name](../assets/images/layer_name_edit.png) 2. For variation names, hovering over the variation icon will show the variation name with an edit icon next to it, click on the edit icon to edit the variation name. ![Variation Name](../assets/images/variation_name_edit.png) ::: tip Use `#?` to apply materials via URL in runtime without the need to reload the page. e.g. `https://ijewel3d.com/drive/files/{MODEL_ID}/embedded#?Band=Rose-Gold&Gem=Ruby`\ Alternatively, this can be used to implement custom UI for the material configurator: ```html ``` ::: ## Host and domain setup For the Mini Viewer SDK, add the hosting domain in iJewel3D Platform: 1. Host the HTML and JavaScript code on your website server. 2. Open **Settings → Domains**. 3. Select **Add Domain**. 4. Enter the production hostname, such as `www.example.com`. 5. Under **Domain Type**, select **Self-Hosted Domain**. 6. Select **Add Domain**. Enter only the hostname. Do not include `https://`, a port, or a page path. --- # iJewel3D Viewer SDK ![Connect iJewel Viewer and Drive](../assets/images/viewer_drive_connect.webp) The iJewel Viewer library loads 3D models from your iJewel3D account by ID, exact name, or tag. ::: tip Tutorial Check out [Embed iJewel3D Models on Your Website](./tutorial-embed-drive.md) for a step-by-step guide on how to use these functions. To learn how to apply materials via URL parameters, see [Apply Materials via URL](./tutorial-embed-drive.md#applying-materials-via-url). ::: ::: details Docs for older iJewel Drive instances The documentation for iJewel Drive instances created before March 2025 is available [here](deprecated/connect-to-drive). ::: ## Loading a Specific Model by ID (`loadModelById`) The primary function currently available for loading a single model directly from Drive is `loadModelById`. This is the recommended approach when you know the specific model file you want to display. ```javascript // Example: Load a model into a div with id="viewer-container" // Ensure the viewer library script is loaded first // // const driveBasename = 'drive'; // for enterprise clients contact us to get your basename, otherwise keep it unchanged const modelFileId = 'xyz789abc123'; // Replace with the actual Model ID const containerElement = document.getElementById('viewer-container'); ijewelViewer.loadModelById( modelFileId, driveBasename, containerElement, { // Optional ViewerOptions showCard: true, showLogo: true, // Add other options as needed } ); // Optional: Listen for the ready event window.addEventListener("ijewel-viewer-ready", (event) => { console.log("Viewer is ready:", event.detail.viewer); const viewerInstance = event.detail.viewer; // You can interact with the viewer instance here }); ``` ### Parameters | Parameter | Type | Required | Description | |:------------|:--------------|:---------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `modelId` | string | Yes | The unique File ID of the 3D model file within your Drive. | | `basename` | string | Yes | The unique identifier for your iJewel Drive instance (e.g., 'yourcompany-drive'). Defaults to 'drive'. You don't need to change this one unless you are an enterprise client. Contact support if you don't know yours. | | `container` | HTMLElement | Yes | The HTML element where the viewer canvas will be rendered. | | `options` | ViewerOptions | No | An optional object containing viewer configuration options to customize appearance and behavior. See [Viewer Class](./viewer-class.md#vieweroptions) for details. | ## Loading a Model by Name (`loadModelByName`) `loadModelByName` searches a folder tree for an exact file name. Public files do not require an authentication token. For private files, provide a valid token. Contact iJewel3D support if your application does not have one. ```typescript // Example: Load a model named "ring_model.glb" from folder with ID "folder456" // Ensure the viewer library script is loaded first // // const modelName = 'ring_model.glb'; // Replace with the exact model filename const parentFolderId = 'folder456'; // Replace with the ID of the parent folder const driveBasename = 'drive'; // Or your enterprise basename const authToken = undefined; // Public files do not need a token const containerElement = document.getElementById('viewer-container'); const viewerInstance = await ijewelViewer.loadModelByName( modelName, parentFolderId, driveBasename, authToken, containerElement, { // Optional ViewerOptions showCard: true, // Add other options as needed } ); ``` ### Parameters (`loadModelByName`) | Parameter | Type | Required | Description | |:------------|:--------------|:---------|:------------| | `modelName` | string | Yes | The exact file name, including its extension. | | `parentId` | string | Yes | The folder ID that scopes the search. The search includes nested folders. | | `basename` | string | Yes | The iJewel3D instance identifier. Standard accounts use `drive`. | | `token` | string | No | An authentication token for a private file. Public files do not need one. | | `container` | HTMLElement | Yes | The HTML element that contains the viewer canvas. | | `options` | ViewerOptions | No | The viewer configuration. See [Viewer Class](./viewer-class.md#vieweroptions). | ## Loading a Model by Tag (`loadModelByTag`) `loadModelByTag` searches a folder tree for a matching public file. Use a unique tag within that folder tree. This function does not accept an authentication token. The selected file must be public. ```typescript // Example: Load the public model tagged "pid-12345" // Make sure that the viewer library scripts are loaded first // // const tag = 'pid-12345'; const scope = 'folder456'; const driveBasename = 'drive'; const containerElement = document.getElementById('viewer-container'); const viewerInstance = await ijewelViewer.loadModelByTag( tag, scope, driveBasename, containerElement, { showCard: true, } ); ``` ### Parameters (`loadModelByTag`) | Parameter | Type | Required | Description | |:------------|:--------------|:---------|:------------| | `tag` | string | Yes | The exact tag assigned to the public file. | | `scope` | string | Yes | The folder ID that scopes the search. The search includes nested folders. | | `basename` | string | Yes | The iJewel3D instance identifier. Standard accounts use `drive`. | | `container` | HTMLElement | Yes | The HTML element that contains the viewer canvas. | | `options` | ViewerOptions | No | The viewer configuration. See [Viewer Class](./viewer-class.md#vieweroptions). | ## Cross-Origin Resource Sharing (CORS) CORS settings restrict Mini Viewer SDK requests to authorized domains. If the console shows a CORS error, ask iJewel3D support to authorize your hosting domain. ## React (`ViewerComponent`) React A complete, runnable example project containing this component is available on GitHub: https://github.com/maanHimself/ijewel-viewer-react-example ### 1. Update `package.json` Add the following lines to your `dependencies`: ``` json { "dependencies": { // ... other dependencies "@ijewel3d/mini-viewer": "https://releases.ijewel3d.com/libs/web/ijewel3d-mini-viewer-0.6.17.tgz", "@types/webgi": "https://releases.ijewel3d.com/libs/webgi-v0/bundle-types-0.22.0.tgz" } } ``` ### 2. Install Dependencies ``` Bash npm install ``` ### 3. Add WebGI Script Add the WebGI script before your React app bundle loads. ```html ``` ### 4. Usage Import the `ViewerComponent` from the library and use it in your React application. Provide the necessary props to load your model. ``` typescript import { ViewerComponent } from "@ijewel3d/mini-viewer"; import { useEffect, useState } from "react"; import type { ViewerApp } from "webgi"; function App() { const [modelId,] = useState("Ep9bWZIlTSG6_8DH7QDc1w"); // Replace with your actual model ID const [viewer , setViewer] = useState(null); useEffect(() => { //optionally, you can use the viewer for further customization if (viewer) { // Example: Set background color const Color = (window as any).Color; viewer.scene.backgroundColor = new Color("#232721"); } }, [viewer]); return (
setViewer(v)} viewerOptions={{ showCard: false, //add other viewer options here }} basename="drive" //optional for enterprise users />
); } export default App; ``` ## Next.js The viewer relies on window, WebGL, and other browser‑only APIs, therefore server‑side rendering (SSR) for the component must be disabled when using Next.js. Add the WebGI script once in your root layout, then load the viewer component with `next/dynamic`. ```tsx import Script from "next/script"; import type { ReactNode } from "react"; export default function RootLayout({ children }: { children: ReactNode }) { return ( ``` ## Step 2: Select and Load a 3D Model - **Access** your iJewel drive with the 3D models. - **Right-click** a model and select "Open in 3D Viewer." ![Connect iJewel Viewer and Drive](../../assets/images/open_in_viewer.webp) - **Copy** the entire query parameter starting with `path=`. ![Connect iJewel Viewer and Drive](../../assets/images/copy-path.webp) - **Paste** this query parameter into the URL on your website where you've embedded the viewer code. This tells the viewer which 3D model to display. Your website url should look something like this: ``` https://www.yourwebsite.com/?path=base64_path ``` :::info The path is the base64 representation of the actual path to your 3D file in the drive. It starts from the root, followed by folder names, and ends with the 3D file name. ::: ## Step 3: Host and Domain Setup - **Host** the viewer code on your website. - **Inform us** of the domain where the viewer is hosted for authorization. --- # Introduction
Welcome to the iJewel Playground documentation. Playground is a web-based 3D visualization platform designed for jewelry professionals — import your 3D models, apply realistic materials, set up lighting, and share stunning renders with clients. ## Quick Access
What is Playground?
Overview of the platform, features, and what you can do with it
Quick Start
Get up and running in minutes — from first login to your first render
Importing Your First Model
Step-by-step guide to importing your 3D jewelry model into the scene
UI Overview
Left panel, canvas, right panel, toolbar — learn the full interface layout
--- # What is iJewel Playground? iJewel Playground is a web based 3D platform built specifically for the luxury industry. It enables designers, brands, and creators to present their products in highly photorealistic quality, all in real time, without the long waiting times of traditional rendering.

With iJewel Playground, users can import 3D models, assign materials, set up lighting, apply advanced post processing effects, and create interactive configurators.

Today, thousands of professionals across 60+ countries rely on it daily to visualize, customize, and share their creations with clients.
![iJewel Playground](../assets/images/playground_screen.webp) ## Key Features ### Real-time Photorealistic 3D Visualization One of the most important features of iJewel Playground is that it is purpose built for real time visualization of luxury products. High-end categories such as jewelry, watches, premium accessories, and automobiles demand exceptional attention to detail in their digital representation. Playground delivers on this need with its rich suite of materials, advanced lighting options, dynamic animations, and powerful post-processing tools, ensuring every product is showcased with unmatched realism and sophistication Instantly preview jewelry and luxury designs with uncompromising realism. Diamonds sparkle, metals shine, and lighting reacts naturally—giving clients a true-to-life experience without hours of offline rendering. ### Intuitive UI/UX Designed for ease of use, the interface is simple enough for first time users yet powerful enough for professionals. Complex 3D workflows are streamlined into clear steps, making it easy to focus on creativity rather than technical hurdles. ### Rich Material Library Access a rich collection of pre built materials designed specifically for jewelry and luxury products including precious metals, antique finishes, diamonds, gemstones, precious stones, car paints, fine fabrics (satin, velvet, cotton, and more), wood, leathers, and many others. Beyond the library, users can also create and fine tune custom materials, giving them complete control over every detail of their designs. ### Extensive Scene Presets Save time with ready to use environments and lighting setups. From elegant studio backdrops to dramatic HDR scenes, complete 3D stages, backgrounds, and ground settings, Playground’s scene presets make it effortless to showcase luxury products under the perfect conditions. With just a few clicks, you can craft unique atmospheres that reflect your brand’s identity and elevate the visual storytelling of your creations. --- # Quick Start ![iJewel Playground](../assets/images/playground_screen.webp) To quickly create a realistic render and get a felling of the workflow in iJewel Playground, follow these simple steps: * Pick one of the sample models * **Apply materials** from metal, diamond, gem, and PBR presets, or customize your own. * **Choose HDR lighting** for a realistic environment reflection and mood. * **Configure the scene** Backgrounds, ground reflections, shadows, and camera setups. * **Adjust Post processing** Apply filters such as reflections, bloom, tone-mapping, ambient occlusion and more. * **Export & share** Download images, videos, or scene presets to showcase your work. Here is a [Quick Introduction Video](https://www.youtube.com/watch?v=P0R38Y2S-b0) --- # Importing Your First Model You can import files into Playground in two simple ways: 1. Drag your file directly into the **Main Canvas Area**. 2. Browse & Select - Click the **Import File** button in the toolbar or editor UI. - Select the file from your local computer. ![File Dialog Screenshot](../assets/images/playground-importfile.webp) ::: tip Playground also provides a few **sample models** for a quick start. Perfect for testing workflows before importing your own designs. ![Placeholder - Sample models](../assets/images/playground-loadsample.webp) ::: --- # UI Overview The iJewel Playground interface is designed to give you both **speed** and **control** while working with your 3D models. Whether you're a beginner or a professional 3D artist, this page will help you understand where everything is and how the interface is organized. ## Interface Layout The Playground is divided into **three main areas**: ![iJewel Playground Interface](../assets/images/ui-overview-rp.webp) 1. Left Panel — Presets & quick settings for fast, professional results 2. Canvas (Center) — The live 3D viewport where your models are displayed 3. Right Panel — Professional tools with full control over every setting ::: tip The **left panel** is designed for speed — ready-made presets you can apply with one click. The **right panel** is for precision — complete control over every detail. Both panels work together to give you the perfect balance between convenience and customization. ::: --- ## Canvas (3D Viewport) The canvas is the central area where your 3D model is displayed in real-time. ### Welcome Screen When no model is loaded, you'll see the welcome screen with options to get started: ![Welcome Screen](../assets/images/ui-overview-welcome.webp) - **Drag and drop** a 3D file directly onto the canvas - **Select local file** from the right panel to browse your files - **Load a sample** — click one of the sample models at the bottom to start experimenting right away ### Navigation Controls Once a model is loaded, you can navigate the 3D scene: | Action | Mouse | Touch (Mobile/Tablet) | |---|---|---| | **Rotate** | Click & drag | Drag with one finger | | **Zoom** | Scroll wheel | Pinch with two fingers | | **Reposition** | Hold `Shift` + drag | Drag with two fingers | ### Selecting Objects To select an object, simply **click on it**. The selected object will be highlighted with an **orange outline**. Once selected, you can apply materials, add configurators, and adjust settings for that specific object. ![Selected object with orange outline](../assets/images/ui-select-object.webp) ::: tip Click on **empty space** to deselect the current object. ::: ### Canvas Toolbar The toolbar is located on the right side of the canvas, providing quick access to common actions: ![Canvas Toolbar](../assets/images/ui-3d-canvas.webp)
Fullscreen
Fullscreen
Expand the viewer to fill the screen
Reset
Reset Settings
Remove all custom settings and start fresh
Delete
Delete Scene
Clear everything from the canvas
Fit Object
Fit Object to Scene
Auto-frame the selected object or entire scene
Loop Camera
Loop Camera Views
Play your saved camera view animation
GLTF Animation
GLTF Animation
Play animations imported from other software (Blender, etc.)
Auto Rotate
Auto Rotate
Simple 360° rotation of the model
Capture
Capture Snapshot
Download a PNG of exactly what you see — no UI elements
Export GLB
Export GLB
Download all objects and settings as a GLB file
::: tip **Fit Object to Scene** is one of the most useful tools. Editing a specific diamond? Select it, click this button, and the canvas frames it perfectly. Click on empty space and use it again to frame your entire scene. ::: ### Material Configurator (Canvas) When you **select an object** on the canvas, an **Add Configurator** button appears at the top-right of the canvas. This lets you create interactive material options that your clients can switch between in real-time. ![Selected object with Add Configurator button](../assets/images/ui-3d-canvas-selected-object.webp)
Add Configurator
Add Configurator
Appears when an object is selected and has no configurator yet
Edit Configurator
Edit Configurator
Appears when an object is selected and already has a configurator
**How it works:** 1. **Select an object** on the canvas — the "Add Configurator" button appears at the top-right 2. **Click Add Configurator** — a popup appears on the canvas showing the material library (5 categories: Metals, Gems, Ceramics, Pearls, Other) 3. **Choose or enter a name (Label)** at the top of the popup. The field suggests labels for the selected material category, and also accepts a custom label. Selecting a suggestion applies it immediately 4. **Click materials** to add them — each selected material appears at the bottom of the canvas 5. **Click a selected material again** to remove it from the configurator ![Configurator popup with material selection](../assets/images/ui-configurator-popup.webp) Once configured, the material options appear at the bottom of the canvas. Your clients can click to switch between materials in real-time. ![Ready configurator at the bottom of the canvas](../assets/images/ui-ready-configurator-canvas.webp) ::: tip You can create **multiple configurators** for different objects in the same scene — for example, one for metals and one for gemstones. The configurator name helps you identify which is which. ::: --- ## Left Panel — Presets & Quick Settings The left panel provides **ready-to-use presets** for fast, professional results. These are designed to save you time — instead of adjusting dozens of settings manually, just click a preset and your scene is instantly transformed. ![Left Panel](../assets/images/ui-overview-lp.webp)
HDR Metal
HDR Metal
HDRI environment maps optimized for metal reflections — gold, silver, platinum
HDR Gem
HDR Gem
HDRI environment maps for diamond sparkle, fire, and brilliance
Background
Background
Solid colors, gradients, and specialty jewelry backgrounds
Scene Presets
Scene Presets
Complete setups with HDRI, background, ground & tonemapping — one click
Stage
Stage
Professional platforms, display stands, ring boxes, cone stands, snow globes
Ground
Ground
Shadow presets — soft shadows, contact shadows, reflective surfaces
Pose
Pose
Compute Stable Pose — ring lying flat, standing, or custom angle
Export
Export
Quick image & video export — PNG, JPEG, WebP, MP4 up to 4K
Batch Render
Batch Render
Render multiple outputs at once for batch production
Embed
Embed
Generate embed code for your website or e-commerce platform
Branding
Branding Settings
Logo, watermark, and brand customization for embeds
Advanced
Advanced Settings
Environment rotation, intensity, SSBevel shortcut
TryOn
TryOn
Virtual try-on for rings using AR camera
--- ## Left Panel — Material Library When you **select an object** on the canvas, a set of material category icons appears at the top of the left panel. This is the **Material Library** — an extensive collection of ready-to-use materials organized by category. ![Material Library](../assets/images/ui-overview-lp-materials.webp) Simply click any material to apply it instantly to the selected object.
How it works
Click any object on the canvas → material category icons appear at the top of the left panel → browse and click to apply materials instantly.
Metals
Metals
Gold, white gold, rose gold, silver, platinum, antique finishes, enamel, and more
Gems
Gems & Diamonds
Diamonds (with/without dispersion), emeralds, sapphires, rubies, fancy colors, inclusions, iridescent
Ceramics
Ceramics
Ceramic finishes in various colors and textures
Pearls
Pearls
Beautiful pearl presets with realistic iridescence and luster
Other
Other Materials
Turquoise, malachite, lapis lazuli, jasper, carbon, coral, enamel, fabric, leather, marble, wood, and more
Free vs Premium vs Advance
Free
Gems & Materials Basic, Gems Inclusions Basic
Premium
Gems & Materials Extended, Gems Inclusions Basic
Advance
Gems & Materials All, Gems Inclusions All
Materials marked with a 💎 icon require a Premium or Advance plan. See pricing details.
--- ## Right Panel — Professional Tools The right panel contains **every setting available** in Playground, organized into tabs. The icons are arranged vertically on the far right side of the screen. ![Right Panel](../assets/images/ui-overview-right-panel.webp)
Viewer
Viewer
Renderer quality & scale, Camera & Field of View, Drop Options
Picking
Picking
Hierarchy, Material Library, Diamonds, Transform Controls, Picker, UV Unwrapping, Widgets
Scene
Scene
Background / Environment, Ground, Lights, Cameras, HDRi Ground, Gradient SVG
Anti-aliasing
Anti-aliasing
Progressive, Temporal AA, Velocity Buffer (TAA)
Post Processing
Post Processing
SSR, Tonemapping, Bloom, Depth of Field, SSAO, SSBevel, Vignette, LUT & more
Export
Export
Asset Export (GLB), Video Export, Image Export, S3 Connection, Share Link
Animations
Animations
GLTF Animations, Camera Views, Viewer Animations, Physics, Pose Plugin
Modifiers
Modifiers
Object Rotations, Extrude Tube Shapes, Simple Text, Parallax, Simplify Modifier
Configurators
Configurators
KHR Material Variants, Material Configurator, Switch Node
Plugins
Plugins
Full Screen, Loading Screen, Model Stage, Rhino 3dm Loader, CSS3D Renderer & more
Extras
Extras
Virtual Cameras, Rainbow Diamond Coloring, Snow Fall Particles, Wave Ground
--- ## Image Input Menu Many settings across the right panel use image inputs — for textures, background images, environment maps, and more. When an image is loaded in any of these inputs, clicking on the image thumbnail opens a context menu with the following options: ![Image input context menu](../assets/images/ui-overview-image-menu.webp)
Remove Image
Delete the current image from this input
Download Image
Save the current image to your computer
Set/Replace Image
Upload a new image from your computer to replace the current one
From URL
Load an image from a web URL
Cancel
Close the menu without making changes
--- ## What's Next? Now that you know where everything is, here are the recommended next steps: - **[Quick Start](./quick-start)** — Set up your first scene in minutes - **[Importing Your First Model](./import-first-model)** — Learn how to bring your 3D designs into Playground - **[Renderer Settings](./renderer-settings)** — Improve your render quality - **[Export Images](./export-images)** — Save high-resolution renders - **[Export Videos](./export-videos)** — Create turntable and camera animations --- # Importing Playground supports importing 3D models, custom materials, and scene settings. Drag & drop files directly onto the canvas or use the import panels to bring your content into the scene.
.glb
3D Models
Import .glb files via drag & drop — your 3D jewelry models with geometry and materials
.pmat
.dmat
Materials
Import custom PBR materials (.pmat) and diamond materials (.dmat) — apply or save to library
.vjson
.json
Scene Settings
Import complete scene configurations or individual setting presets
Optimization Guidelines
Best practices for preparing your 3D models for optimal performance in Playground
--- # Importing 3D Models iJewel Playground supports all popular 3D formats, making it easy to bring your jewelry designs into an interactive, real-time environment. ## Supported File Formats
.OBJ / .OBJ + .MTL .GLB / .GLTF .3DM (Rhino) .FBX .STL
::: tip Recommended Format for Jewelry For **jewelry workflows**, the **3DM format** is highly recommended. It supports layers, which Playground reads automatically — based on standard naming conventions, default materials are applied instantly, letting you view your jewelry in a photorealistic way right from the start. ::: ::: warning STL Limitations **STL format** does not support materials, making it unsuitable unless your model uses only a single material. Additionally, STL files often have unsmoothed normals, which can reduce the visual quality of jewelry models. ::: --- ## Import Methods You can import files into Playground in two ways: ### 1. Drag & Drop Drag your file(s) directly into the **Main Canvas Area**. When you first open Playground, the welcome screen provides a clear drop zone: Drag and drop files onto the canvas ### 2. Browse & Select Click the **Import File** button in the toolbar to open a file dialog and select the file(s) from your computer. Import file button ::: tip - You can **drag & drop multiple files** at once to import them together. - Drop a **folder or zipped folder** with multiple 3D files — Playground will automatically process its contents (including subfolders). - For **OBJ + MTL** files, make sure both are dropped together to correctly apply material data. ::: --- ## Drop Options Before importing, you can configure how models are placed in the scene. These settings are located in **Viewer → Drop Options**. Drop Options panel
Auto Scale
Automatically adjusts the model's proportions (defined by Auto Radius) to fit the scene.
Auto Radius
Defines the radius by which the model proportions will be scaled.
Auto Center
Ensures the model is positioned at the exact center of the canvas.
::: tip Keep **Auto Scale + Auto Center** turned **ON** when importing single models. This ensures that even off-center or incorrectly scaled models are normalized for an optimal starting view. ::: Turn **OFF** Auto Scale / Auto Center if you want to preserve the original **size** and **relative position** of your models. For example, if you import two separate files (e.g., the **shank** and the **head** of a ring), enabling Auto Scale / Auto Center may rescale or reposition them incorrectly, resulting in misalignment.
Correct alignment — parts assembled properly
✅ Auto Scale OFF — correct alignment
Misalignment — parts shifted due to Auto Scale
❌ Auto Scale ON — misalignment
--- ## Sample Models Playground provides a few built-in **sample models** for quick testing. Perfect for exploring workflows before importing your own designs. Load sample models See the [Quick Start](./quick-start) guide for more details. --- ## Import Options for Jewelry Once a jewelry model is imported, Playground will prompt you with a few options to help you get started faster. ### 1. Default Materials Based on the **layer/material names** assigned in the imported file, Playground will attempt to assign default materials automatically. Click **Yes** to apply the suggested materials. Default Materials popup ::: info Default Material Mapping - `Metal 01`, `Metal 02`, ... → Assigned default **Metal** materials - `Gem 01`, `Gem 02`, ... → Assigned default **Gem** materials ::: --- ### 2. HDR Map for Gem/Metal If a model has both **gem/diamond** and **metal** materials, Playground will prompt you to apply a **separate HDR environment map** for each category. HDR Map popup ::: tip Recommendation It is generally recommended to use a **separate HDR environment map** for gems/diamonds and metals. This allows finer control over the look and realism of your jewelry. ::: --- ### 3. Default Material Configurator If default layers are assigned for **metals** and/or **gems/diamonds**, Playground will prompt you to create a **material configurator** — enabling interactive switching of gem and metal materials in the embedded viewer. Material Configurator popup ::: tip Editing Configurator The default configurator can be **edited later** if you wish to change materials or modify the configurator settings. See [Material Configurator](./material-configurator) for details. ::: ::: info These **Import Options** appear as pop-up prompts immediately after adding a new model, before it is fully loaded into the **Scene Hierarchy**. ::: --- ## Related Pages - **[Import Materials](./import-materials)** — Load saved PBR and diamond material presets - **[Import Scene Settings](./import-scene-settings)** — Apply complete scene configurations - **[FAQ: Importing Models](./faq-import)** — Common questions about importing --- # Import Materials iJewel Playground allows you to import your own custom materials and use them alongside the built-in material library. The supported formats are **`.pmat`** (PBR Material) and **`.dmat`** (Diamond Material). ## Supported Formats | Format | Description | |---|---| | `.pmat` | PBR material file — used for metals, ceramics, pearls, etc. | | `.dmat` | Diamond material file — used for diamonds and other gemstones | ![Material file format](../assets/images/import-materials-format.webp) ## Two Ways to Import Materials There are two ways to add a custom material in Playground: **apply directly to an object** or **add to the material library** for reuse across projects. --- ### Method 1 — Apply Directly to an Object Use this method when you want to quickly apply a material to a specific object without saving it to the library. 1. **[Select an object](./ui-overview#selecting-objects)** on the canvas 2. **Drag and drop** your `.pmat` or `.dmat` file onto the 3D canvas 3. A popup will appear asking: **"Apply material to the selected object?"** — click **Yes** or **No** ![Apply to selected object popup](../assets/images/import-mat-object-apply-to-selected-object.webp) 4. A second popup will appear asking: **"Apply to all objects using this material?"** — click **Yes** or **No** ![Apply to all objects popup](../assets/images/import-mat-object-apply-to-all.webp) ::: tip Selective Material Application These two popups give you precise control over where the material is applied. By answering **Yes** to the first and **No** to the second, you can apply the material **only to the selected object** — even if other objects in the scene share the same original material. This effectively separates the material, allowing different objects to have different looks. ::: --- ### Method 2 — Add to Material Library Use this method when you want to save a material for reuse across multiple projects. Once added, the material stays in your library and is available anytime. 1. **[Select an object](./ui-overview#selecting-objects)** on the canvas — this opens the material library in the left panel 2. Navigate to the appropriate material category (Metals, Gems, Ceramics, Pearls, or Other) 3. Click the **circle with a plus icon** at the very beginning of the material list 4. Choose the `.pmat` or `.dmat` file you want to upload 5. The material will appear in the library with an **automatically generated preview** thumbnail ![Adding material to the library](../assets/images/import-mat-library.webp) To apply the material, simply **click on its icon** in the library — it will be applied to the currently selected object. To remove a material from the library, click the **cross icon** at the top-right corner of its thumbnail. ::: tip Materials added to the library are persistent — you can use them in other projects without needing to import them again. ::: ::: warning Premium & Advance Saving custom materials to the library requires a paid plan. **Premium** allows up to **5 saved materials**, and **Advance** allows up to **100**. See [pricing details](https://ijewel.design/pricing) for more information. ::: --- ## Related Pages - **[UI Overview](./ui-overview)** — Learn about the interface layout, panels, and navigation - **[Importing 3D Models](./import-models)** — How to bring your 3D designs into Playground - **[UI Overview — Material Library](./ui-overview#left-panel-—-material-library)** — Browse the built-in material categories - **[UI Overview — Material Configurator](./ui-overview#material-configurator-canvas)** — Create interactive material switching for your clients - **[Import Scene Settings](./import-scene-settings)** — Import `.vjson` and `.json` scene configuration files - **[Export Models](./export-models)** — Export your scene as `.glb`, including materials and settings - **[Export Materials](./export-materials)** — Export `.pmat` and `.dmat` material files - **[Export Scene Settings](./export-scene-settings)** — Export `.vjson` and `.json` scene configuration files --- # Import Scene Settings iJewel Playground allows you to import scene settings files to quickly apply preconfigured environments, lighting, post-processing, and more. This is especially useful when you want to reuse a look you've already perfected or share setups between projects. ## Supported Formats | Format | Description | |---|---| | `.vjson` | Complete scene configuration — contains all settings: HDR maps, background, ground, post-processing, tonemapping, camera, and more | | `.json` | Partial settings — contains only specific settings, for example only ground or only tonemapping | ![Settings file formats](../assets/images/import-settings-format.webp) ::: info What's inside a .vjson file? A `.vjson` file is a full snapshot of your scene configuration. It includes everything: environment HDR maps, background color/gradient, ground settings, light positions, post-processing effects (bloom, SSAO, SSR, etc.), tonemapping, anti-aliasing, and camera parameters. Importing one instantly recreates the entire look of a scene. ::: --- ## Two Ways to Import Settings There are two ways to use settings files: **apply directly to the current scene** or **save to the preset library** for reuse. --- ### Method 1 — Apply Directly to the Current Scene Use this method when you want to quickly load settings into your active scene. 1. Open your project in Playground 2. **Drag and drop** your `.vjson` or `.json` file onto the 3D canvas 3. The settings are **applied immediately** — you will see the scene update in real-time ::: tip This is the fastest way to switch between different scene looks. Just drag a different `.vjson` file to instantly change the entire atmosphere of your scene. ::: --- ### Method 2 — Save to Scene Presets Library Use this method when you want to save a `.vjson` file for reuse across multiple projects. Once added, the preset stays in your library and is available anytime. 1. Open the [left panel](./ui-overview#left-panel-—-presets-quick-settings) and go to the **Scene Presets** tab:
Scene PresetsScene Presets
2. Click the **square with a plus icon** at the beginning of the preset list 3. Select the `.vjson` file you want to upload 4. The preset will be added to the library with an **automatically generated preview** of the scene settings 5. To apply the preset, simply **click on its icon** 6. To remove a preset from the library, click the **cross icon** at the top-right corner of its thumbnail ![Saving vjson to Scene Presets library](../assets/images/import-settings-library-vjson.webp) ::: warning Premium & Advance Saving presets to the library requires a paid plan. **Premium** allows up to **5 saved presets**, and **Advance** allows up to **100**. See [pricing details](https://ijewel.design/pricing) for more information. ::: --- ## .vjson vs .json — When to Use Which | | `.vjson` | `.json` | |---|---|---| | **Scope** | All scene settings at once | Only specific settings | | **Use case** | Recreate an entire scene look | Adjust one aspect (e.g., ground only) | | **Example** | Full studio setup with HDR, lighting, ground, post-processing | Just the tonemapping or just the ground shadow | | **Library** | Can be saved to Scene Presets | Ground `.json` can be saved to Ground tab; other `.json` — drag & drop only | ::: tip Ground Presets A `.json` file with ground settings can also be saved to the library — use the GroundGround tab on the left panel and click the plus icon, just like with Scene Presets. Other partial `.json` files (tonemapping, etc.) can only be applied via drag & drop. ::: ![Saving ground json to library](../assets/images/import-settings-library-json.webp) --- ## Related Pages - **[UI Overview](./ui-overview)** — Learn about the interface layout and panels - **[UI Overview — Left Panel](./ui-overview#left-panel-—-presets-quick-settings)** — Scene Presets and other quick settings - **[Import Materials](./import-materials)** — Import custom `.pmat` and `.dmat` files - **[Importing 3D Models](./import-models)** — Bring your 3D designs into Playground - **[Renderer Settings](./renderer-settings)** — Configure render quality and scale - **[Export Models](./export-models)** — Export your scene as `.glb`, including settings - **[Export Scene Settings](./export-scene-settings)** — Export `.vjson` and `.json` scene configuration files --- # Coming Soon... --- # Exporting Everything you create in Playground can be exported. Download 3D models, save custom materials for reuse, back up your scene settings, render high-resolution images and videos, or share an interactive 3D viewer link with your clients. --- ## 3D Export your full scene as a file.
.glb
3D Models Full scene with geometry, materials, textures & settings in one file
--- ## Materials Save individual materials for reuse.
.pmat
PBR Materials Metals, ceramics, pearls — save and reuse across projects
.dmat
Diamond Materials Diamonds and other gemstones with dispersion & brilliance
--- ## Settings Back up and transfer scene configurations.
.vjson
Scene Settings HDR, background, ground, post-processing — entire scene look in one file
.json
Partial Settings Export only specific settings — ground, tonemapping, or other individual presets
--- ## Share Deliver to clients and publish online.
.webp
Images High-resolution renders up to 4K with transparent background support
.mp4
Videos Turntable, camera views, and 360° rotation videos up to 4K
3D Viewer Link Generate a shareable link to an interactive 3D viewer for clients and partners
Embed Embed an interactive 3D viewer directly into your website or e-commerce platform
--- # Export Models iJewel Playground allows you to export your scene as a **GLB** file — a compact binary format that packages 3D geometry, materials, textures, and optionally scene settings into a single file. There are three ways to export, depending on how much control you need. ## Export Format | Format | Description | |---|---| | `.glb` | Binary glTF — contains all objects, materials, textures, and optionally scene settings in one file | --- ## Three Ways to Export --- ### Method 1 — Quick Export (Canvas Toolbar) The fastest way to export. Click the Export GLBExport GLB button on the [canvas toolbar](./ui-overview#canvas-toolbar) — this immediately downloads your scene as a `.glb` file with current settings. ![Quick export from toolbar](../assets/images/export-model-toolbar.webp) --- ### Method 2 — Left Panel Export For a quick export with the option to enable compression: 1. Open the ExportExport tab on the [left panel](./ui-overview#left-panel-—-presets-quick-settings) 2. Enable **Compress** if you want to reduce the file size (uses DRACO compression) 3. Click **Download .glb** ![Export from left panel](../assets/images/export-model-left-panel.webp) ::: tip Use the left panel export when you need a smaller file for web embedding or sharing. DRACO compression significantly reduces file size with minimal quality loss. ::: --- ### Method 3 — Right Panel (Advanced Export) For full control over what's included in the exported file, use the **Asset Export** section on the [right panel](./ui-overview#right-panel-—-professional-tools): 1. Open the ExportExport tab on the right panel 2. Go to the **Asset Export → GLB Export** section 3. Enter a **file name** at the top 4. Configure export options (see below) 5. Click **Export GLB** ![Advanced export from right panel](../assets/images/export-model-rignt-panel.webp) #### Export Options
DRACO Compress
Applies DRACO compression to reduce file size. Useful for web delivery and embedding.
Scene Settings
Include all scene configuration (HDR, background, ground, post-processing, etc.) in the exported file. Disable if you only need the 3D geometry and materials.
Embed Image Previews
Embeds preview images of materials and scene inside the GLB file.
Only Visible
Exports only objects that are currently visible in the Hierarchy. Hidden objects are excluded from the file. This is useful for splitting one scene into multiple files — hide/show different parts and export separately.
Encrypt
Protects the file with a password. When enabled, a password input field appears. This password will be required every time someone tries to load the file.
Compress HDR env maps
Compresses the HDR environment maps included in the file to reduce overall size.
Convert to indexed
Converts geometry to indexed format for better performance and smaller file size.
Ignore invalid animations
Skips any animations that may cause export errors, ensuring a clean export.
Encrypt option with password field

Protecting Your Designs

Jewelry designs are often unique and commercially valuable. The Encrypt option lets you protect your GLB files with a password — anyone trying to open the file will need to enter it first. This adds an extra layer of security when sharing files with clients, manufacturers, or partners.

Learn more about encryption →

::: tip Splitting a Scene into Multiple Files Use the **Only Visible** option together with the [Hierarchy](./picking) to export parts of your scene separately. For example, hide everything except the ring band, export it, then hide the band and show the gemstone, and export again. This gives you individual GLB files for each component. ::: --- ## Related Pages - **[UI Overview](./ui-overview)** — Interface layout, toolbar, and panels - **[UI Overview — Canvas Toolbar](./ui-overview#canvas-toolbar)** — Quick export button location - **[Importing 3D Models](./import-models)** — Bring your 3D designs into Playground - **[Import Materials](./import-materials)** — Import custom `.pmat` and `.dmat` files - **[Import Scene Settings](./import-scene-settings)** — Import `.vjson` and `.json` scene files - **[Export Images](./export-images)** — Save high-resolution renders as PNG, JPEG, or WebP - **[Export Videos](./export-videos)** — Create turntable and camera animation videos --- # Export Materials iJewel Playground allows you to export custom materials as standalone files. This is useful for backing up your material settings, sharing them with colleagues, or reusing them in other projects. ## Export Formats | Format | Description | |---|---| | `.pmat` | PBR material file — for metals, ceramics, pearls, etc. | | `.dmat` | Diamond material file — for diamonds and other gemstones | --- ## Exporting a PBR Material (.pmat) To export a physical material: 1. **[Select the object](./ui-overview#selecting-objects)** that has the material you want to export 2. Open the PickingPicking tab on the [right panel](./ui-overview#right-panel-—-professional-tools) 3. In the **Picker** section, find the **Physical Material** settings 4. Scroll down to the bottom 5. Click **Download .pmat** --- ## Exporting a Diamond Material (.dmat) To export a diamond material: 1. **[Select the object](./ui-overview#selecting-objects)** that has the diamond material 2. Open the PickingPicking tab on the [right panel](./ui-overview#right-panel-—-professional-tools) 3. In the **Picker** section, find the **Diamond Material** settings 4. Scroll down to the bottom 5. Click **Download .dmat** --- ## Related Pages - **[Import Materials](./import-materials)** — Import `.pmat` and `.dmat` files back into Playground - **[UI Overview](./ui-overview)** — Interface layout, panels, and navigation - **[Export Models](./export-models)** — Export your full scene as a `.glb` file - **[Export Scene Settings](./export-scene-settings)** — Export `.vjson` and `.json` scene configuration files - **[Custom PBR Materials](./coming-soon)** — Create your own PBR materials from scratch - **[Custom Diamond Materials](./coming-soon)** — Create your own diamond materials --- # Export Scene Settings iJewel Playground allows you to export your scene settings as standalone files. This is useful for backing up your scene look, transferring configurations between projects, or sharing presets with colleagues. ## Export Formats | Format | Description | |---|---| | `.vjson` | Complete scene configuration — all settings: HDR maps, background, ground, post-processing, tonemapping, material configurators, and more | | `.json` | Individual setting — only a specific plugin or parameter (e.g., ground, tonemapping, camera) | --- ## Exporting All Scene Settings (.vjson) There are two ways to export a complete `.vjson` file with all your scene settings. ### Method 1 — Left Panel (Quick Export) The fastest way to export all scene settings: 1. Open the ExportExport tab on the [left panel](./ui-overview#left-panel-—-presets-quick-settings) 2. Find the **Scene Settings** section 3. Click **Download VJSON** This saves all settings currently applied in your scene — background, ground, shadows, tonemapping, post-processing, material configurators, and everything else — as a single `.vjson` file. ![Export scene settings from left panel](../assets/images/export-ss-left-panel.webp) --- ### Method 2 — Right Panel (Advanced Export) For more control over exactly what to include in the exported file: 1. Open the ExportExport tab on the [right panel](./ui-overview#right-panel-—-professional-tools) 2. Go to the **Asset Export** section 3. Open **Preset Config Export** 4. Click **Plugins** to see the full list of what can be included or excluded ![Preset Config Export with plugin list](../assets/images/export-ss-righr-panel-section.webp) Here you can individually toggle which settings to include in the `.vjson` export. For example, you can exclude material configurators, remove a specific HDR map, or keep only the post-processing settings — giving you full control over what goes into the file. #### Quick Actions
Select None
Deselect all plugins — start from scratch and manually pick only what you need
Select All
Select all plugins — export everything
Export Plugins
Export only the currently selected plugins as a `.vjson` file
Export All Viewer Config Editor
Export the complete viewer configuration including all settings and plugins
![Quick action buttons](../assets/images/export-ss-right-panel-buttons.webp) --- ## Exporting Individual Settings (.json) You can also export a single setting as a `.json` file — for example, only the ground preset, only the tonemapping, or only the camera settings. This is useful when you want to transfer one specific aspect of your scene to another project. 1. On the right panel, navigate to the tab that contains the setting you want to export (e.g., SceneScene for ground settings, or Post ProcessingPost Processing for effects) 2. Find the specific setting (e.g., Ground, Tonemapping, SSR, etc.) 3. Click the **three dots** (⋮) next to the setting name 4. Select **Download preset** from the menu 5. The `.json` file with that specific setting will be downloaded ### What can be exported as individual .json? You can export presets for almost any setting in the right panel, including: - **Scene:** Ground, Progressive Shadow, Background - **Post Processing:** Screen Space Reflection (SSR), Tonemapping, Bloom, Depth of Field, SSAO, SSBevel, Vignette - **Viewer:** Renderer settings, Camera settings - **Anti-aliasing:** TAA, Progressive AA ::: tip Individual `.json` presets can be imported back by drag & drop onto the canvas. Ground `.json` files can also be [saved to the library](./import-scene-settings#method-2-—-save-to-scene-presets-library) for quick reuse. ::: --- ## Related Pages - **[Import Scene Settings](./import-scene-settings)** — Import `.vjson` and `.json` files back into Playground - **[UI Overview](./ui-overview)** — Interface layout and panels - **[Export Models](./export-models)** — Export your scene as a `.glb` file - **[Export Materials](./export-materials)** — Export `.pmat` and `.dmat` material files - **[Renderer Settings](./renderer-settings)** — Configure render quality and scale --- # Export Images iJewel Playground makes it easy to save high-resolution images of your jewelry renders in multiple formats. There are two ways to export images — a quick method and an advanced method. ## Quick Export (Camera Icon) The fastest way to capture an image is using the **camera icon** in the floating Quick Actions panel on the canvas. - Click the **camera icon** to instantly save a **PNG** snapshot of your current view. Camera icon in the Quick Actions panel on the canvas ::: tip This is perfect for quick captures during your design process. The image is saved at the current canvas resolution — make sure to adjust your [Renderer Settings](./renderer-settings.md) first if you need higher quality. ::: ## Advanced Export (Export Tab) For more control over format, resolution, and file naming, use the **Export Tab** in the Editor UI Panel. ### Steps 1. Open the **Export** tab in the right-side Editor UI Panel. 2. Choose your desired format: - **PNG** — Lossless quality, supports transparency. Best for product images. - **JPEG** — Smaller file size, no transparency. Good for web and social media. - **WEBP** — Modern format with excellent compression. Ideal for websites and e-commerce. 3. Enter a **file name** for your export. 4. Click **Download**. Image Export section in the right-side Editor UI Panel ## Export from the Left Menu You can also export images from the **left-side Presets Panel**: 1. Set the desired **width** and **height** for your output resolution. 2. Select the output **format** (PNG, JPEG, or WEBP). 3. Click **Download**. Snapshot export in the left-side Presets Panel ::: tip Higher Quality Exports For the best quality exports, increase the **width and height** values before downloading. This produces sharper images suitable for print, catalogs, or high-DPI displays. ::: ## Transparent Background To export an image with a transparent background (PNG format only), you need to configure several settings before exporting: 1. Go to [Background / Environment](./background-environment) and set the **Background Color** alpha channel to `0` (fully transparent) 2. Go to [Ground](./ground) and uncheck **Visible** to hide the ground plane 3. Disable [Progressive Shadow](./progressive-shadow) if it is enabled 4. Choose **PNG** as the export format (JPEG and WEBP do not support transparency) 5. Export the image ::: tip This is especially useful for e-commerce product listings and marketing materials where you need the jewelry on a clean, transparent background that can be composited onto any backdrop. ::: --- ## Recommended Settings by Use Case | Use Case | Format | Suggested Resolution | |---|---|---| | E-commerce product listing | PNG or WEBP | 1000×1000 px or higher | | Social media | JPEG or WEBP | 1080×1080 px | | Print catalog | PNG | 2000×2000 px or higher | | Website banner | WEBP | 1920×600 px | --- # Export Videos iJewel Playground allows you to record and export videos of your jewelry models — perfect for product showcases, social media, and e-commerce listings. You can create turntable animations, camera path recordings, and 360° spins. ## Turntable Video (Left Menu) The left-side Presets Panel provides a quick way to export turntable videos. ### Steps 1. Set the **resolution** (width and height) for your video output. 2. Configure the **FPS** (frames per second) — higher FPS results in smoother playback. 3. Set the **duration** of the video. 4. Click **Download**. The rendering process will begin, indicated by a **red border on the canvas**. Turntable video export in the left-side Presets Panel ::: warning Keep the browser tab open until the rendering process is complete. Closing or switching away from the tab may interrupt the export. ::: ## Advanced Recording (Right Panel) The **Export** section in the right-side Editor UI Panel offers multiple recording modes for different types of video output. ### Recording Modes | Mode | Description | |---|---| | **Standard Recording** | Records whatever is happening on the canvas in real time — ideal for custom interactions and walkthroughs. | | **Camera Views** | Records a sequence based on your saved camera view positions. | | **360° Animation** | Automatically rotates the model clockwise for a full 360° turntable video. | | **360° Animation (CCW)** | Same as above, but rotates counterclockwise. | Video Export recording modes in the right-side Editor UI Panel ### Steps 1. Open the **Export** tab in the Editor UI Panel. 2. Select your desired **recording mode**. 3. Customize your settings: - **Resolution** — Output width and height in pixels. - **FPS** — Frames per second (24 or 30 recommended for smooth playback). - **Duration** — Length of the video in seconds. 4. Click **Record**. 5. Wait for the recording to finish — a **red indicator** will appear on the canvas during the process. ::: tip For e-commerce and social media, a **360° animation** at 5–10 seconds duration with 30 FPS is a great starting point. It gives customers a complete view of the product in a short, engaging clip. ::: ::: tip Video file too large? See [Reducing the Video File Size](#reducing-the-video-file-size) below - a few settings can shrink a 33 MB export to under 1 MB. ::: ## Recommended Settings by Use Case | Use Case | Mode | FPS | Duration | |---|---|---|---| | Product listing | 360° Animation | 30 | 5–8 sec | | Social media reel | 360° Animation | 30 | 5–15 sec | | Client presentation | Camera Views | 24–30 | 10–20 sec | | Custom walkthrough | Standard Recording | 30 | As needed | ## Reducing the Video File Size Is your exported video too large? The compression settings are located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the ExportExport tab: set **Mime type** to *MP4 Video (ffmpeg)* and expand **FFmpeg Options (Advanced)** - highlighted below. FFmpeg Options (Advanced) in the Export tab of the right panel The two settings that matter for file size are **crf** and **preset**. Raise the crf (higher = smaller file) and set the preset to `veryfast` - this alone can shrink a 30+ MB export to a fraction of its size. Pick your goal: | Goal | Settings | Approx. size (10-sec video) | |---|---|---| | Best quality (larger file) | crf `18`, preset `veryfast` | ~4.5 MB | | Balanced (recommended for web) | crf `23`, preset `veryfast` | ~2 MB | | Smallest file | crf `28`, preset `veryfast` | ~1 MB | Exact sizes vary with the scene, the resolution, and the duration. If the file is still too large, keep raising the crf (it goes up to `51`) and lower the export resolution. What each option does: | Option | What it does | |---|---| | **imageType** | The format of the frames captured from the canvas before they are encoded into the video (`jpeg`, `png`, or `webp`). | | **bitrate** | A fixed target for the amount of data per second of video. When active, it makes the output size predictable. | | **crf** | Constant Rate Factor, the quality control. Lower values give better quality, higher values give stronger compression. Range `0`–`51`. | | **pixFmt** | The pixel format of the encoded video. `yuv420p` is compatible with all common browsers and players. | | **preset** | The encoding speed vs. compression trade-off. Faster presets encode quicker but compress less thoroughly. | | **colorTrc** / **colorSpace** | Color metadata written into the video, so the exported colors match what you see in the viewer. | Every scene is different, so feel free to play around: export a short test clip, check the size and quality, and adjust the crf up or down until you are happy with the result. --- # Scene Basics A scene in iJewel Playground consists of your 3D model together with everything that defines how it looks — background, lighting, ground, shadows, camera, and materials. Understanding these building blocks helps you create professional jewelry visualizations. ## What Makes Up a Scene Every scene has three core components: **3D Objects** — your imported jewelry model, organized as a [hierarchy](./hierarchy) of mesh nodes (containing actual geometry) and transform nodes (containing position, rotation, scale). Multiple meshes can share the same material, and objects can be nested inside parent groups. **Materials** — define the visual appearance of each object. By default, Playground assigns a Physical (PBR) Material for realistic rendering. You can convert objects to Diamond Material for gemstones. See [Picking → Physical Material](./picking#physical-material) and [Picking → Diamond Material](./picking#diamond-material). **Scene Settings** — everything else: background color, environment maps, ground, shadows, post-processing, lighting, and camera configuration. These are managed primarily through the SceneScene tab on the right panel. --- ## Scene Tab Sections The Scene tab on the right panel contains the following sections:
Background / Environment
Background color, environment maps (HDRI), and intensity settings. Read more →
Progressive Shadow
Soft, progressively refined shadows beneath the model
Ground
Ground plane visibility, reflections, and shadow settings
Scene
General scene settings and configuration
Gradient SVG
Custom gradient backgrounds using SVG
Lights
Add and configure directional, spot, and point lights in the scene
Cameras (Loaded)
Camera presets loaded from the model file
HDRi Ground
Use the HDRI environment map as a projected ground plane
Generate Geometry
Create simple primitive shapes (spheres, cubes, planes) directly in the scene
--- ## Documentation Pages
Scene Hierarchy
Browse all objects, select by name, and hide/show individual parts
Picking
Object properties, materials, diamonds, and all interactive controls
Transform Controls
Move, rotate, and scale objects with interactive gizmos and keyboard shortcuts
Renderer Settings
Configure render quality, resolution scale, and performance options
Scene settings like Background / Environment, Progressive Shadow, and Ground are documented separately under the **[Scene Settings](./scene-settings)** section in the sidebar. --- # Scene Basics A scene in iJewel Playground consists of your 3D model together with everything that defines how it looks — background, lighting, ground, shadows, camera, and materials. Understanding these building blocks helps you create professional jewelry visualizations. ## What Makes Up a Scene Every scene has three core components: **3D Objects** — your imported jewelry model, organized as a [hierarchy](./hierarchy) of mesh nodes (containing actual geometry) and transform nodes (containing position, rotation, scale). Multiple meshes can share the same material, and objects can be nested inside parent groups. **Materials** — define the visual appearance of each object. By default, Playground assigns a Physical (PBR) Material for realistic rendering. You can convert objects to Diamond Material for gemstones. See [Picking → Physical Material](./picking#physical-material) and [Picking → Diamond Material](./picking#diamond-material). **Scene Settings** — everything else: background color, environment maps, ground, shadows, post-processing, lighting, and camera configuration. These are managed primarily through the SceneScene tab on the right panel. --- ## Scene Tab Sections The Scene tab on the right panel contains the following sections:
Background / Environment
Background color, environment maps (HDRI), and intensity settings. Read more →
Progressive Shadow
Soft, progressively refined shadows beneath the model
Ground
Ground plane visibility, reflections, and shadow settings
Scene
General scene settings and configuration
Gradient SVG
Custom gradient backgrounds using SVG
Lights
Add and configure directional, spot, and point lights in the scene
Cameras (Loaded)
Camera presets loaded from the model file
HDRi Ground
Use the HDRI environment map as a projected ground plane
Generate Geometry
Create simple primitive shapes (spheres, cubes, planes) directly in the scene
--- ## Documentation Pages
Scene Hierarchy
Browse all objects, select by name, and hide/show individual parts
Picking
Object properties, materials, diamonds, and all interactive controls
Transform Controls
Move, rotate, and scale objects with interactive gizmos and keyboard shortcuts
Renderer Settings
Configure render quality, resolution scale, and performance options
Scene settings like Background / Environment, Progressive Shadow, and Ground are documented separately under the **[Scene Settings](./scene-settings)** section in the sidebar. --- # Renderer Settings The Renderer Settings control the rendering quality and resolution of the 3D viewport, as well as the output quality for exported images and videos. Adjusting these settings lets you balance between real-time performance while designing and maximum quality for final renders. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneViewer tab, in the **Renderer** section at the top. ![Renderer Settings Panel](../assets/images/playground-renderer-settings.webp)
--- ## Settings
Mode
Dropdown — controls the rendering mode for the viewport. Full enables all effects for the highest quality preview and exports
Scale
Slider — resolution multiplier for the 3D canvas (default: 1.000). Increasing the value enhances both the real-time viewing quality and the resolution of exported images and videos. Higher values produce sharper, more detailed renders — ideal for close-up jewelry shots where every facet matters
Custom Canvas Size
Set exact canvas dimensions (width × height in pixels). Useful when you need renders at specific dimensions — square images for e-commerce listings, wide formats for banners, or standard resolutions like 1920×1080
::: warning Performance Note Higher scale values require more GPU processing power. If you experience lag during real-time viewing, keep the scale at `1.000` while working and increase it only before exporting. ::: --- ## Recommended Workflow **While designing** — you can set the scale to `2.000` on most desktop computers — modern browsers handle it well. On lower-end devices, keep it at `1.000` for smooth performance. **Before exporting** — increase the scale to `3.000` or `4.000` for the sharpest results. On lower-end devices, `2.000` is a good minimum. If you're unsure about your device's capabilities, start with `1.000` and increase gradually. **Export** — use the [Export Images](./export-images) or [Export Videos](./export-videos) features to download your high-resolution renders. --- ## Related Pages - **[Scene Basics](./scene)** — Overview of all scene components - **[Export Images](./export-images)** — Export high-resolution renders - **[Export Videos](./export-videos)** — Export animated video renders - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # Scene Hierarchy The Scene Hierarchy gives you a complete overview of every 3D object in your scene. It displays the parent-child structure of your model, lets you select individual objects by name, and allows you to hide or show any object — which is especially useful when working with complex jewelry assemblies. ## Where to Find It The Hierarchy is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the PickingPicking tab. It is the first section you see when you open this tab. Click on the **Hierarchy** section header to expand the full tree view of your scene. ![Scene Hierarchy panel](../assets/images/playground-sb-hierarchy.webp) --- ## Selecting Objects Clicking on an **object name** in the hierarchy selects that object in the scene. The selected object will be highlighted in the 3D viewport, and its properties will become available for editing. This is particularly useful when: - An object is **hard to click** in the viewport because it's small or hidden behind other objects - You need to select a **parent group** rather than an individual mesh - You want to quickly navigate between different parts of a complex model ::: tip You can also select objects by clicking directly on them in the 3D viewport. See [Selecting Objects](./ui-overview#selecting-objects) for more details. ::: --- ## Hiding and Showing Objects Each object in the hierarchy has a **checkbox** next to its name. Toggling this checkbox controls the object's visibility: - **Checked** — the object is visible in the scene - **Unchecked** — the object is hidden from the scene
Click on name
Select the object — it gets highlighted in the viewport and its properties become editable
Toggle checkbox
Show or hide the object in the scene — hidden objects disappear from the viewport
Toggle parent
Hiding a parent object also hides all of its children at once
--- ## Practical Use Cases ### Exporting Without Certain Objects Hiding objects in the hierarchy directly affects what gets included when you [export your model](./export-models). Combined with the **Only Visible** export option, you can: 1. Hide the objects you don't want to export (e.g., hide all stones, keep only the band) 2. Go to export and enable **Only Visible** 3. The exported `.glb` file will only contain the visible objects This is a powerful way to split a complex scene into separate files or to create variations of the same model without duplicating the original. ::: tip Use **Only Visible** together with **Hierarchy** to control exactly which parts end up in the exported file. See [Export Models — Splitting Scenes](./export-models) for more details. ::: ### Working with Transform Controls After selecting an object through the hierarchy, you can use [Transform Controls](./transform-controls) to move, rotate, or scale it directly in the viewport. This is especially useful for repositioning individual stones or adjusting specific parts of an assembly. ### Debugging Material Assignments Selecting an object in the hierarchy helps you see exactly which material is applied to it. This is useful when you need to change materials on a specific part of the model — for example, applying a different metal only to the prongs while keeping the band unchanged. You can also [import custom materials](./import-materials) (`.pmat` and `.dmat` files) and apply them to selected objects by drag & drop. --- ## Related Pages - **[UI Overview](./ui-overview)** — Full interface layout including the right panel - **[Selecting Objects](./ui-overview#selecting-objects)** — Different ways to select objects in the viewport - **[Export Models](./export-models)** — Export your scene as `.glb`, including visibility-based filtering - **[Transform Controls](./transform-controls)** — Move, rotate, and scale objects in the scene - **[Import Models](./import-models)** — How to bring 3D models into Playground --- # Picking The Picking tab is your main workspace for interacting with individual objects in the scene. When you select an object — either by clicking on it in the viewport or through the [Scene Hierarchy](./hierarchy) — the Picking tab shows everything related to that object: its name, visibility, transform properties, material, and more. ## Where to Find It The Picking tab is located on the [right panel](./ui-overview#right-panel-—-professional-tools). Click the PickingPicking icon to open it. ![Picking tab](../assets/images/pg-picking.webp) The tab contains the following sections:
Hierarchy
Tree view of all objects in the scene — select and hide objects. Read more →
Material Library
Browse and apply preset materials — metals, ceramics, pearls, and more. Import custom materials →
Diamonds
HDRI environment map for diamonds, Environment Rotation, and support for multiple HDRI maps per scene
Transform Controls
Move, rotate, and scale objects directly in the viewport. Read more →
Picker
All properties of the currently selected object — name, visibility, transform, material, and more
UV Unwrapping (xAtlas)
View and edit UV coordinates for texture mapping
Widgets
Additional visual helpers and interactive controls
--- ## Diamonds The Diamonds section manages the HDRI environment map used specifically for diamond and gemstone rendering. Diamonds require a separate environment map to produce realistic light dispersion and brilliance effects. Here you can adjust the **Environment Rotation** to change the angle of light reflections in your diamonds. You can also add a second or third environment map — this is useful when you want different diamonds in the same scene to use different HDRI maps for unique visual results. The Diamonds section also contains action buttons that change depending on the selected object's current material type: **When a regular object is selected** (Physical Material):
Make Diamond
Convert the object's material from Physical Material to Diamond Material, enabling diamond-specific rendering with light dispersion and brilliance
Clear Cache
Clear the cached diamond rendering data to force a fresh recalculation
**When a diamond object is selected** (Diamond Material):
Make Standard
Convert the object back from Diamond Material to a regular Physical Material
Auto Instance Diamonds (dev)
Developer utility for automatically instancing diamond objects
Clear Cache
Clear the cached diamond rendering data to force a fresh recalculation
![Diamonds section](../assets/images/picking-diamonds.webp) Once converted with Make Diamond, the Picker will display **Diamond Material** instead of Physical Material under the selected mesh, with its own set of properties tailored for gemstone rendering. ::: info Diamond Material editing will be covered on a dedicated page. See [Diamond Materials](./coming-soon) for more information. You can also [import custom .dmat materials](./import-materials) and [export diamond materials](./export-materials) from your scene. ::: --- ## Picker The Picker is the core section of the Picking tab. It has two global settings at the top:
Enabled
Checkbox — when enabled, clicking on objects in the canvas selects them. Disable to prevent accidental selection
AutoFocus
Checkbox — when enabled, the camera automatically zooms in on the object when you click on it
When you select an object, a section with the object's name (e.g., **mesh_1**) appears inside the Picker. This section contains all the properties described below. ### Visibility & Navigation
Visible
Checkbox — show or hide the object in the 3D canvas. Same as toggling visibility in the Hierarchy
Pick/Focus
Button — zoom the camera to focus on the selected object
Pick Parent
Button — select the parent object of the current selection in the hierarchy
Name
Text input — the name of the selected object. You can rename it here
### Rendering & Shadow
Casts Shadow
Whether this object casts shadows onto other objects and the ground
Receive Shadow
Whether this object receives shadows from other objects
Frustum culled
Whether the object is culled when outside the camera's view frustum
Render Order
Controls the rendering order — useful for overlapping transparent objects
### Transform The transform properties let you position, rotate, and scale the selected object numerically. You can type exact values for precise control.
Position
X, Y, Z coordinates — move the object to an exact position in the scene
Rotation
X, Y, Z angles — rotate the object around each axis
Scale
X, Y, Z values — resize the object along each axis
::: tip For visual, interactive transformations (drag to move/rotate/scale in the viewport), use [Transform Controls](./transform-controls) — also available in the Picking tab. ::: ### Quick Actions
Auto Scale
Automatically scale the object to fit the scene proportionally
Auto Center
Move the object to the center of the scene
Pivot to Node Center
Reset the object's pivot point to the center of its bounding box
### Rotate Model Quick rotation buttons that rotate the object by **90°** on each axis:
Rotate X +90 / −90
Rotate the object 90° around the X axis
Rotate Y +90 / −90
Rotate the object 90° around the Y axis
Rotate Z +90 / −90
Rotate the object 90° around the Z axis
Useful for quickly reorienting models that were exported in a different coordinate system. ### Geometry Displays information about the object's geometry, including a unique **uuid** and **name**. Also provides utility actions:
Center Geometry
Move the geometry to center
Center Geometry (keep position)
Center the geometry while keeping the object's world position
Compute vertex normals
Recalculate vertex normals for smooth shading
Compute vertex tangents
Recalculate tangents needed for normal mapping
Normalize normals
Ensure all normals are unit length for correct lighting
Convert to non-indexed
Convert the geometry from indexed to non-indexed format
### Physical Material The Physical Material section shows the PBR material currently assigned to the selected object. It contains subsections for editing all material properties: color, map, **Rough/Metal**, **Bump/Normal**, **Sheen**, **Clearcoat**, and more. ![Physical Material section](../assets/images/picking-physical-material.webp) ::: info Detailed material editing will be covered on a dedicated page. See [PBR Materials](./coming-soon) for more information. You can also [import custom .pmat materials](./import-materials) and [export materials](./export-materials) from your scene. ::: ### Diamond Material If the selected object is a diamond (converted via [Make Diamond](#diamonds)), this section appears instead of Physical Material. It contains diamond-specific properties for controlling dispersion, brilliance, and other gemstone rendering settings. ![Diamond Material section](../assets/images/picking-diamond-material.webp) ::: info Detailed diamond material editing will be covered on a dedicated page. See [Diamond Materials](./coming-soon) for more information. ::: ### Object Actions Below the Physical Material section, there are four action buttons for managing the selected object:
Remove Material
Remove the material assigned to this object
Duplicate Object
Create a copy of the selected object in the scene
Wrap in Parent
Create a new parent group and place the selected object inside it
Delete Object
Remove the selected object from the scene entirely
### Physics Physics simulation settings for the selected object. This section allows you to configure physical behavior for interactive scenes. ### Transform Animation Settings for animating the object's position, rotation, and scale over time. Used for creating keyframe-based transform animations. --- ## Related Pages - **[Scene Hierarchy](./hierarchy)** — Browse and manage all objects in the scene tree - **[UI Overview](./ui-overview)** — Full interface layout including the right panel - **[Import Materials](./import-materials)** — Import `.pmat` and `.dmat` material files - **[Export Materials](./export-materials)** — Export materials for reuse in other projects - **[Transform Controls](./transform-controls)** — Move, rotate, and scale objects visually - **[PBR Materials](./coming-soon)** — Detailed material editing guide - **[Diamond Materials](./coming-soon)** — Working with diamond and gemstone materials --- # Transform Controls Transform Controls allow you to move, rotate, and scale objects directly in the 3D viewport using interactive gizmos. This is the most visual and intuitive way to reposition objects in your scene. ## Where to Find It Transform Controls are located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the PickingPicking tab, in the **Transform Controls** section. ![Transform Controls panel](../assets/images/pg-transform-controls.webp) --- ## How to Enable 1. Open the **Picking** tab on the right panel 2. Find the **Transform Controls** section 3. Check the **Enable** checkbox 4. Select any object in the scene Once enabled and an object is selected, a 3D gizmo with colored arrows will appear on the object in the viewport. You can click and drag these arrows to transform the object. To disable Transform Controls, simply uncheck the **Enable** checkbox — the gizmo will disappear from the viewport. --- ## Settings
Mode
Choose the transformation type: Translate (move), Rotate, or Scale
Space
World — axes are aligned with the scene. Local — axes are aligned with the object's own orientation
Size
Adjust the size of the gizmo arrows in the viewport — make them bigger or smaller for comfort
Show X
Show or hide the X axis (red arrow)
Show Y
Show or hide the Y axis (green arrow)
Show Z
Show or hide the Z axis (blue arrow)
--- ## Keyboard Shortcuts You can quickly switch between modes and toggle axes using keyboard shortcuts:
Q
Toggle Space between World and Local
W
Switch to Translate mode
E
Switch to Rotate mode
R
Switch to Scale mode
X
Toggle Show X axis on/off
Y
Toggle Show Y axis on/off
Z
Toggle Show Z axis on/off
Ctrl+Z
Undo the last transformation (Cmd+Z on Mac)
--- ## Scaling the Entire Object In **Scale** mode (press `R`), you can scale the object along individual axes by dragging the corresponding arrow. To scale the entire object uniformly, click and drag the **small gray square** in the center of the gizmo — this resizes the object proportionally on all axes at once. --- ## Moving the Entire Object If you want to move or transform a complete object (not just an individual mesh), you need to select the **root parent** in the hierarchy first: 1. Open the [Scene Hierarchy](./hierarchy) 2. Click on the **parent object name** (the top-level group) 3. The Transform Controls gizmo will now affect the entire object, including all its children This is a common workflow — for example, when you want to reposition a whole ring assembly rather than just one stone or the band. --- ## Pivot Point The gizmo appears at the object's **pivot point**. Sometimes, especially with imported models, the pivot may not be centered on the object — it can be at the origin of the scene or at an unexpected location. This makes transformations (especially rotation and scaling) behave unexpectedly. To fix this, use the **Pivot to Node Center** button in the [Picker](./picking#quick-actions) section. This resets the pivot to the center of the object's bounding box. ![Pivot to Node Center](../assets/images/pg-transform-controls-pivot.webp) ::: warning If you use Pivot to Node Center on a **diamond object**, it may affect the diamond material structure. To fix this, go to the [Diamonds section](./picking#diamonds) and click **Make Standard** to revert the object to a regular material, then click **Make Diamond** again to reapply the diamond material. Alternatively, you can apply any diamond preset from the Material Library on the left panel. ::: --- ## Related Pages - **[Picking](./picking)** — Full overview of the Picking tab and all its sections - **[Scene Hierarchy](./hierarchy)** — Select parent objects and manage the scene tree - **[UI Overview](./ui-overview)** — Full interface layout including the right panel - **[Export Models](./export-models)** — Export your transformed scene as `.glb` - **[Import Models](./import-models)** — How to bring 3D models into Playground --- # Scene Settings The Scene Settings control everything about the visual environment surrounding your model — background, lighting, ground, shadows, and more. All of these settings are found in the SceneScene tab on the [right panel](./ui-overview#right-panel-—-professional-tools). ![Scene Settings tab](../assets/images/Scene-Settings.webp) --- ## Scene Tab Sections
Background / Environment
Background color, images, HDRI environment maps, intensity and rotation settings. Read more →
Progressive Shadow
Soft directional shadow beneath the model with adjustable focus, spread, color, and direction. Read more →
Ground
Ground plane with shadow, material, and blending options. Can be disabled for floating objects. Read more →
Scene
Contains the Clear Scene button — removes all objects and resets the scene. Same as the Clear Scene button on the toolbar. Use with caution: this action cannot be undone
Gradient SVG
Create custom gradient backgrounds using SVG. Read more →
Lights
Add and configure directional, ambient, point, and spot lights in the scene. Read more →
Cameras (Loaded)
Cameras imported from your 3D software — activate to use custom camera paths and animations. Read more →
HDRi Ground
Use the HDRI environment map as a projected ground plane. Read more →
Generate Geometry
Create simple primitive shapes (spheres, cubes, planes) directly in the scene. Read more →
--- ## Documentation Pages
Background / Environment
Background color, HDRI maps, environment intensity and rotation
Progressive Shadow
Soft directional shadow with adjustable focus, spread, and color
Ground
Ground plane, shadows, material, blending, and floating object mode
Gradient SVG
Create custom gradient backgrounds with two colors
Renderer Settings
Configure render quality, resolution scale, and performance options
Lights
Directional, ambient, point, and spot lights in the scene
Cameras (Loaded)
Imported cameras, camera paths, and animation playback
HDRi Ground
Project the HDRI environment map as a ground surface
Generate Geometry
Create primitive shapes like planes, spheres, boxes, and more
--- ## Related Pages - **[Scene Basics](./scene)** — Overview of working with 3D objects: hierarchy, picking, transforms - **[Import Scene Settings](./import-scene-settings)** — Import `.vjson` and `.json` scene configuration files - **[Export Scene Settings](./export-scene-settings)** — Export your scene settings for backup or sharing - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # Background / Environment The Background / Environment section controls the visual backdrop and lighting environment of your scene. Here you can set a background color, add a background image, load HDRI environment maps for realistic reflections, and adjust intensity and rotation. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab. It is the first section at the top. ![Background / Environment section](../assets/images/bg-env.webp) --- ## Background ### Color Choose a background color for your scene using the color picker. This color is visible behind your 3D model and in renders. ![Background color picker](../assets/images/bg-env-color.webp) ### Image Upload a custom background image from your computer. This image will be displayed behind the 3D model instead of the solid color. ![Background image settings](../assets/images/bg-env-image.webp) ### Env Map BG When enabled, the Environment Map (HDRI) is also used as the background image. This creates a seamless look where the reflections on the model match the visible background. ### Bg Intensity Controls the brightness of the background. Increase to make the background brighter, decrease to darken it. This only affects the visual background — not the lighting on the model. --- ## Environment Map (HDRI) The Environment Map is an HDRI image that wraps around the entire scene and provides realistic lighting and reflections on your model. This is the primary light source for PBR materials — metals, ceramics, and pearls all react to the environment map. **Changing the HDRI map dramatically changes how your model looks** — different maps produce completely different reflections, highlights, and overall mood. You can load a custom HDRI map by uploading it in this section, or choose from the large library of ready-made HDRI presets on the [left panel](./ui-overview#left-panel-—-presets-quick-settings). The library includes many presets specifically optimized for jewelry rendering — the first preset is designed for metals. ::: tip For creating custom HDRI maps, you can use the [iJewel HDRI Editor](https://editor.hdrmap.com/#) — a dedicated tool for building environment lighting setups from scratch. ::: --- ## Environment Settings
Env Rotation
Rotate the environment map along three axes. Changing the rotation changes where highlights and reflections appear on the model. Also available in Advanced Settings on the left panel
Env Intensity
Controls the brightness of the environment lighting on the model. Reduce to dim the reflections, increase to make them stronger. Also available in Advanced Settings on the left panel
Environment 1
A second environment map slot. Useful when you want different objects in the same scene to use different HDRI maps — for example, a separate environment for pearls
Fixed Env Direction
When enabled, the environment stays fixed while you rotate the model — reflections shift as the model turns. When disabled, the environment rotates together with the model, keeping reflections in the same relative position
::: tip **Env Rotation** and **Env Intensity** are duplicated in the Advanced Settings on the left panel for quick access. Changing the value in one place updates it in the other automatically. ::: --- ## Video Tutorials ### Tutorial: How to Make Pure White and Transparent Background
### Tutorial: How to Change Background & Ground Color
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Ground](./ground)** — Ground plane, shadows, material, and blending - **[Scene Basics](./scene)** — Overview of working with 3D objects - **[UI Overview](./ui-overview)** — Full interface layout including panels - **[Import Scene Settings](./import-scene-settings)** — Import `.vjson` and `.json` scene configuration files - **[Export Scene Settings](./export-scene-settings)** — Export your scene settings for backup or sharing - **[Renderer Settings](./renderer-settings)** — Configure render quality and scale --- # Progressive Shadow Progressive Shadow adds a soft, realistic shadow beneath your model using a directional light. Once enabled, you get full control over the shadow's color, direction, softness, and intensity — making your jewelry renders look more grounded and professional. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Progressive Shadow** section. ![Progressive Shadow section](../assets/images/scene-progressive-shadow.webp) --- ## Enabling Progressive Shadow Check the **Enable** checkbox to activate the Progressive Shadow. A directional light will be created in the scene, and a shadow will appear beneath your model. Uncheck to disable. --- ## Directional Light Settings Once enabled, you can configure the directional light that casts the shadow: ### Visibility & Intensity
Visible
Checkbox — show or hide the directional light helper in the viewport
Intensity
Slider — controls the strength of the directional light
Color
Color picker — choose the color of the shadow. Use darker colors for subtle shadows or try colored shadows for creative effects
### Focus & Spread
Focus
Slider — controls how tight the shadow area is. Higher focus produces a more concentrated shadow beneath the model
Spread
Slider — controls the softness of the shadow edges. Higher spread produces a softer, more diffused shadow
Distance Scale
Slider — adjusts the distance of the light from the model
### Direction & Advanced
Direction
Three inputs (X, Y, Z) — set the direction the light comes from. This changes where the shadow falls relative to the model
Radius
Slider — the radius of the shadow map area
First Stone Size
Slider — size of the first shadow cascade step
Bias
Slider — shadow bias to reduce shadow acne artifacts
Normal Bias
Slider — normal-based bias for further artifact reduction
--- ## Video Tutorial ### How to Create Custom Shadows
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Ground](./ground)** — Ground plane, shadows, material, and blending - **[Scene Basics](./scene)** — Overview of working with 3D objects - **[Background / Environment](./background-environment)** — Background color, HDRI maps, and environment settings - **[UI Overview](./ui-overview)** — Full interface layout including panels - **[Export Scene Settings](./export-scene-settings)** — Export your scene settings including shadow configuration --- # Ground The Ground section controls the floor plane beneath your model. It is responsible for the surface your jewelry sits on, the shadow it casts, and how the ground blends with the background. One of the most important features here is the ability to **disable the ground entirely** — if you want your object to appear floating in space, simply uncheck the Visible checkbox. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Ground** section (the third section from the top). ![Ground section](../assets/images/scene-ground.webp) --- ## Visible Check or uncheck the **Visible** checkbox to show or hide the ground plane. When disabled, the model appears to float — useful for pendants, earrings, or any jewelry that should look suspended rather than resting on a surface. --- ## Ground Settings
Size
Slider — controls the size of the ground plane. Increase for a larger visible floor area
Render to Depth
When enabled, the ground plane blends into the background. This helps create a seamless transition between the floor surface and the background color or image
Limit Camera
Prevents the camera from going below the floor level. When enabled, users cannot rotate the view to see the underside of the ground — keeping the presentation clean and professional
Tone Map
Applies tone mapping to the ground plane
Shadow Frames
Controls the number of frames used for shadow calculation. More frames produce a softer, smoother shadow but take longer to compute
--- ## Height The **Height** slider raises or lowers the ground plane relative to the model. This is one of the most frequently used ground settings — it lets you fine-tune exactly where the floor sits in relation to your jewelry. Lower the ground to create a subtle levitation effect where the model appears to hover slightly above the surface, or raise it to align the floor with a specific part of the model. Small adjustments to height can make a big difference in the overall look of your render. --- ## Randomized Light This subsection controls the directional light that creates the shadow cast onto the ground plane. By adjusting these settings you can fine-tune the shadow's appearance, direction, and softness.
Color
Color picker — sets the color of the shadow light
Intensity
Slider — controls the strength of the light. Higher intensity produces a darker, more visible shadow
Direction
Three inputs (X, Y, Z) — sets the direction the light comes from, which determines where the shadow falls relative to the model
Radius
Slider — the radius of the shadow map area
Bias
Slider — shadow bias to reduce visual artifacts (shadow acne)
Focus
Slider — controls how tight the shadow area is. Higher focus produces a more concentrated shadow beneath the model
Spread
Slider — controls the softness of the shadow edges. Higher spread produces a softer, more diffused shadow
--- ## Physical Material This subsection controls the visual appearance of the ground surface. It uses the same Physical (PBR) Material as regular 3D objects, with all the same properties — Color, Roughness, Metalness, Bump, Normal, Sheen, Clear Coat, Emission, and Reflection. For a detailed description of all material properties, see [PBR Materials](./coming-soon). --- ## Blending The Blending subsection controls how the ground shadow blends with the scene.
Opacity
Slider — controls the transparency of the ground shadow. Lower opacity creates a softer, more subtle shadow. Use this when you want a gentle shadow hint rather than a solid dark shadow beneath the model
--- ## Video Tutorials ### Tutorial: How to Change Background & Ground Color
### Tutorial: How to Create Custom Shadows
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Progressive Shadow](./progressive-shadow)** — Additional directional shadow with focus and spread controls - **[Background / Environment](./background-environment)** — Background color, HDRI maps, and environment settings - **[UI Overview](./ui-overview)** — Full interface layout including panels - **[Export Scene Settings](./export-scene-settings)** — Export your scene settings including ground configuration --- # Gradient SVG The Gradient SVG section lets you create custom gradient backgrounds directly inside iJewel Playground. You choose two colors, adjust the gradient type and angle, and the result is applied as an SVG image to the scene background. This is a quick way to create professional-looking gradient backdrops without any external tools. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Gradient SVG** section. ![Gradient SVG section](../assets/images/scene-gradient-svg.webp) --- ## How It Works The Gradient SVG tool generates an SVG gradient image and places it into the **Image** slot in the [Background / Environment](./background-environment) section. When you enable **Apply to Background**, any changes you make to the gradient are immediately visible in the viewport. To see your gradient in real time, make sure the **Apply to Background** checkbox at the bottom of the section is checked. All changes to colors, angle, and positions will update the background automatically. --- ## Settings
Enabled
Checkbox — enable or disable the Gradient SVG tool
Type
Dropdown — choose the gradient type: Linear (straight gradient from one side to another) or Radial (circular gradient from center outward)
Position 1
Two values — the starting position of the first color stop in the gradient
Position 2
Two values — the ending position of the second color stop in the gradient
Angle
Slider — rotation angle of the gradient in degrees (0–360). Only applies to Linear type
Color 1
Color picker — the first gradient color
Color 2
Color picker — the second gradient color
Apply to Background
Checkbox — when enabled, the generated SVG gradient is automatically applied to the scene background. All changes are visible in real time
Refresh SVG
Button — manually regenerate and apply the SVG gradient
--- ## Removing the Gradient The gradient is stored as an SVG image in the [Background / Environment](./background-environment) → **Image** section. To remove it: 1. Open the **Background / Environment** section (the first section in the Scene tab) 2. Go to the **Image** subsection 3. Click on the image thumbnail and select the rectangular image placeholder from the menu to clear it This will remove the SVG gradient from the background and return to the default background color. --- ## Video Tutorial ### Tutorial: How to Change Background & Ground Color
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Background / Environment](./background-environment)** — Background color, HDRI maps, and environment settings - **[Export Images](./export-images)** — Export your renders including gradient backgrounds - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # HDRi Ground The HDRi Ground section lets you project the current HDRI environment map onto a ground surface, placing your model inside the full HDRI sphere. When enabled, the background and the floor become one continuous HDRI image — your object appears as if it exists inside the real environment captured by the HDRI map. This is a quick way to get a realistic, immersive scene without any additional setup. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **HDRi Ground** section. ::: info HDRi Ground uses whatever HDRI map is currently loaded in the [Background / Environment](./background-environment) section. If no HDRI map is set, enabling HDRi Ground will have no visible effect. ::: --- ## Enabled Check or uncheck the **Enabled** checkbox to toggle the HDRi Ground on or off. When enabled, the HDRI environment map wraps around the scene as a sphere, and the ground becomes part of that sphere — creating a seamless environment where the background and floor are one continuous image. --- ## Settings
World Radius
Controls the size of the HDRI sphere surrounding the scene. A larger radius pushes the environment further away, while a smaller radius brings it closer to the model
Tripod Height
Adjusts the vertical offset of the HDRI projection — similar to the height at which the original HDRI photo was captured. Change this to align the horizon line with your model's ground level
Origin Position (X, Y, Z)
Three inputs that shift the center point of the HDRI sphere in 3D space. Use this to reposition the environment relative to your model if the default alignment doesn't look right
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Background / Environment](./background-environment)** — Set the HDRI map used by HDRi Ground - **[Ground](./ground)** — Standard ground plane with shadow and material options - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # Generate Geometry The Generate Geometry section lets you create basic 3D primitive shapes directly inside iJewel Playground. This is useful when you want to quickly test materials, experiment with lighting setups, or add simple objects to your scene without importing anything from external 3D software. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Generate Geometry** section. --- ## Available Shapes The section provides six buttons, each generating a different primitive shape:
Generate Plane
A flat rectangular surface — useful for floors, walls, or material previews
Generate Sphere
A round shape — great for testing reflections and material properties
Generate Box
A cube — a simple shape for testing materials on flat surfaces and edges
Generate Circle
A flat circular disc
Generate Torus
A donut-shaped ring — particularly useful for previewing ring materials and finishes
Generate Cylinder
A cylindrical tube — good for testing materials on curved and flat surfaces together
Once generated, the shape appears in the scene and in the [Hierarchy](./hierarchy). You can then select it, apply materials, adjust transforms, or use it alongside your imported models. --- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Picking](./picking)** — Select generated objects and apply materials - **[Transform Controls](./transform-controls)** — Move, rotate, and scale generated shapes - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # Cameras (Loaded) The Cameras (Loaded) section displays cameras that were imported with your 3D model file. If you create a camera in your 3D software (such as Blender, 3ds Max, or Cinema 4D) and export it together with the model, that camera will appear here. This is especially useful for creating specific camera paths and animations — you set up the exact camera movement in your 3D software, export it, and then play it back in iJewel Playground. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Cameras (Loaded)** section. ![Cameras (Loaded) section](../assets/images/scene-cameras.webp) ::: info This section will be empty if your model file does not contain any cameras. To use loaded cameras, you need to export cameras from your 3D software together with the model. ::: --- ## How It Works By default, iJewel Playground uses its own viewport camera — the one that lets you orbit, zoom, and pan around the model freely. When you load a model that contains a camera, it appears as an object in this section. You can then **activate** that camera to switch from the default viewport to the imported camera's point of view. ### Tutorial: Creating a Camera Path and Rendering It in Playground This tutorial walks through the full workflow for camera animations: you start by creating a camera path in **Blender** — setting up keyframes, defining the movement curve, and configuring the animation timeline. Then you export the scene (model + camera) as a `.glb` file and import it into **iJewel Playground**. Once loaded, you activate the imported camera and use the export tools to render the final video directly in the browser.
--- ## Camera Properties When you expand a loaded camera, it shows properties similar to a regular object:
Visible
Checkbox — show or hide the camera helper in the viewport
Pick/Focus
Button — zoom the viewport to focus on the camera object
Pick Parent
Button — select the parent object in the hierarchy
Name
Text input — the name of the camera (imported from your 3D software)
Position
Three inputs (X, Y, Z) — the camera's position in the scene
Rotation
Three inputs (X, Y, Z) — the camera's rotation angles
Scale
Three inputs (X, Y, Z) — the camera's scale
Render Order
Controls the rendering order
--- ## Key Actions Below the camera properties, there is an important action button: ![Camera actions — Activate Main](../assets/images/scene-cameras-activate-main.webp)
Activate Main
Switch from the default viewport to this loaded camera. The button changes to Deactivate Main once active. While activated, you can no longer orbit or pan — you see only through this camera
::: tip Playing Camera Animations If your loaded camera has an animation (a camera path created in your 3D software), activate the camera with **Activate Main**, then enable the animation using the **GLTF Animation** controls. The camera will follow the path you defined in your 3D software. To return to the default viewport, click **Deactivate Main**. ::: --- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[UI Overview](./ui-overview)** — Full interface layout including panels - **[Export Videos](./export-videos)** — Export animated video renders using camera paths - **[Import Scene Settings](./import-scene-settings)** — Import scene configurations --- # Cameras (Loaded) The Cameras (Loaded) section displays cameras that were imported with your 3D model file. If you create a camera in your 3D software (such as Blender, 3ds Max, or Cinema 4D) and export it together with the model, that camera will appear here. This is especially useful for creating specific camera paths and animations — you set up the exact camera movement in your 3D software, export it, and then play it back in iJewel Playground. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Cameras (Loaded)** section. ![Cameras (Loaded) section](../assets/images/scene-cameras.webp) ::: info This section will be empty if your model file does not contain any cameras. To use loaded cameras, you need to export cameras from your 3D software together with the model. ::: --- ## How It Works By default, iJewel Playground uses its own viewport camera — the one that lets you orbit, zoom, and pan around the model freely. When you load a model that contains a camera, it appears as an object in this section. You can then **activate** that camera to switch from the default viewport to the imported camera's point of view. ### Tutorial: Creating a Camera Path and Rendering It in Playground This tutorial walks through the full workflow for camera animations: you start by creating a camera path in **Blender** — setting up keyframes, defining the movement curve, and configuring the animation timeline. Then you export the scene (model + camera) as a `.glb` file and import it into **iJewel Playground**. Once loaded, you activate the imported camera and use the export tools to render the final video directly in the browser.
--- ## Camera Properties When you expand a loaded camera, it shows properties similar to a regular object:
Visible
Checkbox — show or hide the camera helper in the viewport
Pick/Focus
Button — zoom the viewport to focus on the camera object
Pick Parent
Button — select the parent object in the hierarchy
Name
Text input — the name of the camera (imported from your 3D software)
Position
Three inputs (X, Y, Z) — the camera's position in the scene
Rotation
Three inputs (X, Y, Z) — the camera's rotation angles
Scale
Three inputs (X, Y, Z) — the camera's scale
Render Order
Controls the rendering order
--- ## Key Actions Below the camera properties, there is an important action button: ![Camera actions — Activate Main](../assets/images/scene-cameras-activate-main.webp)
Activate Main
Switch from the default viewport to this loaded camera. The button changes to Deactivate Main once active. While activated, you can no longer orbit or pan — you see only through this camera
::: tip Playing Camera Animations If your loaded camera has an animation (a camera path created in your 3D software), activate the camera with **Activate Main**, then enable the animation using the **GLTF Animation** controls. The camera will follow the path you defined in your 3D software. To return to the default viewport, click **Deactivate Main**. ::: --- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[UI Overview](./ui-overview)** — Full interface layout including panels - **[Export Videos](./export-videos)** — Export animated video renders using camera paths - **[Import Scene Settings](./import-scene-settings)** — Import scene configurations --- # Coming Soon... --- # Lights The Lights section allows you to add additional light sources to your scene beyond the default environment map (HDRI). While the HDRI map provides the main lighting for realistic jewelry rendering, extra lights can be used to add highlights, colored accents, or dramatic shadow effects. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Lights** section. ![Lights section with four add buttons](../assets/images/lights-buttons.webp) The section provides four buttons to add different types of lights:
Add Directional Light
Parallel light rays from a specific direction — like sunlight. Best for consistent shadows
Add Ambient Light
Uniform light that illuminates all objects equally from all directions — fills in dark areas without casting shadows
Add Point Light
Light that emits from a single point in all directions — like a light bulb. Useful for localized highlights
Add Spot Light
Cone-shaped light that emits from a point in a specific direction — like a flashlight or stage spotlight
You can add multiple lights of the same type — for example, clicking **Add Directional Light** twice will create two separate directional lights, each with its own settings. --- ## Directional Light A directional light simulates a distant light source where all rays are parallel, similar to sunlight. Once added, a **Directional Light** section appears below the buttons with the following settings:
Enabled
Checkbox — turn the light on or off without removing it
Color
Color picker — sets the color of the light
Intensity
Slider — controls the brightness of the light
Rotation
Three inputs (X, Y, Z) — controls the direction the light points
Position
Three inputs (X, Y, Z) — position of the light in the scene
Shadow Enabled
Checkbox — enable or disable shadow casting from this light
Shadow Map Size
Controls the resolution of the shadow map — higher values produce sharper shadows
Shadow Bias
Slider — adjusts shadow bias to reduce shadow acne artifacts
Shadow Normal Bias
Slider — normal-based bias for further artifact reduction
Shadow Radius
Slider — controls the softness of the shadow edges
Shadow First Doom
Advanced shadow rendering parameter
--- ## Ambient Light An ambient light illuminates all objects in the scene equally from all directions. It does not cast shadows and has no position or direction — it simply raises the overall brightness level. ![Ambient Light settings](../assets/images/lights-ambient.webp)
Enabled
Checkbox — turn the light on or off
Color
Color picker — sets the color of the ambient light
Intensity
Slider — controls the brightness of the ambient light
--- ## Point Light A point light emits from a single point in all directions, similar to a light bulb. The light intensity decreases with distance from the source. ![Point Light settings](../assets/images/lights-point.webp)
Enabled
Checkbox — turn the light on or off
Color
Color picker — sets the color of the light
Intensity
Slider — controls the brightness of the light
Distance
Slider — maximum distance the light reaches. Objects beyond this distance are not illuminated
Decay
Slider — how quickly the light dims with distance. Higher values make the light fall off faster
Position
Three inputs (X, Y, Z) — position of the light in the scene
Shadow Enabled
Checkbox — enable or disable shadow casting
Shadow Map Size
Three inputs — resolution of the shadow map
Shadow Bias
Slider — adjusts shadow bias to reduce artifacts
Shadow Radius
Slider — controls the softness of the shadow edges
--- ## Spot Light A spot light emits a cone of light from a point toward a target direction, like a flashlight or stage spotlight. The cone width and edge softness can be controlled. ![Spot Light settings](../assets/images/lights-spot.webp)
Enabled
Checkbox — turn the light on or off
Color
Color picker — sets the color of the light
Intensity
Slider — controls the brightness of the light
Angle
Slider — controls the width of the spotlight cone in degrees
Penumbra
Slider — controls the softness of the spotlight edge. Higher values create a gradual fade at the cone edges
Rotation
Three inputs (X, Y, Z) — controls the direction the spotlight points
Position
Three inputs (X, Y, Z) — position of the light in the scene
Shadow Enabled
Checkbox — enable or disable shadow casting
Shadow Map Size
Two inputs — resolution of the shadow map
Shadow Bias
Slider — adjusts shadow bias to reduce artifacts
Shadow Radius
Slider — controls the softness of the shadow edges
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Background / Environment](./background-environment)** — HDRI environment maps that provide the primary scene lighting - **[Progressive Shadow](./progressive-shadow)** — Soft shadow beneath the model - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # Lights The Lights section allows you to add additional light sources to your scene beyond the default environment map (HDRI). While the HDRI map provides the main lighting for realistic jewelry rendering, extra lights can be used to add highlights, colored accents, or dramatic shadow effects. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the SceneScene tab, in the **Lights** section. ![Lights section with four add buttons](../assets/images/lights-buttons.webp) The section provides four buttons to add different types of lights:
Add Directional Light
Parallel light rays from a specific direction — like sunlight. Best for consistent shadows
Add Ambient Light
Uniform light that illuminates all objects equally from all directions — fills in dark areas without casting shadows
Add Point Light
Light that emits from a single point in all directions — like a light bulb. Useful for localized highlights
Add Spot Light
Cone-shaped light that emits from a point in a specific direction — like a flashlight or stage spotlight
You can add multiple lights of the same type — for example, clicking **Add Directional Light** twice will create two separate directional lights, each with its own settings. --- ## Directional Light A directional light simulates a distant light source where all rays are parallel, similar to sunlight. Once added, a **Directional Light** section appears below the buttons with the following settings:
Enabled
Checkbox — turn the light on or off without removing it
Color
Color picker — sets the color of the light
Intensity
Slider — controls the brightness of the light
Rotation
Three inputs (X, Y, Z) — controls the direction the light points
Position
Three inputs (X, Y, Z) — position of the light in the scene
Shadow Enabled
Checkbox — enable or disable shadow casting from this light
Shadow Map Size
Controls the resolution of the shadow map — higher values produce sharper shadows
Shadow Bias
Slider — adjusts shadow bias to reduce shadow acne artifacts
Shadow Normal Bias
Slider — normal-based bias for further artifact reduction
Shadow Radius
Slider — controls the softness of the shadow edges
Shadow First Doom
Advanced shadow rendering parameter
--- ## Ambient Light An ambient light illuminates all objects in the scene equally from all directions. It does not cast shadows and has no position or direction — it simply raises the overall brightness level. ![Ambient Light settings](../assets/images/lights-ambient.webp)
Enabled
Checkbox — turn the light on or off
Color
Color picker — sets the color of the ambient light
Intensity
Slider — controls the brightness of the ambient light
--- ## Point Light A point light emits from a single point in all directions, similar to a light bulb. The light intensity decreases with distance from the source. ![Point Light settings](../assets/images/lights-point.webp)
Enabled
Checkbox — turn the light on or off
Color
Color picker — sets the color of the light
Intensity
Slider — controls the brightness of the light
Distance
Slider — maximum distance the light reaches. Objects beyond this distance are not illuminated
Decay
Slider — how quickly the light dims with distance. Higher values make the light fall off faster
Position
Three inputs (X, Y, Z) — position of the light in the scene
Shadow Enabled
Checkbox — enable or disable shadow casting
Shadow Map Size
Three inputs — resolution of the shadow map
Shadow Bias
Slider — adjusts shadow bias to reduce artifacts
Shadow Radius
Slider — controls the softness of the shadow edges
--- ## Spot Light A spot light emits a cone of light from a point toward a target direction, like a flashlight or stage spotlight. The cone width and edge softness can be controlled. ![Spot Light settings](../assets/images/lights-spot.webp)
Enabled
Checkbox — turn the light on or off
Color
Color picker — sets the color of the light
Intensity
Slider — controls the brightness of the light
Angle
Slider — controls the width of the spotlight cone in degrees
Penumbra
Slider — controls the softness of the spotlight edge. Higher values create a gradual fade at the cone edges
Rotation
Three inputs (X, Y, Z) — controls the direction the spotlight points
Position
Three inputs (X, Y, Z) — position of the light in the scene
Shadow Enabled
Checkbox — enable or disable shadow casting
Shadow Map Size
Two inputs — resolution of the shadow map
Shadow Bias
Slider — adjusts shadow bias to reduce artifacts
Shadow Radius
Slider — controls the softness of the shadow edges
--- ## Related Pages - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Background / Environment](./background-environment)** — HDRI environment maps that provide the primary scene lighting - **[Progressive Shadow](./progressive-shadow)** — Soft shadow beneath the model - **[UI Overview](./ui-overview)** — Full interface layout including panels --- # Coming Soon... --- # Coming Soon... --- # Coming Soon... --- # Anti-aliasing Anti-aliasing smooths out jagged edges (also called "stair-stepping" or "aliasing") on your 3D model and scene, producing cleaner, more photorealistic renders. In iJewel Playground, anti-aliasing is split into three independent sections — **Progressive**, **Temporal AA**, and **Velocity Buffer (TAA)** — each designed for a different rendering scenario. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), accessible via the Anti-aliasingAnti-aliasing tab. --- ## How the Three Sections Work Together Each anti-aliasing method targets a specific use case:
Progressive
Multi-frame accumulation for still images. The renderer takes multiple samples over time and averages them to eliminate aliasing. Best for final image exports where you can wait a few seconds for the render to converge. Read more →
Temporal AA
Real-time anti-aliasing for interactive use and animations. Blends the current frame with previous frames to smooth edges while you rotate, zoom, or play animations. Keeps the viewport clean without the wait time of Progressive. Read more →
Velocity Buffer (TAA)
Motion-aware temporal anti-aliasing that uses per-pixel velocity data to reduce ghosting artifacts when objects or the camera move. An advanced complement to Temporal AA for scenes with animation. Read more →
--- ## Quick Guide: Which Setting to Use ::: tip For Still Image Exports Increase the **Progressive → Frame count** to 16, 32, or higher. The more frames, the smoother the result — but the longer the render takes. This is the single most impactful setting for image quality. ::: ::: tip For Real-Time Viewport & Video Recording Enable **Temporal AA** and keep the default **Feedback** values (0.88 / 0.97). This gives you smooth edges in the viewport and during video export without a long convergence wait. If you see ghosting on moving objects, enable **Velocity Buffer (TAA)**. ::: ::: tip For Fast Previews Lower the **Progressive → Frame count** to 4 or 8 for quicker convergence. You can also disable Progressive entirely and rely on Temporal AA alone for a responsive viewport. ::: ::: warning Performance Note Higher Progressive frame counts significantly increase export time — especially for video. If your video export takes 10+ minutes, try reducing Progressive frames to 4–8 and relying on Temporal AA instead. See the [FAQ on video export speed](./faq-export) for more tips. ::: --- ## Documentation Pages
Progressive Multi-frame accumulation — Frame count & Jitter Temporal AA Real-time anti-aliasing — Feedback & Stable Noise Velocity Buffer (TAA) Motion-aware anti-aliasing to reduce ghosting
--- ## Related Pages - **[Renderer Settings](./renderer-settings)** — Resolution and quality configuration - **[Export Images](./export-images)** — Image export settings and quality tips - **[Export Videos](./export-videos)** — Video export settings - **[FAQ: Rendering & Performance](./faq-rendering)** — Common rendering questions --- # Progressive Progressive anti-aliasing works by rendering multiple frames of the same view and accumulating (averaging) them together. Each frame uses a slightly different sub-pixel offset, so fine details and edges are sampled at many positions — the result is a smooth, high-quality image with no jagged edges. This is the primary quality setting for **still image exports**. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Anti-aliasingAnti-aliasing tab, in the **Progressive** section. Progressive anti-aliasing settings --- ## How It Works When the scene is idle (no camera movement, no animation playing), Playground begins accumulating frames in the background. You'll notice the image gradually becomes sharper and smoother over a few seconds — this is the progressive render converging. Once the set number of frames has been reached, the image is fully resolved. Any interaction (rotating, zooming, panning) resets the accumulation and it starts over. This is normal — Progressive is designed for the **final still result**, not for real-time interaction. --- ## Settings
Frame count
The number of frames to accumulate before the render is considered complete. Higher values produce smoother results but take longer. Default is 32. Common values: 4–8 for fast previews, 16–32 for high-quality exports, 64+ for maximum quality
Jitter
When enabled, each accumulated frame uses a slightly randomized sub-pixel offset. This prevents structured aliasing patterns and produces a more natural, film-like anti-aliasing. Enabled by default — recommended to keep it on
--- ## Recommended Values
Quick preview
Frame count: 4–8. Fast convergence, good enough for checking composition and lighting
Image export
Frame count: 16–32. Good balance of quality and speed for final renders
Video export
Frame count: 4–8. Each video frame must converge separately, so high values dramatically increase render time. For video, rely on Temporal AA for smoothing between frames
Maximum quality
Frame count: 64+. Use for hero shots or print-quality renders where every pixel matters
::: warning Export Time Progressive frame count is the **biggest factor** in video export duration. If your turntable export takes 10+ minutes, reducing frames from 32 to 4–8 can cut the time by 75% or more while still producing smooth results (especially when combined with Temporal AA). ::: --- ## Related Pages - **[Anti-aliasing](./anti-aliasing)** — Overview of all anti-aliasing sections - **[Temporal AA](./anti-aliasing-temporal)** — Real-time temporal anti-aliasing - **[Velocity Buffer (TAA)](./anti-aliasing-velocity-buffer)** — Motion-aware anti-aliasing - **[Export Images](./export-images)** — Image export settings - **[Export Videos](./export-videos)** — Video export settings --- # Temporal AA Temporal Anti-Aliasing (TAA) is a real-time anti-aliasing technique that blends the **current frame with previous frames** to smooth out edges and reduce flickering. Unlike Progressive (which accumulates many frames while the scene is still), Temporal AA works **continuously** — even while you rotate, zoom, or play animations — making it the primary anti-aliasing method for interactive use and video recording. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Anti-aliasingAnti-aliasing tab, in the **Temporal AA** section. Temporal AA settings --- ## How It Works Each rendered frame is compared to the previous frame. Pixels that haven't changed much are blended together (using the **Feedback** values), which smooths out aliasing and reduces temporal flickering — the shimmering you sometimes see on thin edges or detailed geometry when the camera moves. The trade-off is **ghosting**: if the feedback is too high, moving objects can leave faint trails because the renderer holds on to old frame data too long. The Feedback parameters let you control this balance. --- ## Settings
Enabled
Toggles Temporal AA on or off. When enabled, the renderer blends consecutive frames to reduce aliasing in real time. Recommended to keep enabled for interactive work and video exports
Feedback
Two values that control how much of the previous frame is blended into the current frame. The first value (0.88 by default) controls the blending weight for most pixels. The second value (0.97 by default) controls the blending for high-confidence pixels. Higher values produce smoother results but increase ghosting on moving objects. Lower values reduce ghosting but allow more aliasing/flickering
Stable Noise
(Use Total Frame Count)
When enabled, the noise pattern used for rendering effects (like screen-space reflections and ambient occlusion) is tied to the total accumulated frame count rather than being re-randomized each frame. This produces more stable, consistent noise that Temporal AA can smooth out more effectively — reducing the "crawling" noise artifacts you may see on metallic or glossy surfaces
--- ## Feedback Values Explained The two Feedback numbers work together to balance smoothness and responsiveness:
First value (0.88)
General blending factor. At 0.88, each new frame contributes about 12% new data while 88% comes from the history buffer. Lowering this (e.g., to 0.5–0.7) makes the image more responsive but noisier. Raising it (e.g., to 0.95) makes it smoother but increases ghosting
Second value (0.97)
High-confidence blending factor applied to pixels where the renderer is very sure the data is correct (no disocclusion, no major change). This higher value allows those stable areas to accumulate more temporal data for maximum smoothness
::: tip Default Values The defaults (**0.88 / 0.97**) are well-tuned for jewelry rendering. In most cases, you don't need to change them. Only adjust if you notice ghosting on animated objects (lower the values) or flickering on still surfaces (raise the values). ::: --- ## When to Use Temporal AA Temporal AA is most useful when: - You're **interacting** with the scene (rotating, zooming) and want smooth edges in real time - You're **recording video** — Temporal AA provides frame-to-frame smoothing that Progressive can't offer during animation - You're working with **screen-space effects** (SSR, SSAO, SSGI) that produce per-frame noise — TAA smooths this noise over time - You want a **responsive viewport** without waiting for Progressive to converge ::: info Temporal AA + Progressive These two methods are complementary. Progressive accumulates frames when the scene is still; Temporal AA blends frames in real time during motion. For the best quality, keep both enabled — Progressive handles the final still render, and Temporal AA handles everything in between. ::: --- ## Related Pages - **[Anti-aliasing](./anti-aliasing)** — Overview of all anti-aliasing sections - **[Progressive](./anti-aliasing-progressive)** — Multi-frame accumulation for still images - **[Velocity Buffer (TAA)](./anti-aliasing-velocity-buffer)** — Motion-aware anti-aliasing - **[Export Videos](./export-videos)** — Video export settings --- # Velocity Buffer (TAA) The Velocity Buffer is an advanced extension of Temporal AA that uses **per-pixel motion vectors** to improve anti-aliasing quality during camera movement and object animation. When enabled, the renderer tracks how each pixel has moved between frames, allowing Temporal AA to correctly reproject previous frame data and avoid ghosting artifacts. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Anti-aliasingAnti-aliasing tab, in the **Velocity Buffer (TAA)** section. Velocity Buffer TAA settings --- ## How It Works Without a velocity buffer, Temporal AA assumes that each pixel in the current frame corresponds to the same screen position in the previous frame. This works well when the scene is still, but during camera rotation or object animation, pixels shift — and the old frame data at that position is no longer valid. This mismatch causes **ghosting** (faint trails behind moving edges). The Velocity Buffer solves this by computing a **motion vector** for every pixel — a 2D offset describing where that pixel was in the previous frame. Temporal AA then uses these vectors to look up the correct historical data, producing clean anti-aliasing even during motion. --- ## Settings
Enabled
Toggles the Velocity Buffer on or off. When enabled, the renderer generates per-pixel motion vectors each frame, which Temporal AA uses for motion-compensated reprojection. This reduces ghosting during camera movement and object animation
--- ## When to Enable It The Velocity Buffer adds a small amount of GPU overhead because it renders an extra pass per frame. For most jewelry rendering workflows, here's when to use it: ::: tip Enable When - You're **recording turntable videos** or camera path animations — the velocity buffer prevents ghosting on edges as the camera moves - You have **animated objects** in the scene (e.g., a pendant swing, rotating display stand) - You notice **ghosting or trailing artifacts** on edges during camera rotation with Temporal AA enabled ::: ::: info Can Be Left Disabled When - You're only working with **still images** — Progressive handles anti-aliasing for stills, and no motion occurs - Your scene has **no animations** and you're fine with minor ghosting during viewport interaction - You're on a **lower-end GPU** and want to save performance for other effects ::: --- ## Velocity Buffer + Temporal AA The Velocity Buffer is not a standalone anti-aliasing method — it enhances **Temporal AA** by providing motion data. For it to have any effect, **Temporal AA must also be enabled**. If Temporal AA is disabled, enabling the Velocity Buffer alone will have no visible impact. The typical setup for animated scenes is: 1. **Temporal AA** → Enabled (with default Feedback values) 2. **Velocity Buffer (TAA)** → Enabled 3. **Progressive** → Frame count 4–8 (for each video frame to converge quickly) This combination gives you smooth, ghost-free anti-aliasing during animation with minimal render overhead. --- ## Related Pages - **[Anti-aliasing](./anti-aliasing)** — Overview of all anti-aliasing sections - **[Progressive](./anti-aliasing-progressive)** — Multi-frame accumulation for still images - **[Temporal AA](./anti-aliasing-temporal)** — Real-time temporal anti-aliasing - **[Export Videos](./export-videos)** — Video export settings --- # Post Processing Post Processing effects are applied after the 3D scene is rendered, adjusting the final image appearance — color grading, reflections, edge highlights, lens effects, and more. These settings let you fine-tune the visual style of your jewelry renders without changing the scene itself. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), accessible via the Post ProcessingPost Processing tab. Post Processing tab overview --- ## Sections
Screen Space Reflections (SSR) Real-time reflections on glossy and metallic surfaces Tonemapping Exposure, contrast, saturation, and color mapping modes Outline Selection highlight and object outline settings Chromatic Aberration Lens color fringing effect for a cinematic look Filmic Grain Analog film grain noise for a warmer, organic feel Look Up Tables (LUT) Custom color grading presets via .cube files Vignette Darkened edges for a focused center look Depth of Field Selective focus with background blur Screen Space Ambient Occlusion (SSAO) Contact shadows in crevices — enabled by default Screen Space Bevel Edge softening without modifying geometry Bloom Glow effect around bright areas Screen Space Global Illumination (SSGI) Indirect light bouncing between surfaces Screen Space Contact Shadows Fine shadows between close surfaces
--- ## Related Pages - **[Anti-aliasing](./anti-aliasing)** — Progressive, Temporal AA, and Velocity Buffer settings - **[Renderer Settings](./renderer-settings)** — Resolution and quality configuration - **[Export Images](./export-images)** — Image export settings - **[Export Videos](./export-videos)** — Video export settings --- # Screen Space Reflections (SSR) Screen Space Reflections adds real-time reflections of the surrounding environment onto your 3D objects. This is especially visible on metallic surfaces — polished gold, silver, and platinum will reflect the ground, nearby objects, and the environment, making the render look more realistic and grounded. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab. It is the first section at the top. Screen Space Reflections settings ::: info SSR can only reflect what is currently visible on screen. Off-screen objects fall back to environment map reflections. ::: --- ## Settings
Enabled
Checkbox — toggles SSR on or off
Intensity
Slider — overall strength of reflections. Default 1.00
Boost
Three values (RGB) — per-channel reflection intensity boost. Default 1.00 / 1.00 / 1.00
Object Radius
Slider — maximum ray travel distance. Default 1.00
Auto Radius
Checkbox — automatically calculates optimal radius based on scene size. Recommended to keep enabled
Power
Slider — reflection falloff curve. Higher = sharper falloff at grazing angles. Default 1.10
Tolerance
Slider — depth matching precision. Higher = fewer gaps but potential artifacts. Default 0.50
Step Count
Slider — ray marching steps. More steps = more accurate but slower. Default 16
Low Quality Frames
Slider — number of lower-quality frames during camera movement for better responsiveness. Default 0
Ignore Front Rays
Checkbox — ignores camera-facing rays to prevent self-reflection artifacts. Enabled by default
Mask Front Rays Factor
Slider — masking strength for front-facing rays. Default -0.20
::: tip Default values work well for most jewelry. For stronger ground reflections on polished bands, increase **Intensity** to 1.2–1.5. If reflections have gaps, increase **Step Count** to 24–32. ::: --- ## Related Pages - **[Tonemapping](./tonemapping)** — Exposure, contrast, saturation, and background clipping - **[Background / Environment](./background-environment)** — HDRI environment maps and reflections - **[Renderer Settings](./renderer-settings)** — Resolution and quality configuration - **[FAQ: Rendering & Performance](./faq-rendering)** — Common rendering questions --- # Tonemapping Tonemapping controls color grading of the final render — exposure, saturation, and contrast. Small adjustments here can dramatically improve the look of your jewelry. This section also contains **Clip Background**, the key setting for transparent background exports. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Tonemapping** section. Tonemapping settings --- ## Mode The **Mode** dropdown selects the tonemapping algorithm. Each mode produces a different color response.
ACESFilmic
Default. Cinematic colors with natural highlight rolloff. Recommended for most jewelry renders
Linear
No tonemapping — raw HDR values. Useful for post-production color grading
Reinhard
Classic curve — softer, less contrasty than ACES
Cineon
Kodak film response — warm, slightly desaturated analog film look
Uncharted 2
Filmic curve — good balance between contrast and highlight detail
AgX
Modern approach — handles bright saturated areas better than ACES, prevents color burn-out
--- ## Settings
Tonemap Background
Checkbox — applies tonemapping to the background as well. When off, only the 3D model is affected
Clip Background
Key setting for transparent exports. Removes the background and sets alpha to 0 — export as PNG to get a transparent image
Exposure
Slider — overall brightness. Default 1.00
Saturation
Slider — color intensity. Increase for more vivid rose gold or colored gemstones. Default 1.00
Contrast
Slider — difference between light and dark areas. A common adjustment is bumping this to 1.01–1.05 for a more polished look. Default 1.00
Render Depth
Checkbox — shows a black-and-white depth visualization instead of the color render. Useful for previewing Depth of Field ranges or creating depth maps for compositing
::: tip Transparent Background Enable **Clip Background**, disable **Scene → Ground → Visible** and **Progressive Shadow**, then export as **PNG**. Watch the [How to Make Pure White and Transparent Background](https://www.youtube.com/watch?v=GCJIOmcEaPo) tutorial. ::: --- ## Related Pages - **[Screen Space Reflections](./screen-space-reflections)** — SSR settings for realistic reflections - **[Background / Environment](./background-environment)** — Background color, HDRI maps, and environment settings - **[Export Images](./export-images)** — Image export with quality and format settings - **[Ground](./ground)** — Ground plane visibility and shadow settings - **[FAQ: Scene, Lighting & Environment](./faq-scene)** — Common scene setup questions --- # Outline Outline controls the selection highlight that appears around objects when you click on them in the viewport. By default, clicking an object draws a colored border around it. Here you can change the outline color, intensity, or disable it entirely. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Outline** section. Outline settings --- ## How It Works When you select an object in the viewport, Playground draws a colored outline along its edges so you can see what is selected. If you **disable** the outline, selecting still works — you just won't see the colored border. --- ## Settings
Enable
Checkbox — toggles the outline on or off. When disabled, objects are still selectable but without the colored border
Highlight
Checkbox — when enabled, the entire area of the selected object is filled with the outline color, not just the border. Use Transparency to control how visible this fill is
Intensity
Slider — controls how strong/visible the outline color is. Default 2.00
Transparency
Slider — controls the opacity of the highlight fill when Highlight is enabled. Lower values make the fill more see-through. Default 1.00
Color
Color picker — choose the outline color. Change this if you prefer a different selection color for your workflow. Default is orange (0xf36c00)
::: tip If the default orange outline is hard to see against your scene, try switching to a brighter color like white or cyan. ::: --- ## Related Pages - **[Picking](./picking)** — Selecting objects in the viewport - **[Transform Controls](./transform-controls)** — Move, rotate, and scale selected objects - **[Screen Space Reflections](./screen-space-reflections)** — SSR post-processing effect - **[Tonemapping](./tonemapping)** — Color grading and background clipping --- # Chromatic Aberration Chromatic Aberration adds a subtle color fringing effect around the edges of the image, simulating the way real camera lenses separate light into RGB channels. This gives the render a more photographic, cinematic feel — especially noticeable at the edges of the frame. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Chromatic Aberration** section. Chromatic Aberration settings --- ## Settings
Enable
Checkbox — toggles the chromatic aberration effect on or off
Intensity
Slider — controls the strength of the color fringing. Keep it low (around 0.05–0.15) for a subtle photographic touch. Higher values create a more dramatic, stylized effect. Default 0.10
::: tip A little goes a long way — values around 0.05–0.10 add a subtle realism without making the image look distorted. This effect is most visible at the edges of the frame and on high-contrast areas like diamond facets against a dark background. ::: --- ## Related Pages - **[Tonemapping](./tonemapping)** — Color grading and background clipping - **[Screen Space Reflections](./screen-space-reflections)** — SSR post-processing effect - **[Outline](./outline)** — Selection highlight settings - **[Export Images](./export-images)** — Image export settings --- # Filmic Grain Filmic Grain adds a subtle noise texture over the render, simulating the grain you see in analog film photography. This gives the image a warmer, more organic feel — useful for lifestyle product shots or when you want to move away from a perfectly clean digital look. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Filmic Grain** section. Filmic Grain settings --- ## Settings
Enable
Checkbox — toggles the filmic grain effect on or off
Multiply
Checkbox — when enabled, the grain is blended using multiply mode, which darkens the image slightly and makes the grain more visible in bright areas
Intensity
Slider — controls how strong the grain effect is. Keep it low for a subtle film look, increase for a more stylized vintage feel
--- ## Related Pages - **[Tonemapping](./tonemapping)** — Color grading and exposure adjustments - **[Chromatic Aberration](./chromatic-aberration)** — Lens color fringing effect - **[Look Up Tables (LUT)](./lut)** — Custom color grading presets - **[Export Images](./export-images)** — Image export settings --- # Look Up Tables (LUT) LUT (Look Up Table) lets you apply custom color grading presets to your render. You can create a `.cube` LUT file in Photoshop (or any other color grading software) with your preferred adjustments — curves, levels, color balance, contrast — and then import it into Playground to apply that same look to your jewelry renders. This is a powerful way to achieve a consistent, cinematic color style across all your exports. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Look Up Tables (LUT)** section. Look Up Tables LUT settings --- ## How It Works 1. Export a snapshot of your scene from Playground 2. Open it in Photoshop and adjust curves, levels, filters — any color grading you want 3. Save the adjustments as a `.cube` LUT file 4. Import the `.cube` file into Playground via the LUT section 5. The color grading is applied to the entire render in real time You can apply LUTs globally or to specific parts of the scene (metals, diamonds, ground) using the separate LUT input slots. --- ## Settings
Enable
Checkbox — toggles the LUT effect on or off
LUT Background
Checkbox — when enabled, the LUT is also applied to the background. When disabled, only the 3D model is color-graded
Intensity
Slider — controls the strength of the LUT effect. At 1.0 the LUT is fully applied, at 0 it has no effect. Use intermediate values to blend between the original and graded look
LUT
Input — the main LUT slot. Upload a .cube file to apply your color grading preset to the entire render
LUT 1
Input — additional LUT slot for applying a different color grading to specific materials
LUT 2
Input — additional LUT slot for applying a different color grading to specific materials
--- ## Video Tutorial ### Tutorial: How to Create and Apply Custom LUTs in iJewel Playground
--- ## Related Pages - **[Tonemapping](./tonemapping)** — Exposure, contrast, saturation, and background clipping - **[Filmic Grain](./film-grain)** — Analog film grain effect - **[Chromatic Aberration](./chromatic-aberration)** — Lens color fringing effect - **[Export Images](./export-images)** — Image export settings --- # Vignette Vignette darkens or tints the edges of the render, drawing the viewer's eye toward the center of the image. This is one of the most commonly used cinematic effects — it subtly frames the jewelry and keeps the focus on the product. Use it for lifestyle-style product shots, social media content, or any render where you want a polished, editorial look. With the color picker, you can go beyond the classic dark vignette — try warm tones for a golden-hour feel, or cool tones for a modern, icy aesthetic. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Vignette** section. Vignette settings --- ## Settings
Enable
Checkbox — toggles the vignette effect on or off
Power
Slider — controls the strength and spread of the vignette. Higher values create a more pronounced darkening at the edges
Color
Color picker — sets the vignette color. Default is black, but you can choose any color for a stylized look
--- ## Related Pages - **[Tonemapping](./tonemapping)** — Exposure, contrast, and color grading - **[Filmic Grain](./film-grain)** — Analog film grain effect - **[Chromatic Aberration](./chromatic-aberration)** — Lens color fringing effect --- # Depth of Field Depth of Field creates a blur effect that simulates how a real camera lens focuses — objects at the focal point stay sharp while everything closer or further away becomes blurred. This effect is especially useful for close-up product shots where you want to highlight a specific detail — like a gemstone setting, an engraving, or the front face of a ring — while softly blurring the rest. It adds a professional, photographic quality to your renders and works great for hero images and marketing materials. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Depth of Field** section. Depth of Field settings --- ## How to Set the Focus Point 1. Enable **Enable Edit** checkbox in the Depth of Field section 2. Click directly on the object in the canvas where you want the focus to be — the focal point is set automatically 3. Once the focus is set, disable **Enable Edit** to return to normal object selection on the canvas
--- ## Settings
Enable
Checkbox — toggles the depth of field effect on or off
Depth Range
Slider — controls the range of the in-focus zone. A smaller range means a narrower area stays sharp
Near Blur Scale
Slider — controls how strong the blur is for objects closer to the camera than the focal point
Far Blur Scale
Slider — controls how strong the blur is for objects further from the camera than the focal point
Enable Edit
Checkbox — when enabled, click on the canvas to set the focal point. Disable after setting focus to resume normal object selection
--- ## Related Pages - **[Screen Space Reflections (SSR)](./screen-space-reflections)** — Real-time reflections - **[Tonemapping](./tonemapping)** — Exposure and color grading - **[Bloom](./bloom)** — Glow effect around bright areas --- # Screen Space Ambient Occlusion (SSAO) SSAO adds soft contact shadows in crevices, corners, and where surfaces meet — making the scene look more realistic and grounded. It is **enabled by default** in Playground. This effect is essential for jewelry renders because it brings out the depth between prongs, around stone settings, inside chain links, and along any tight geometry. Without SSAO, models can look flat — with it, you get a natural sense of volume and contact between surfaces. For most cases, the main settings you need are **Intensity** and **Radius**. If you're unsure about the other options, enable **Auto Radius** and just adjust **Intensity**. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **SS Ambient Occlusion** section. SS Ambient Occlusion settings --- ## Settings
Enable
Checkbox — toggles SSAO on or off. Enabled by default
Enable Cavity
Checkbox — enables cavity occlusion, which adds extra detail shadows in fine surface crevices
Cavity Brightness
Slider — adjusts the brightness of cavity shadows
Intensity
Slider — controls how strong the ambient occlusion effect is. Default: 0.25
Radius
Slider — sets the sampling radius for occlusion. Larger radius = wider, softer shadows. Default: 1.0
Bias
Slider — offsets the occlusion calculation to reduce self-shadowing artifacts
Fall-Off
Slider — controls how quickly the occlusion fades with distance
Num Samples
Slider — number of sampling points per pixel. More samples = smoother result but slower performance
Smooth Enabled
Checkbox — applies smoothing to the occlusion result for a softer look
Auto Radius
Checkbox — automatically calculates the optimal radius based on the scene. Enable this if you're unsure about manual radius settings
H Sharpness
Number input — controls the sharpness of the occlusion edges
::: tip Quick Setup Enable **Auto Radius** and adjust **Intensity** — this is the simplest way to get good SSAO results without tweaking individual settings. ::: --- ## Related Pages - **[Screen Space Bevel](./screen-space-bevel)** — Edge softening effect - **[Screen Space Reflections (SSR)](./screen-space-reflections)** — Real-time reflections - **[Tonemapping](./tonemapping)** — Exposure and color grading --- # Screen Space Bevel Screen Space Bevel (SSB) softens sharp edges on 3D models without modifying the geometry. This makes edges look more realistic by adding a subtle bevel/rounding effect in the render. In real life, jewelry never has perfectly sharp edges — even precision-machined metal has slight rounding. SSB simulates this, making your renders look more natural and physically accurate. It's particularly noticeable on ring bands, bezels, and prong tips where sharp CG edges would otherwise look unrealistic. The SSB setting in Post Processing controls the effect globally — disabling it here turns off SSB for all materials in the scene. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Screen Space Bevel** section. Screen Space Bevel settings ### Before / After
Without SS Bevel
With SS Bevel
⇔
Before
After
--- ## Settings
Enable
Checkbox — toggles the global SSB effect on or off. Disabling this turns off SSB for all materials
SS Bevel
Checkbox — enables the screen-space bevel calculation
SS Bevel Radius
Slider — controls how wide the bevel effect is on edges. Higher values create a more visible edge rounding
--- ## SSB in Other Locations SSB can also be configured per material and at the scene level: - **Per material** — When you select an object via Picking, the material settings include an **SSB** section with its own **Radius** slider. This lets you control the bevel strength for individual materials separately. - **Left panel → Advanced → Plugins** — Contains an **SSB** checkbox and **SSB Intensity** slider that act as scene-wide overrides. --- ## Related Pages - **[Screen Space Ambient Occlusion (SSAO)](./ssao)** — Contact shadows in crevices - **[Screen Space Reflections (SSR)](./screen-space-reflections)** — Real-time reflections - **[Outline](./outline)** — Selection highlight settings --- # Bloom Bloom adds a glow effect around bright areas of the render, simulating how intense light bleeds in a camera lens. This effect is especially powerful for diamond and gemstone jewelry — it makes bright reflections and sparkles appear to radiate light, just like they do in real photography. Use it to enhance the brilliance of stones, create dramatic hero shots, or add a luxurious feel to your renders. A subtle bloom can make the difference between a flat-looking render and one that feels alive with light. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Bloom** section. Bloom settings ### Before / After
Without Bloom
With Bloom
⇔
Before
After
--- ## Settings
Enable
Checkbox — toggles the bloom effect on or off
Threshold
Slider — brightness threshold above which bloom is applied. Only pixels brighter than this value will glow
Soft Threshold
Slider — softens the threshold transition so bloom fades in gradually rather than appearing abruptly
Intensity
Slider — controls how strong the bloom glow is
Interference
Slider — adds a color interference pattern to the bloom for a more complex optical effect
Radius
Slider — controls how far the bloom glow spreads from bright areas
Power
Slider — adjusts the falloff curve of the bloom. Higher values concentrate the glow closer to bright areas
Debug
Checkbox — shows a debug view where the screen turns black and only the bloom-affected areas are visible. Use this to see exactly where bloom appears and adjust settings accordingly. Disable when done
::: tip Using Debug Mode Enable **Debug** to see exactly where bloom is appearing — the screen goes black and only glowing areas are shown. Adjust **Intensity**, **Radius**, and **Threshold** until the bloom looks right, then disable **Debug** to see the final result. ::: --- ## Related Pages - **[Depth of Field](./depth-of-field)** — Selective focus with background blur - **[Tonemapping](./tonemapping)** — Exposure and color grading - **[Screen Space Reflections (SSR)](./screen-space-reflections)** — Real-time reflections --- # Screen Space Global Illumination (SSGI) Screen Space Global Illumination simulates light bouncing between surfaces — for example, a gold ring casting a warm glow onto a white surface. This brings out subtle color interactions between metals, gemstones, and the ground, making jewelry renders feel more natural and cohesive. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **SS Global Illumination** section. SS Global Illumination settings --- ## Settings
Enable
checkbox
Toggles the SSGI effect on or off
Intensity
slider
How strong the indirect lighting effect is
Power
slider
Falloff curve — higher values concentrate the effect closer to surfaces
Auto Radius
checkbox
Automatically calculates the optimal sampling radius
Object Radius
slider
How far indirect light can travel between surfaces
Tolerance
slider
Depth tolerance for ray matching — reduces artifacts on thin geometry
Bias
slider
Offsets ray origin to reduce self-illumination artifacts
Fall-Off
slider
How quickly the indirect lighting fades with distance
Ray Count
slider
Rays per pixel — more rays = smoother result but slower
Step Count
slider
Steps per ray — more steps = more precise tracing
Smooth Enabled
checkbox
Smooths the GI result for a softer, less noisy look
Render In Camera
checkbox
Calculates GI from the camera's perspective
GI Enabled
checkbox
Toggles the GI calculation independently from the main Enable
--- ## Related Pages - **[Screen Space Ambient Occlusion (SSAO)](./ssao)** — Contact shadows in crevices - **[Screen Space Contact Shadows](./screen-space-contact-shadows)** — Fine shadows between close surfaces - **[Screen Space Reflections (SSR)](./screen-space-reflections)** — Real-time reflections - **[Tonemapping](./tonemapping)** — Exposure and color grading --- # Screen Space Contact Shadows Screen Space Contact Shadows add fine shadows where surfaces meet or nearly touch — prongs on a stone, a ring band on a surface, chain links against each other. These micro-shadows make jewelry look grounded and physically present. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the Post ProcessingPost Processing tab, in the **Screen Space Contact Shadows** section. Screen Space Contact Shadows settings --- ## Settings
Enable
checkbox
Toggles Screen Space Contact Shadows on or off
Radius
slider
Max distance for contact shadows — keep small for realistic results
Intensity
slider
How dark the contact shadows are
Tolerance
slider
Depth comparison tolerance — reduces false shadows on flat surfaces
Debug Only SSCS
checkbox
Shows only contact shadows — use to fine-tune, then disable
Step Count
slider
Ray marching steps — more steps = more precise but slower
::: tip Using Debug Mode Enable **Debug Only SSCS** to isolate and visualize just the contact shadows. This makes it easy to see where shadows are appearing and adjust **Radius**, **Intensity**, and **Step Count** before disabling debug to see the full render. ::: --- ## Related Pages - **[Screen Space Ambient Occlusion (SSAO)](./ssao)** — Ambient occlusion in crevices - **[Screen Space Global Illumination (SSGI)](./ssgi)** — Indirect light bouncing between surfaces - **[Screen Space Reflections (SSR)](./screen-space-reflections)** — Real-time reflections --- # Animations Animations panel The Animations tab provides tools for controlling all types of motion in your scene — imported glTF animation playback, camera path transitions, scroll-driven interactions, physics simulations, and object posing. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), accessible via the AnimationsAnimations tab. --- ## Sections
glTF Animation Playback of animations embedded in your glTF/GLB file Camera Views Save camera positions and animate transitions between them Viewer Animations Create dynamic scenes by combining environment, lighting, and post-processing animations Scrollable Camera Views Preview Scroll-driven camera transitions for product landing pages Physics Gravity, collisions, and gyroscope-driven motion for realistic interactions
--- ## Related Pages - **[Export Videos](./export-videos)** — Export animations as video files - **[Post Processing](./post-processing)** — Visual effects applied to your renders --- # glTF Animation This section controls playback of animations embedded in your glTF/GLB file. If you created an animation in your 3D software (Blender, 3ds Max, Maya) and exported it with the file, you can play it back and adjust its speed directly in Playground. This is useful for product showcase animations — a ring rotating to show all angles, a pendant swinging, or a bracelet clasp opening and closing. You prepare the animation in your 3D software, export it as glTF/GLB, and then control the playback here. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the AnimationsAnimations tab, in the **glTF Animation** section. You can also start and stop the animation using the Play glTF AnimationPlay glTF Animation button on the top toolbar. glTF Animation settings --- ## Settings
Animation State
read-only
Displays the current animation state
Animation Time
read-only
Displays the current playback time position
Animation Duration
read-only
Displays the total duration of the animation
Loop
checkbox
Repeats the animation continuously after it finishes
Time Scale
slider
Scales the overall animation time
Speed
slider
Controls the playback speed
Animate on Scroll
checkbox
Ties animation progress to page scroll position
Animate on Drag
checkbox
Ties animation progress to mouse/touch drag on the canvas
Drag Axis
select
Drag direction — horizontal or vertical
Autoplay on Load
checkbox
Starts the animation automatically when the scene loads
Sync Max Duration
checkbox
Synchronizes all animations to the longest duration
### Playback Controls
Play Stop Reset
::: tip Key Settings **Loop**, **Time Scale**, and **Speed** are the most commonly adjusted parameters. Loop repeats the animation continuously, while Time Scale and Speed control how fast it plays. Use **Play**, **Stop**, and **Reset** for direct playback control. ::: --- ## Video Tutorials ### Professional Diamond Ring Animation — Blender to iJewel Playground
### How to Create Beautiful Ring Animation — Blender to iJewel Playground
### How to Create Beautiful Pendant Swing Animation — Blender + iJewel Playground
--- ## Related Pages - **[Export Videos](./export-videos)** — Export your animations as video files - **[Animations](./animations)** — Overview of all animation sections --- # Camera Views Camera Views lets you save specific camera positions and animate smooth transitions between them. This is one of the most important features for presenting jewelry — you can set up a front view, a top-down angle, a close-up on the stone, and then animate between them with a single click. You can use Camera Views in two ways: save a single position as a "home" angle that viewers can always return to, or create a sequence of multiple views to showcase your piece from every angle with cinematic transitions. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the AnimationsAnimations tab, in the **Camera Views** section. You can also use the Loop Camera ViewsLoop Camera Views button on the top toolbar to start looping through all saved positions. --- ## How to Create Camera Views — Step by Step ### Step 1: Position Your Camera Navigate in the canvas to find the angle you want to save. You can rotate the model by dragging, zoom in/out with scroll, and hold **Shift + drag** to pan left/right. For more details on canvas navigation, see [UI Overview](./ui-overview). ### Step 2: Save the Position In the Camera Views section, click the **Add Current View** button. A new entry called "Camera View" will appear at the top of the list. This saves the exact camera position, target, and orientation. ### Step 3: Review the Saved View Click on the saved view to expand it. You will see the stored coordinates (Position, Target, Quaternion, Up), plus Duration, Name, and three action buttons: **Focus View**, **Delete View**, and **Update View**. Click **Focus View** to fly the camera to this saved position. The transition speed depends on the **Duration** setting — if you want an instant jump with no animation, set Duration to **0**. ### Step 4: Add More Views Rotate your model to a new angle (for example, a top-down view) and click **Add Current View** again. A second Camera View entry will appear. Repeat this for as many views as you need — front, side, top, close-up on a detail, etc. ### Step 5: Animate Between Views Click the **Animate All Views** button in the main settings. The camera will smoothly transition through all saved positions in order. To fine-tune the animation, adjust these key settings: - **Duration** — increase for slower, more cinematic transitions - **Ease** — controls the acceleration curve. **easeInOutSine** is the most popular choice for smooth, natural motion - **Interpolation** — **Spherical** is the most commonly used for camera movements - **Loop All Views** — enable to loop continuously, so the last view transitions back to the first --- ## Use Cases **Single view as a home position** — If you want your product page to always start from a specific angle, save just one Camera View. Users can rotate the model freely, and the scene can always snap back to this starting position. **Multiple views for product showcase** — Create 3–4 or more Camera Views to highlight different details of your jewelry: front face, top-down, side profile, close-up on the setting. Use **Animate All Views** or **Loop All Views** to present them as a guided tour. --- ## Per-View Buttons Camera Views — per-view buttons Each saved Camera View has three action buttons:
Focus View Delete View Update View
- **Focus View** — Flies the camera to this saved position - **Delete View** — Permanently removes this view - **Update View** — Overwrites the saved coordinates with the current canvas position ::: warning **Delete View** and **Update View** are irreversible. There is no undo — once you delete or update a view, the previous data is gone. ::: --- ## General Settings Camera Views — general settings panel
Loop All Views
checkbox
Loops the animation continuously — the last view transitions back to the first
View Pause Time
input
How long the camera pauses at each view before moving to the next
Ease
select
Transition easing curve. Recommended: easeInOutSine for smooth, natural motion
Duration
slider
Transition time between views. Increase for slower, more cinematic movement
Rotation Offset
slider
Adds a rotation offset to the camera path
Interpolation
select
Camera path interpolation method. Recommended: Spherical
Seek on Scroll
checkbox
Ties the camera view transition to page scroll position
### Action Buttons
Animate All Views Record All Views Add Current View Focus Next Focus Previous
- **Animate All Views** — Plays the full transition sequence through all saved views - **Record All Views** — Records the camera view animation as an MP4 video and downloads it to your computer. This is the same as **Export → Video Export → Record Camera Views** - **Add Current View** — Saves the current canvas camera position as a new view - **Focus Next** — Jumps to the next saved view - **Focus Previous** — Jumps to the previous saved view --- ## Common Mistakes ::: danger Changing Field of View breaks Camera Views If you change the **Field of View** setting in **Viewer → Camera**, all previously saved Camera Views will become inaccurate — the framing and zoom will shift. You will need to delete and re-create your Camera Views after changing Field of View. Always set your Field of View **before** creating Camera Views. ::: --- ## Video Tutorial ### iJewel3D Video Rendering — Camera Paths & Animated Lightmaps
--- ## Related Pages - **[Export Videos](./export-videos)** — Export camera view animations as video files - **[Animations](./animations)** — Overview of all animation sections - **[FAQ: Cameras & Animations](./faq-cameras)** — Common questions about cameras and camera paths - **[Cameras (Loaded)](./cameras-loaded)** — Working with cameras imported from 3D software --- # Viewer Animations Viewer Animations panel Viewer Animations lets you create dynamic, cinematic scenes by combining multiple visual effects into a single animation sequence. You can animate environment rotation, background color, lighting intensity, post-processing effects, and camera properties — all at the same time or in a carefully timed sequence. This is one of the most powerful tools for creating professional jewelry presentations. By layering a few animation blocks — spinning the environment for moving reflections on metal, rotating the diamond light map for sparkle, and shifting the background color — you can turn a static 3D model into a living, cinematic preview. You can also use these animations as **animated product images** — for example, when a customer hovers over your ring on a product page, the static thumbnail can transition into a looping video that showcases sparkling diamonds and moving reflections. Record the animation using [Export Videos](./export-videos) and embed it as a hover-triggered video on your website. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the AnimationsAnimations tab, in the **Viewer Animations** section. --- ## How to Create an Animation — Step by Step ### Step 1: Add a New Animation Block In the Viewer Animations section, click the **Add Animation** button at the bottom of the panel. A new collapsible tab labeled "Animation" will appear. ### Step 2: Choose a Property Expand the new animation tab and select the property you want to animate from the **Property** dropdown. For example, choose **Environment Rotation** to make reflections move across your jewelry's metal surface. ### Step 3: Configure the Settings Set your desired values: - **From / To** — the start and end values for the animation (for colors, use the color pickers) - **Duration** — animation length in milliseconds (e.g., `3000` = 3 seconds) - **Ease** — the speed curve (e.g., `easeInOutSine` for a smooth start and finish) - **Repeat Type** — what happens when the animation ends (Loop, Mirror, or Reverse) Make sure the **updateScene** and **updateViewer** checkboxes are enabled — without them, the animation will not be visible. ### Step 4: Play the Animation Click the **Animate** button at the top of the panel to start the animation. You should see the effect in real time on your model. ### Step 5: Add More Effects Repeat Steps 1–3 to add more animation blocks. For example, add a second block for **Diamond Env Map Rotation** and a third for **Background Color**. Enable **Run in Parallel** to play them all at the same time. --- ## Popular Animation Examples Here are four commonly used animations for jewelry presentations. ### Diamond Env Map Rotation The signature jewelry animation. Rotates the environment map only for Diamond materials, making the gemstone facets sparkle and shift with light. Combine this with Environment Rotation for the most realistic result — the metal and the stone animate independently. ### Environment Rotation Rotates the HDRI map around your model, making reflections glide across polished metal surfaces. Set **From** to `0` and **To** to `6.28` for a full 360° loop. Use **Mirror** repeat type for a seamless back-and-forth motion. ### Background Color Smoothly transitions the scene background between two colors — for example, from warm ivory to cool grey. This creates a subtle atmospheric shift that enhances the cinematic feel of your presentation. ### Tonemap Exposure Dynamically adjusts the exposure level of the final image. This can simulate a "reveal" effect — starting dim and fading up to full brightness, or creating a dramatic spotlight moment. --- ## Pro Tip: The Perfect Jewelry Preview To create a professional, cinematic product preview, set up three animation blocks: 1. **Diamond Env Map Rotation** — for sparkling gemstone fire 2. **Environment Rotation** — for moving reflections on metal 3. **Background Color** — for a soft atmospheric color shift Enable **Run in Parallel**, set all three to the same **Duration** (e.g., `5000` ms), and use **Mirror** as the Repeat Type. Your scene will come to life with smooth, looping motion that showcases your jewelry from its best angle. --- ## Video Tutorial This tutorial covers both Camera Views and Viewer Animations in one walkthrough: ### iJewel3D Video Rendering — Camera Paths & Animated Lightmaps
--- ## Master Controls & Animation List Viewer Animations — master controls and animation list The buttons at the top of the panel control all animation blocks simultaneously:
Animate Animate Reverse Stop
- **Animate** — Starts all animation blocks from top to bottom - **Animate Reverse** — Plays all animations in reverse (from end value back to start value) - **Stop** — Immediately stops all active animations You can create an unlimited number of animation blocks for a single scene. Each block appears as a collapsible tab.
Add Animation
button
Creates a new animation block at the bottom of the list
Run in Parallel
checkbox
When enabled, all animations play simultaneously. When disabled, they play sequentially (first finishes, then second starts, etc.)
--- ## Block Settings Viewer Animations — block settings Each animation block contains the following parameters:
Property
select
The scene parameter to animate (see Available Properties below)
From / To
input
Start and end values for the animation. For colors, a color picker is shown
Duration
input
Animation length in milliseconds (e.g., 3000 = 3 seconds)
Ease
select
Speed curve for the animation. Recommended: easeInOutSine for smooth motion
Repeat Type
select
Behavior after the animation ends — Loop (restart from beginning), Mirror (reverse back and forth), or Reverse (play backwards continuously)
updateScene
checkbox
Calculates the scene changes. Must be enabled for the animation to work
updateViewer
checkbox
Renders the visual output. Must be enabled for the animation to be visible
updateCamera
checkbox
Enable only when animating camera properties (FOV, Depth of Field). Not needed for environment or post-processing animations
::: warning Important Both **updateScene** and **updateViewer** must be enabled in every animation block, otherwise the effect will not appear. Enable **updateCamera** only if you are animating camera-related properties like FOV or Depth of Field. ::: ::: tip Mirror for seamless loops Use **Mirror** as the Repeat Type for the smoothest seamless effect — the animation plays forward and then reverses naturally, avoiding any visible "jump" at the loop point. ::: --- ## Available Properties ### Environment & Light
Background Color
Smooth transition between two background colors (use From/To color pickers)
Environment Rotation
Rotates the HDRI environment map, making reflections move across metal surfaces. Use values 0 to 6.28 for a full 360° rotation
Environment Intensity
Changes the overall scene brightness (from 0 to 1 and above)
Fixed Env Map Direction
Locks the environment map direction during rotation
Directional Light Color / Direction
Animate the color and direction of the directional light source
### Gems Special
Diamond Env Map Rotation
Rotates the environment map only for Diamond materials, creating a sparkling "fire" effect inside gemstone facets. Use values 0 to 6.28 for a full rotation
### Tonemapping & Post-Processing
Tonemap Exposure
Animate the exposure level of the final image
Tonemap Saturation
Animate the color saturation of the scene
Tonemap Contrast
Animate the contrast level of the frame
Tonemap Tone Mapping
Switch between different tone mapping algorithms
### Camera & Lens
Camera FOV
Animate the field of view for a dolly zoom or push-in/pull-out effect
Depth of Field
Animate Focal Point, Blur Scale, and Focal Depth Range to smoothly shift focus between foreground and background
Chromatic Aberration
Add a color fringing lens effect for a cinematic look
Filmic Grain
Animate film grain intensity for a movie-like visual style
### Bloom & Reflections
Bloom (Intensity, Radius, Power)
Animate the soft glow around bright areas of the scene
SSR (Intensity, Boost)
Animate Screen Space Reflections intensity in real time
Vignette (Color, Power)
Animate the edge darkening to draw focus to the center of the frame
--- ## Related Pages - **[Camera Views](./camera-views)** — Save camera positions and animate transitions between them - **[Animations](./animations)** — Overview of all animation sections - **[Post Processing](./post-processing)** — Visual effects you can animate with Viewer Animations - **[Export Videos](./export-videos)** — Export your animations as video files - **[Bloom](./bloom)** — Bloom post-processing effect details - **[Depth of Field](./depth-of-field)** — Depth of Field post-processing effect details --- # Scrollable Camera Views Preview (Dev) Scrollable Camera Views Preview panel Scrollable Camera Views Preview controls how the camera behaves when the user scrolls the page. Instead of clicking buttons to transition between views, the camera position is tied directly to the scroll position — as the user scrolls down, the camera smoothly moves through all saved [Camera Views](./camera-views). This is especially useful for product landing pages where you want the 3D model to animate cinematically as the visitor scrolls through the page content. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the AnimationsAnimations tab, in the **Scrollable Camera Views Preview** section. --- ## Settings
Enabled
checkbox
Toggles scroll-driven camera control on or off
Ease
select
Easing function that controls how the camera accelerates and decelerates. Default: easeInOutSine for smooth, natural motion
Interpolation
select
Camera path interpolation method. Spherical moves the camera along an arc around the object, preserving distance and preventing the camera from clipping through models
Enable Damping
checkbox
Adds inertia to the camera movement. When enabled, the camera doesn't stop instantly after scrolling — it smoothly glides to its final position
Damping
slider
Damping coefficient (default: 0.040). Lower values create a smoother, more "buttery" glide after scrolling stops. Higher values make the camera respond more immediately
Init Anim Time
slider
Duration (in seconds) of the initial animation when the page first loads or the scene first appears (default: 1.000)
Canvas on Top
checkbox
When enabled, the 3D canvas renders above other page elements. Useful for debugging layer overlap issues
--- ## Related Pages - **[Camera Views](./camera-views)** — Save the camera positions that this feature scrolls through - **[Viewer Animations](./viewer-animations)** — Create dynamic scenes with combined visual effects - **[Animations](./animations)** — Overview of all animation sections --- # Physics Physics panel The Physics section controls the physics engine for your scene. It enables gravity, collisions, and inertia for objects, making interactions with jewelry and scene elements feel realistic and dynamic. A common use case in iJewel is **gyroscope-driven motion** — when a customer tilts their phone, the physics engine "pushes" objects in the scene. Pendants start swinging, stones catch the light from different angles, and the jewelry feels like it's physically in the viewer's hands. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the AnimationsAnimations tab, in the **Physics** section. --- ## Settings
Enabled
checkbox
Global physics toggle. When disabled, all objects remain static. When enabled, physics laws apply — objects with mass can fall, collide, and respond to forces
Step Count
input
Number of physics calculations per frame (default: 100). Higher values produce more accurate simulations but increase CPU load
Delta
input
Time step for each physics calculation (default: 0.10). Controls how fast time flows in the physics simulation
### Action Buttons
Step Make Root Bodies
- **Step** — Manually advances the physics simulation by one step. Useful for debugging to see exactly where objects will move next - **Make Root Bodies** — Automatically creates physics bodies for the root objects of your model. This turns regular 3D objects into physical entities with mass that can collide and interact with each other --- ## Related Pages - **[Viewer Animations](./viewer-animations)** — Create dynamic scenes with combined visual effects - **[Animations](./animations)** — Overview of all animation sections - **[Camera Views](./camera-views)** — Save camera positions and animate transitions --- # Materials Materials panel Materials define how every surface in your scene looks — the color, reflectivity, roughness, and transparency of metals, gemstones, ceramics, pearls, and more. iJewel Playground uses two specialized material types: **Physical Material (PBR)** for opaque surfaces like metals and ceramics, and **Diamond Material** for gemstones with ray-traced refraction and sparkle. You can start from scratch by adjusting every parameter manually, or use one of the 300+ ready-made presets from the built-in library to get professional results instantly. ## Where to Find It Materials can be accessed in two ways: 1. **Left panel — Material Presets** — Click on any object in the canvas, then browse the preset library tabs (MetalsMetals, GemsGems, CeramicsCeramics, PearlsPearls, OtherOther) to apply a preset with one click 2. **Right panel — Picking** — Select an object in the canvas while in PickingPicking mode to open its full material editor (Physical Material or Diamond Material) --- ## Sections
PBR Materials Physical material editor for metals, ceramics, glass, and all opaque surfaces Diamond Materials Specialized shader for diamonds, emeralds, sapphires, and all gemstones Material Presets 300+ ready-made materials from the built-in library Material Configurator Create interactive material variations for your embedded viewer
--- ## Related Pages - **[Export Materials](./export-materials)** — Save and share material presets - **[Import Materials](./import-materials)** — Load saved material presets - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials - **[Post Processing](./post-processing)** — Visual effects applied to the final render --- # PBR Materials Physical Material panel Physical Materials (PBR) control how surfaces look in your scene — their color, reflectivity, roughness, transparency, and more. This is the most detailed material editor in iJewel Playground and it uses a physically-based rendering model to produce realistic results. Every metal, stone setting, enamel, ceramic, or glass surface in your jewelry model is controlled through this panel. ## How to Open 1. Click on any object in the canvas to select it 2. Go to the PickingPicking tab on the [right panel](./ui-overview#right-panel-—-professional-tools) 3. The Picker will show the material name, and the **Physical Material** section will open below with all its settings ::: tip Merging Materials You can rename a material in the **name** field. If you select a different object and rename its material to the **same name**, both objects will share the same material — any change to one will apply to both. This is useful when applying library presets to multiple objects at once. ::: --- ## Physical Material These are the top-level settings that appear when you expand the Physical Material section.
name
input
Material name. Rename for convenience (e.g., "Metal", "Pearl") or to merge materials by giving them the same name
wireframe
checkbox
Shows the polygon structure of the mesh instead of the solid surface
vertexColors
checkbox
Enables vertex color data from the model. Usually black by default — rarely needs to be changed
color
color picker
The base color of the material. Use the color picker or enter a hex value directly. The format is 0x followed by 6 hex digits (e.g., 0xe5b377 for gold) — keep the 0x prefix and change only the last 6 characters
Material color example
Custom color applied to metal
Metal material example
Gold metal material
map
image
Texture map applied on top of the base color. Requires UV unwrapping on the model. If your model has no UVs, enable Triplanar mapping below — seamless textures will wrap automatically
Texture map applied to material
Texture map on surface
Wood texture map example
Wood texture with Triplanar
--- ## Rough/Metal Controls how reflective and metallic the surface appears. Together with color, this defines the overall look of your material.
roughness
slider
How rough or smooth the surface is. 0 = mirror-like, 1 = completely matte
metalness
slider
How metallic the surface is. 1 = fully metallic (gold, silver), 0 = non-metallic (ceramic, plastic)
roughnessMap
image
Texture that controls roughness variation across the surface. When added, a roughnessMap Sampler section appears for positioning
metalnessMap
image
Texture that controls metalness variation across the surface. When added, a metalnessMap Sampler appears
::: tip Map Samplers Whenever you add a texture map, a **Sampler** section appears below it with controls for scale, offset, and repeat. If you are using [Triplanar](#triplanar) mapping, you can ignore the Sampler — Triplanar handles texture placement automatically. :::
Roughness 0 — mirror-like
Roughness: 0
Roughness 1 — matte
Roughness: 1
Metalness 0 — non-metallic
Metalness: 0
Roughness 0.25, Metalness 0.80
Roughness: 0.25, Metalness: 0.80
Roughness map applied to material
Roughness map applied
--- ## Bump/Normal Adds surface detail without changing the actual geometry. Bump maps use black-and-white images to create the illusion of height. Normal maps use specialized purple-tinted images for more precise surface detail.
bumpScale
slider
Controls the intensity of the bump effect
bumpMap
image
Black-and-white texture for surface bumps. When added, a bumpMap Sampler appears
normalMap
image
Purple-tinted normal map for detailed surface normals. Adds normalMap Sampler, normalScale (two inputs for X/Y strength), and normalMapType (Tangent Space)
displacementMap
image
Displacement texture that actually moves vertices. Adds displacementMap Sampler and displacementScale
Bump map applied to metal surface
Bump map on metal surface
--- ## Sheen Adds a soft, fabric-like sheen to the surface edges. Can create interesting velvet or silk effects.
sheen
slider
Intensity of the sheen effect
sheenColorMap
image
Texture controlling the sheen color across the surface
sheenRoughness
slider
Roughness of the sheen layer
sheenRoughnessMap
image
Texture controlling sheen roughness across the surface
--- ## Clearcoat Adds a secondary reflective layer on top of the base material — like a glossy varnish. Commonly used for **ceramic**, **marble**, and **lacquered** surfaces.
clearcoat
slider
Intensity of the clearcoat layer. 0 = off, 1 = full reflective coating
clearcoat-Roughness
slider
Roughness of the clearcoat layer itself
clearcoatMap
image
Texture controlling clearcoat intensity across the surface
clearcoatRoughnessMap
image
Texture controlling clearcoat roughness across the surface
clearcoatNormalMap
image
Normal map for the clearcoat layer specifically
Clearcoat 0 — no coating
Clearcoat: 0
Clearcoat 1 — full reflective coating
Clearcoat: 1
--- ## Emission Makes the material glow by emitting light. Useful for decorative elements, LED accents, or artistic effects.
emissive
color picker
The color of the emitted light
emissiveIntensity
input
Brightness of the emission. Higher values create a stronger glow
emissiveMap
image
Texture controlling which parts of the surface emit light. When added, a Map Sampler appears
--- ## Refraction Controls transparency and light refraction through the material. Used for **glass**, **crystal**, and other see-through surfaces.
ior
slider
Index of Refraction — how much light bends when passing through. Glass ≈ 1.5, Diamond ≈ 2.42, Water ≈ 1.33
transmission
slider
How much light passes through the material. 1 = fully transparent, 0 = opaque
thickness
input
The virtual thickness of the material, affecting how much light is absorbed
transmissionMap
image
Texture controlling transmission across the surface
thicknessMap
image
Texture controlling thickness variation across the surface
attenuationDistance
input
Distance at which light is fully absorbed by the material's color
attenuationColor
color picker
The color that light takes on as it passes through the material
Glass material with refraction
Glass material with refraction
--- ## Blending Controls transparency and visibility of the material. **Opacity** and **transparent** are the most commonly used settings here.
opacity
slider
Overall transparency of the object. 1.0 = fully visible, 0 = invisible
transparent
checkbox
Enables transparency rendering. Must be checked for opacity to take effect
depthFunc
select
Depth comparison function (default: LessEqual). Rarely needs to be changed
depthTest
checkbox
Whether to test against the depth buffer when rendering
depthWrite
checkbox
Whether to write to the depth buffer
colorWrite
checkbox
Whether to write color data to the frame buffer
alphaTest
slider
Alpha cutoff threshold. Pixels with alpha below this value are discarded
alphaHash
checkbox
Enables alpha hashing for order-independent transparency
dithering
checkbox
Adds dithering to reduce color banding artifacts
Blending
select
Blending mode (default: None)
alphaMap
image
Texture that controls transparency across the surface
Render to Depth
checkbox
Renders the material to the depth buffer
Inverse AlphaMap
checkbox
Inverts the alpha map values
Polygon Offset
checkbox
Enables polygon offset to prevent z-fighting between overlapping surfaces
Polygon Offset Factor
slider
Scale factor for the polygon offset
Polygon Offset Units
slider
Unit offset for the polygon offset
--- ## AO/Lightmap Ambient Occlusion and Light Maps add pre-baked shadow and lighting detail. Mostly used for ground planes and background surfaces.
aoMapIntensity
slider
Strength of the ambient occlusion map
aoMap
image
Ambient occlusion texture
lightMapIntensity
slider
Strength of the light map
lightMap
image
Pre-baked lighting texture
--- ## Iridescence Creates a rainbow-like color shifting effect that changes depending on the viewing angle — similar to oil on water or the sheen on certain pearls and shells. Some pearl presets in the library (e.g., "Pearl Green") use this for their color-shifting effect.
Intensity
slider
Strength of the iridescent effect
IOR
slider
Index of refraction for the thin film layer
Thickness0
slider
Minimum thin film thickness. Adjust together with Thickness1 to control the color range
Thickness1
slider
Maximum thin film thickness
iridescenceMap
image
Texture controlling where iridescence appears on the surface
iridescenceThicknessMap
image
Texture controlling thickness variation for the iridescent layer
--- ## Environment Override the global environment map for this specific material. This lets you use a different HDRI lighting setup for one material while the rest of the scene uses the default.
Override Environment
checkbox
Enables a custom environment map for this material only
Environment Intensity
slider
Brightness of the custom environment for this material
Environment Map
select
Choose from environment maps added to the scene
--- ## General Settings
Side
select
Which side of the polygons to render. Double is most common. Use Front or Back for special effects
flatShading
checkbox
Disables smooth shading and shows flat polygon faces instead
Mesh count
read-only
Number of meshes using this material
### Download pmat
Download pmat
Exports the current material as a **.pmat** file. You can save your custom material settings and reuse them later or share them with others. --- ## LUT Apply a per-material Look Up Table for color grading. This works the same way as the global [LUT post-processing effect](./lut), but applies only to this specific material.
Enabled
checkbox
Toggles the per-material LUT
index
select
Select which LUT to apply from the available presets
--- ## Anisotropy Creates directional reflections — like the elongated highlights you see on brushed metal.
Anisotropy effect on metal
Anisotropy — brushed metal reflections
Enabled
checkbox
Toggles the anisotropy effect
Factor
slider
Strength of the anisotropic stretch. 0 = uniform, 1 = fully stretched
Noise
slider
Adds randomness to the anisotropy direction
Texture
image
Direction map that controls the anisotropy direction per pixel
Mode
select
Anisotropy calculation mode (default: DIRECTION)
--- ## Triplanar Automatically projects textures onto a model from three directions (X, Y, Z) without requiring UV unwrapping. This is the solution when your model has no UVs — just enable Triplanar, and seamless textures will wrap correctly.
Triplanar mapping applied to model
Triplanar mapping — no UV required
Enabled
checkbox
Toggles triplanar mapping on or off
Fix to Object
checkbox
Locks the texture to the object so it doesn't shift when the object moves
Scale
slider
Size of the projected texture. Smaller values = larger texture pattern
Blend
slider
How smoothly the three projection directions blend into each other
Offset
slider
Shifts the texture position
--- ## ThinFilmLayer Adds a subtle thin film interference effect, creating a slightly paler or tinted look on the surface.
Enabled
checkbox
Toggles the thin film layer effect
Intensity
slider
Strength of the thin film effect
Base Layer
4 inputs
Base layer parameters (4 values)
Noise Layer
4 inputs
Noise layer parameters (4 values)
Noise Params
4 inputs
Additional noise parameters (4 values)
--- ## FragmentClipping Advanced section for clipping parts of the material rendering at the fragment level. --- ## Flat Material Renders the material without any lighting calculations — a flat, unlit appearance. --- ## SparkleBump (NoiseBump) Generates a procedural sparkle/noise bump pattern on the surface. For best results, use ready-made sparkle materials from the preset library rather than configuring this manually. --- ## CustomBumpMap Custom bump map settings for additional surface detail control. --- ## ClearcoatTint Adds a subtle color tint to the clearcoat layer. --- ## SSBevel (Dev) Per-material Screen Space Bevel control. This can also be configured globally from the [Screen Space Bevel](./screen-space-bevel) post-processing settings. --- ## Bloom Per-material Bloom toggle. Allows you to enable or disable the [Bloom](./bloom) post-processing effect for this specific material. --- ## LayeredMaterial Creates a beautiful two-tone effect where a second color appears in surface crevices and recesses. Commonly used for **oxidized bronze**, **oxidized copper**, **patina**, and **antique** finishes — the secondary color naturally accumulates in the grooves and hard-to-reach areas of the model.
Enabled
checkbox
Toggles the layered material effect
cutoff
slider
Controls the threshold between the base material and the layered color. Adjust to control how much of the secondary color appears
color
color picker
The secondary color that appears in crevices and recesses
roughness
slider
Roughness of the secondary layer
Scale
slider
Scale of the pattern used to distribute the secondary layer
StepSize
slider
Controls the sharpness of the transition between layers
metalness
slider
Metalness of the secondary layer
Layered material — oxidized bronze effect
LayeredMaterial — oxidized bronze effect
--- ## Auto UV Mapping Automatic UV unwrapping for the model. Enable this if you want the system to generate UVs automatically. --- ## Object Actions These buttons appear at the bottom of the Picking panel and affect the selected object.
Remove Material Duplicate Object Wrap in Parent Delete Object
- **Remove Material** — Strips the material from the selected object - **Duplicate Object** — Creates a copy of the selected object - **Wrap in Parent** — Wraps the selected object inside a new parent group - **Delete Object** — Permanently removes the selected object from the scene ::: warning **Delete Object** is irreversible. There is no undo — the object and its data will be permanently removed. ::: --- ## Physics Per-object physics body settings. See the [Physics](./physics) page for global physics configuration. --- ## Transform Animation Per-object transform animation settings for position, rotation, and scale keyframes. --- ## Video Tutorial
--- ## Related Pages - **[Material Presets](./material-presets)** — Browse and apply ready-made material presets from the library - **[Diamond Materials](./diamond-materials)** — Material settings specific to gemstones and diamonds - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials - **[Look Up Tables (LUT)](./lut)** — Global LUT post-processing - **[Screen Space Bevel](./screen-space-bevel)** — Global SSBevel post-processing - **[Bloom](./bloom)** — Global Bloom post-processing --- # Diamond Materials Diamond Material is a specialized shader designed for rendering gemstones — diamonds, emeralds, sapphires, rubies, and other precious stones. Unlike [PBR Materials](./pbr-materials), which simulate opaque surfaces, Diamond Material uses ray-traced refraction and dispersion to produce realistic sparkle, fire, and brilliance inside the stone. How your gemstone looks depends heavily on the **HDRI environment map** assigned to it. Different HDRI maps produce dramatically different sparkle patterns, so try several options from the Gems library on the left panel or create your own. All images on this page use the **Gem001** HDRI map. ::: warning My diamond doesn't look right? If your diamond looks white, flat, or lacks sparkle, the most common cause is the wrong HDRI environment map. See [FAQ: Materials & Diamonds](./faq-materials) for troubleshooting steps and video tutorials on fixing common diamond issues. ::: ## Gem Shapes If your scene contains multiple diamond shapes (round, pear, oval, princess, marquise, emerald, etc.), each shape **must be on a separate material layer**. For example, round diamonds should be on a "Gem 01" layer, pear shapes on a "Gem 02" layer, and so on. If different shapes share the same material layer, you won't be able to adjust settings per shape, and some stones may render incorrectly. ### Video Tutorial — Fixing Diamond Rendering
### Shape Examples
Round
Pear
Oval
Princess
Marquise
Emerald
--- ## How to Open 1. Click on any gemstone object in the canvas to select it 2. Go to the PickingPicking tab on the [right panel](./ui-overview#right-panel-—-professional-tools) 3. The Picker will show the material name, and the **Diamond Material** section will open below with all its settings If your object does not have a Diamond Material yet, you can assign one in two ways: 1. **From the Gems library** — Open the GemsGems tab on the left panel and select any gem preset to apply it to the selected object 2. **From Picking → Diamonds** — Go to the Picking panel, find the **Diamonds** section, and click **Make Diamond**. This converts the Physical Material on the selected object into a Diamond Material Diamond Material panel --- ## Diamond Material Diamond Material — general view Classic white diamond
name
input
Material name. Works the same as in PBR Materials — rename for convenience or give two objects the same name to merge their materials
wireframe
checkbox
Shows the polygon structure of the gemstone mesh
Environment
select
Select which environment map to use for this gemstone. If you have added multiple environments to the Diamonds section, you can assign different HDRIs to different stones
Color
color picker
The base color of the gemstone. White (0xffffff) for a classic diamond, or any color for colored gemstones like emerald, sapphire, or ruby
Colored diamond material
Emerald green color applied to diamond
Env Intensity
slider
Controls the overall brightness of the gemstone. Default is around 1.30. Increase for a brighter, more vivid stone; decrease for a subtler look
Env Intensity at 0.84
Env Intensity: 0.84 — slightly dimmer stone
Env Rotation Offset
slider
Rotates the HDRI map around the gemstone. Use this to find the perfect lighting angle — rotate until you see the most beautiful sparkle and fire for your current camera position
Env Rotation Offset X/Y/Z
slider
Fine-tune the environment map rotation on individual axes. Useful when one specific diamond has a bright overexposed spot — adjust these to shift the HDRI and fix it
Dispersion
slider
Adds rainbow color separation (chromatic dispersion) — the colorful "fire" effect you see in real diamonds when light splits into its spectral colors
Dispersion effect — rainbow fire
Dispersion enabled — rainbow fire effect
Absorption
slider
Intensifies the selected Color for colored gemstones. Only visible when the stone has a non-white color — higher values produce a deeper, more saturated tint
Absorption effect on colored gemstone
Absorption — intensified color on a tinted stone
Refractive Index
slider
Controls the depth and brilliance of the stone. Default is 2.60. Lower values create a shallower, less brilliant look. Increase or decrease depending on the stone shape and cut — unusual or custom cuts may need adjustment
Gamma
slider
Contrast adjustment for the gemstone's internal colors. Default is 1.00. Increase to boost contrast and make colors more vivid, decrease for a softer look
RGB Boost
3 inputs
Boost individual Red, Green, and Blue channels. An alternative to the Color picker for adding specific tints — can produce brighter, more saturated color effects
RGB Boost 2-2-2
RGB Boost: 2.0 / 2.0 / 2.0 — brighter, saturated tint
Transmission
slider
Makes the stone transparent, allowing the metal prongs and setting behind it to show through. This creates beautiful color reflections inside the gemstone from the surrounding metal
Transmission — metal prongs visible through diamond
Transmission — metal prongs visible through the stone
Reflectivity
slider
Controls how much the surface of the gemstone reflects light. Higher values create a more mirror-like top surface
Ray Bounces
slider
Number of times light bounces inside the stone. Default is 4–5. Increase up to 16 for more realistic results on certain cuts
Ray Bounces 12 — more realistic pear shape
Ray Bounces: 12 — more realistic brilliance
Diamond Oriented Lighting
slider
Changes the orientation of the environment map relative to the stone
::: tip Finding the perfect sparkle If a diamond looks overexposed (pure white with no detail) from a certain angle, use the **Env Rotation Offset** sliders to rotate the HDRI map slightly. Small adjustments can dramatically change how light enters the stone and produce much better fire and brilliance. ::: --- ## General Settings
Mesh count
read-only
Number of meshes using this diamond material
uuid
read-only
Unique identifier for this material
### Download .dmat
Download .dmat
Exports the current diamond material as a **.dmat** file. You can save your custom gemstone settings and reuse them later. See [Export Materials](./export-materials) for more details. --- ## LUT Apply a per-material Look Up Table for color grading. See the [Look Up Tables (LUT)](./lut) page for a full overview of how LUT works. --- ## ThinFilmLayer Adds a thin film interference effect that creates rainbow-like color shifting on the stone's surface. See [PBR Materials — ThinFilmLayer](./pbr-materials#thinfilmlayer) for settings details. ThinFilmLayer on diamond --- ## Flat Material Renders the gemstone without any lighting calculations — a flat, unlit appearance. --- ## Bloom Per-material Bloom toggle. Allows you to enable or disable the [Bloom](./bloom) post-processing effect for this specific gemstone. --- ## Inclusions
Diamond with inclusions Diamond with inclusions — variant 2
Inclusions simulate the natural imperfections found inside real gemstones — tiny cracks, mineral deposits, and internal fractures that give each stone its unique character. This is especially important for colored gemstones like emeralds, sapphires, and rubies, which naturally contain visible inclusions. You can use ready-made inclusion maps from the **Gems** library on the left panel, or create your own unique inclusions by adding custom maps and adjusting the settings below.
Enabled
checkbox
Toggles inclusions on or off
VariableBlur
slider
Controls the blur amount applied to inclusion textures
VariableParam1
slider
First variable parameter for inclusion rendering
VariableParam2
slider
Second variable parameter for inclusion rendering
blurRadius
slider
Radius of the blur applied to inclusions
ClampHDR
checkbox
Clamps HDR values in the inclusion rendering
SurfaceScale
slider
Scale of the surface texture for inclusions
Color Map Scale
slider
Scale of the color map used for inclusions
BumpScale
slider
Intensity of the bump effect from inclusion textures
InclusionScale
slider
Scale of the inclusion pattern inside the stone
IncNormalScale
slider
Scale of the inclusion normal map effect
InclusionRoughnessMap
image
Roughness texture for the inclusion areas
InclusionMap
image
Main inclusion texture — black-and-white map that defines where inclusions appear inside the stone
Surface Roughness
slider
Roughness of the stone's surface (not the internal inclusions)
RoughnessMap
image
Surface roughness texture map
normalMap
image
Normal map for surface detail on the stone
InclusionNormalMap
image
Normal map specifically for inclusions — adds additional surface detail to the inclusion areas
Map
image
General texture map for the gemstone surface
--- ## Auto UV Mapping Automatic UV unwrapping for the gemstone model. --- ## Object Actions These buttons appear at the bottom of the Picking panel and affect the selected object.
Remove Material Duplicate Object Wrap in Parent Delete Object
- **Remove Material** — Strips the material from the selected object - **Duplicate Object** — Creates a copy of the selected object - **Wrap in Parent** — Wraps the selected object inside a new parent group - **Delete Object** — Permanently removes the selected object from the scene --- ## Physics Per-object physics body settings. See the [Physics](./physics) page for global physics configuration. --- ## Transform Animation Per-object transform animation settings for position, rotation, and scale keyframes. --- ## Diamond Close-Up Views
Diamond — front view
Front
Diamond — side view
Side
Diamond — back view
Back
--- ## Video Tutorial
--- ## Related Pages - **[PBR Materials](./pbr-materials)** — Physical material settings for metals, ceramics, and other surfaces - **[Material Presets](./material-presets)** — Browse and apply ready-made material presets - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials and diamonds - **[Export Materials](./export-materials)** — Save and share material presets - **[Look Up Tables (LUT)](./lut)** — LUT color grading - **[Bloom](./bloom)** — Bloom post-processing - **[Viewer Animations](./viewer-animations)** — Animate Diamond Env Map Rotation for sparkling effects --- # Material Presets Material Presets library iJewel Playground includes a library of 300+ ready-made materials that you can apply to any object with a single click. The presets are professionally configured and cover the most common jewelry materials — from yellow and white gold to emeralds, sapphires, pearls, and ceramics. ## How to Use 1. Click on any object in the canvas to select it 2. On the left panel, browse the material categories using the tabs at the top 3. Click on any preset thumbnail to apply it instantly to the selected object ## Categories The library is organized into five tabs:
Metals
Metals
Gold (yellow, white, rose), silver, platinum, palladium, brass, copper, bronze, titanium, and more. Applies a PBR Material
Gems
Gems
Diamonds (white, colored), emeralds, sapphires, rubies, amethyst, topaz, and many more. Applies a Diamond Material
Ceramics
Ceramics
Ceramic, marble, enamel, and other non-metallic surfaces. Applies a PBR Material with clearcoat
Pearls
Pearls
Pearl materials with iridescence and soft sheen effects. Applies a PBR Material with iridescence
Other
Other
Wood, leather, fabric, glass, rubber, and other specialized surfaces
## Availability The number of available presets depends on your subscription plan. Free users have access to a limited selection, while Premium and Advance plans unlock the full library. See [iJewel Pricing](https://ijewel.design/pricing) for plan details and feature comparison. ## Saving Custom Presets You can save your own custom materials to the library for reuse across projects. After configuring a material the way you want it, use the **Download** button in the material panel: - **Download pmat** — saves a Physical Material as a `.pmat` file - **Download dmat** — saves a Diamond Material as a `.dmat` file To reapply a saved material, drag and drop the `.pmat` or `.dmat` file into Playground. See [Export Materials](./export-materials) and [Import Materials](./import-materials) for the full workflow. ## Video Tutorial
--- ## Related Pages - **[PBR Materials](./pbr-materials)** — Full Physical Material editor reference - **[Diamond Materials](./diamond-materials)** — Full Diamond Material editor reference - **[Materials](./materials)** — Materials overview - **[Export Materials](./export-materials)** — Save and share material presets - **[Import Materials](./import-materials)** — Load saved material presets - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials --- # Material Configurator Material Configurator The Material Configurator lets you create interactive material variations for your 3D model. When embedded in the [iJewel Viewer](../viewer/introduction), your customers can switch between different metals, gemstone colors, ceramics, pearls, and any other materials — directly on your product page. When you add a configurator, a UI bar appears at the bottom of the canvas. The lower bar shows the configuration name (e.g., "Metal"), and the upper bar displays the available material variants as clickable thumbnails. Configurator UI on the canvas --- ## Adding a Material Configurator — Step by Step ### Step 1: Select the Object Click on the object in the canvas that you want to add material variations to. The object will be highlighted. ### Step 2: Open the Configurator At the top of the canvas, click the **Add Configurator** button. A material library panel will appear with tabs for different categories (Metals, Gems, Ceramics, Pearls, Other). ### Step 3: Choose Materials Click on any material to add it as a variant — it will instantly appear in the configurator bar at the bottom of the canvas. You can add as many variants as you want — there is no limit. Click on a selected material again to remove it. ### Step 4: Done The configuration name is automatically taken from the material name of the selected object. You can now click on different variants in the bottom bar to preview how each material looks on your model. --- ## Adding Gem Variations The process works the same for gemstones. Select a gem object, click **Add Configurator**, and the library will automatically open to the **Gems** tab (since the selected object already has a [Diamond Material](./diamond-materials)). Choose your gem variants the same way. --- ## Adding Custom Materials If you've created a custom material in the [PBR Materials](./pbr-materials) or [Diamond Materials](./diamond-materials) editor (for example, a specific color or texture), you can add it as a variant too: 1. Make sure your object is still selected 2. Make all the material changes you need in the Picking panel 3. At the bottom of the canvas, click the **+** button (Add Current Material) — the last button in the configurator bar This adds your current custom material as a new variant. --- ## Editing the Configuration Name The configuration name appears in the lower bar on the canvas (e.g., "Metal", "Gem"). To change it: 1. Enter Edit mode — either click the **Edit Configurator** button at the top of the canvas (after selecting the object), or right-click on the configuration name and choose **Edit** 2. Change the name in the input field at the top of the material library panel --- ## Editing Variant Names Each material variant has a name that appears as a tooltip on hover. To rename a variant: 1. Hover over the variant thumbnail in the configurator bar 2. A tooltip with the variant name will appear — move your cursor to the right side of the tooltip 3. Click the **pencil icon** to edit the name --- ## Removing a Material Variant There are two ways to remove a variant from the configurator: **Method 1** — Right-click on the variant thumbnail in the configurator bar and click **Delete** **Method 2** — Enter Edit mode and click on the material in the library to deselect it --- ## Deleting an Entire Configuration To remove the entire configurator from an object: --- ## Right Panel Controls You can also manage the configurator from the right panel. Select an object and go to the **Configurator** tab to find the **Material Configurator** section. Material Configurator — right panel controls The right panel provides additional buttons:
Clear Variations Remove Completely Add Variation Refresh UI Apply All
- **Clear Variations** — Removes all material variations from the selected configurator - **Remove Completely** — Deletes the entire configurator from the object - **Add Variation** — Adds the material currently applied to the object (the one you edited in the [Picking](./pbr-materials) panel) as a new variant - **Refresh UI** — Refreshes the configurator UI on the canvas - **Apply All** — Applies changes to all configurator entries --- ## Downloading & Importing Configurations ### Download a Configuration Preset To save your configurator setup for reuse across other scenes: 1. Go to the **Configurator** tab on the right panel 2. Find the **Material Configurator** section 3. Click the **three dots** (⋯) next to the section title 4. Click **Download Preset** A `.json` file will be downloaded to your computer containing all your material configurations. ### Import a Configuration Preset To apply a saved configuration to a new scene: 1. Open the new scene in Playground 2. Drag and drop the `.json` file into the canvas The configurator will automatically apply to objects that have matching material names. This is why it's important to keep consistent material names across your models. ::: warning Material names must match The configurator links to objects by their **material name** (the `name` field in [PBR Materials](./pbr-materials#physical-material) or [Diamond Materials](./diamond-materials#diamond-material)). If you rename a material after creating a configurator, the link will break and the configurator will stop working. Always set your material names before creating configurations. ::: --- ## Video Tutorial ### Transfer Configurator Between Projects
--- ## Related Pages - **[PBR Materials](./pbr-materials)** — Physical material editor for metals, ceramics, and surfaces - **[Diamond Materials](./diamond-materials)** — Diamond material editor for gemstones - **[Material Presets](./material-presets)** — Browse the built-in material library - **[Export Scene Settings](./export-scene-settings)** — Export full scene settings including configurator data - **[Import Scene Settings](./import-scene-settings)** — Import scene configurations - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials --- # Material Configurator Material Configurator The Material Configurator lets you create interactive material variations for your 3D model. When embedded in the [iJewel Viewer](../viewer/introduction), your customers can switch between different metals, gemstone colors, ceramics, pearls, and any other materials — directly on your product page. When you add a configurator, a UI bar appears at the bottom of the canvas. The lower bar shows the configuration name (e.g., "Metal"), and the upper bar displays the available material variants as clickable thumbnails. Configurator UI on the canvas --- ## Adding a Material Configurator — Step by Step ### Step 1: Select the Object Click on the object in the canvas that you want to add material variations to. The object will be highlighted. ### Step 2: Open the Configurator At the top of the canvas, click the **Add Configurator** button. A material library panel will appear with tabs for different categories (Metals, Gems, Ceramics, Pearls, Other). ### Step 3: Choose Materials Click on any material to add it as a variant — it will instantly appear in the configurator bar at the bottom of the canvas. You can add as many variants as you want — there is no limit. Click on a selected material again to remove it. ### Step 4: Done The configuration name is automatically taken from the material name of the selected object. You can now click on different variants in the bottom bar to preview how each material looks on your model. --- ## Adding Gem Variations The process works the same for gemstones. Select a gem object, click **Add Configurator**, and the library will automatically open to the **Gems** tab (since the selected object already has a [Diamond Material](./diamond-materials)). Choose your gem variants the same way. --- ## Adding Custom Materials If you've created a custom material in the [PBR Materials](./pbr-materials) or [Diamond Materials](./diamond-materials) editor (for example, a specific color or texture), you can add it as a variant too: 1. Make sure your object is still selected 2. Make all the material changes you need in the Picking panel 3. At the bottom of the canvas, click the **+** button (Add Current Material) — the last button in the configurator bar This adds your current custom material as a new variant. --- ## Editing the Configuration Name The configuration name appears in the lower bar on the canvas (e.g., "Metal", "Gem"). To change it: 1. Enter Edit mode — either click the **Edit Configurator** button at the top of the canvas (after selecting the object), or right-click on the configuration name and choose **Edit** 2. Change the name in the input field at the top of the material library panel --- ## Editing Variant Names Each material variant has a name that appears as a tooltip on hover. To rename a variant: 1. Hover over the variant thumbnail in the configurator bar 2. A tooltip with the variant name will appear — move your cursor to the right side of the tooltip 3. Click the **pencil icon** to edit the name --- ## Removing a Material Variant There are two ways to remove a variant from the configurator: **Method 1** — Right-click on the variant thumbnail in the configurator bar and click **Delete** **Method 2** — Enter Edit mode and click on the material in the library to deselect it --- ## Deleting an Entire Configuration To remove the entire configurator from an object: --- ## Right Panel Controls You can also manage the configurator from the right panel. Select an object and go to the **Configurator** tab to find the **Material Configurator** section. Material Configurator — right panel controls The right panel provides additional buttons:
Clear Variations Remove Completely Add Variation Refresh UI Apply All
- **Clear Variations** — Removes all material variations from the selected configurator - **Remove Completely** — Deletes the entire configurator from the object - **Add Variation** — Adds the material currently applied to the object (the one you edited in the [Picking](./pbr-materials) panel) as a new variant - **Refresh UI** — Refreshes the configurator UI on the canvas - **Apply All** — Applies changes to all configurator entries --- ## Downloading & Importing Configurations ### Download a Configuration Preset To save your configurator setup for reuse across other scenes: 1. Go to the **Configurator** tab on the right panel 2. Find the **Material Configurator** section 3. Click the **three dots** (⋯) next to the section title 4. Click **Download Preset** A `.json` file will be downloaded to your computer containing all your material configurations. ### Import a Configuration Preset To apply a saved configuration to a new scene: 1. Open the new scene in Playground 2. Drag and drop the `.json` file into the canvas The configurator will automatically apply to objects that have matching material names. This is why it's important to keep consistent material names across your models. ::: warning Material names must match The configurator links to objects by their **material name** (the `name` field in [PBR Materials](./pbr-materials#physical-material) or [Diamond Materials](./diamond-materials#diamond-material)). If you rename a material after creating a configurator, the link will break and the configurator will stop working. Always set your material names before creating configurations. ::: --- ## Video Tutorial ### Transfer Configurator Between Projects
--- ## Related Pages - **[PBR Materials](./pbr-materials)** — Physical material editor for metals, ceramics, and surfaces - **[Diamond Materials](./diamond-materials)** — Diamond material editor for gemstones - **[Material Presets](./material-presets)** — Browse the built-in material library - **[Export Scene Settings](./export-scene-settings)** — Export full scene settings including configurator data - **[Import Scene Settings](./import-scene-settings)** — Import scene configurations - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials --- # Material Configurator Material Configurator The Material Configurator lets you create interactive material variations for your 3D model. When embedded in the [iJewel Viewer](../viewer/introduction), your customers can switch between different metals, gemstone colors, ceramics, pearls, and any other materials — directly on your product page. When you add a configurator, a UI bar appears at the bottom of the canvas. The lower bar shows the configuration name (e.g., "Metal"), and the upper bar displays the available material variants as clickable thumbnails. Configurator UI on the canvas --- ## Adding a Material Configurator — Step by Step ### Step 1: Select the Object Click on the object in the canvas that you want to add material variations to. The object will be highlighted. ### Step 2: Open the Configurator At the top of the canvas, click the **Add Configurator** button. A material library panel will appear with tabs for different categories (Metals, Gems, Ceramics, Pearls, Other). ### Step 3: Choose Materials Click on any material to add it as a variant — it will instantly appear in the configurator bar at the bottom of the canvas. You can add as many variants as you want — there is no limit. Click on a selected material again to remove it. ### Step 4: Done The configuration name is automatically taken from the material name of the selected object. You can now click on different variants in the bottom bar to preview how each material looks on your model. --- ## Adding Gem Variations The process works the same for gemstones. Select a gem object, click **Add Configurator**, and the library will automatically open to the **Gems** tab (since the selected object already has a [Diamond Material](./diamond-materials)). Choose your gem variants the same way. --- ## Adding Custom Materials If you've created a custom material in the [PBR Materials](./pbr-materials) or [Diamond Materials](./diamond-materials) editor (for example, a specific color or texture), you can add it as a variant too: 1. Make sure your object is still selected 2. Make all the material changes you need in the Picking panel 3. At the bottom of the canvas, click the **+** button (Add Current Material) — the last button in the configurator bar This adds your current custom material as a new variant. --- ## Editing the Configuration Name The configuration name appears in the lower bar on the canvas (e.g., "Metal", "Gem"). To change it: 1. Enter Edit mode — either click the **Edit Configurator** button at the top of the canvas (after selecting the object), or right-click on the configuration name and choose **Edit** 2. Change the name in the input field at the top of the material library panel --- ## Editing Variant Names Each material variant has a name that appears as a tooltip on hover. To rename a variant: 1. Hover over the variant thumbnail in the configurator bar 2. A tooltip with the variant name will appear — move your cursor to the right side of the tooltip 3. Click the **pencil icon** to edit the name --- ## Removing a Material Variant There are two ways to remove a variant from the configurator: **Method 1** — Right-click on the variant thumbnail in the configurator bar and click **Delete** **Method 2** — Enter Edit mode and click on the material in the library to deselect it --- ## Deleting an Entire Configuration To remove the entire configurator from an object: --- ## Right Panel Controls You can also manage the configurator from the right panel. Select an object and go to the **Configurator** tab to find the **Material Configurator** section. Material Configurator — right panel controls The right panel provides additional buttons:
Clear Variations Remove Completely Add Variation Refresh UI Apply All
- **Clear Variations** — Removes all material variations from the selected configurator - **Remove Completely** — Deletes the entire configurator from the object - **Add Variation** — Adds the material currently applied to the object (the one you edited in the [Picking](./pbr-materials) panel) as a new variant - **Refresh UI** — Refreshes the configurator UI on the canvas - **Apply All** — Applies changes to all configurator entries --- ## Downloading & Importing Configurations ### Download a Configuration Preset To save your configurator setup for reuse across other scenes: 1. Go to the **Configurator** tab on the right panel 2. Find the **Material Configurator** section 3. Click the **three dots** (⋯) next to the section title 4. Click **Download Preset** A `.json` file will be downloaded to your computer containing all your material configurations. ### Import a Configuration Preset To apply a saved configuration to a new scene: 1. Open the new scene in Playground 2. Drag and drop the `.json` file into the canvas The configurator will automatically apply to objects that have matching material names. This is why it's important to keep consistent material names across your models. ::: warning Material names must match The configurator links to objects by their **material name** (the `name` field in [PBR Materials](./pbr-materials#physical-material) or [Diamond Materials](./diamond-materials#diamond-material)). If you rename a material after creating a configurator, the link will break and the configurator will stop working. Always set your material names before creating configurations. ::: --- ## Video Tutorial ### Transfer Configurator Between Projects
--- ## Related Pages - **[PBR Materials](./pbr-materials)** — Physical material editor for metals, ceramics, and surfaces - **[Diamond Materials](./diamond-materials)** — Diamond material editor for gemstones - **[Material Presets](./material-presets)** — Browse the built-in material library - **[Export Scene Settings](./export-scene-settings)** — Export full scene settings including configurator data - **[Import Scene Settings](./import-scene-settings)** — Import scene configurations - **[FAQ: Materials & Diamonds](./faq-materials)** — Common questions about materials --- # Object Configurator The Object Configurator in Playground allows you to create interactive **object variations** — letting end users switch between different design options (e.g., ring heads, pendant shapes, or bracelet links) directly in the embedded 3D viewer. ## How It Works The Object Configurator operates by **toggling visibility** of objects within a single scene. All object variations are loaded into the scene at once, but only one is visible at a time. When the user selects a different option, the current object is hidden and the selected one is revealed. **Example:** A ring with 5 different head designs — all 5 heads are present in the scene, but only the selected one is displayed. Switching between options is instant. ::: info Because all variations must be included in a single file, this approach results in **larger file sizes**. The more object variations you add, the heavier the scene becomes. ::: ## Video Tutorial Watch how to set up an Object Configurator in Playground step by step: --- ## When to Use The Playground Object Configurator is suitable for: - **Quick prototyping** — testing how different design options look together - **Simple configurations** — a small number of variations (2–5 options) - **Internal previews** — sharing design alternatives with your team before publishing --- ## Advanced: Ring Configurator on iJewel3D Platform For production use and customer-facing configurators, we recommend the **Ring Configurator** available on the iJewel3D Platform. Instead of loading all variations into one heavy file, the Platform Configurator uses an **anchor-based system**: - **Components are separate files** — each head and shank is an independent, lightweight 3D model - **Anchors define placement** — components snap together automatically at predefined anchor points - **Files are swapped dynamically** — only the currently selected combination is loaded, keeping performance optimal - **Hundreds of combinations** — mix and match heads, shanks, diamond shapes, carat sizes, and materials This results in **significantly smaller file sizes** and a smoother user experience, especially for catalogs with many variations. ::: tip Getting Started with Ring Configurator The Ring Configurator documentation covers everything from preparing 3D components to embedding the final configurator on your website: **[Ring Configurator Documentation →](https://docs.ijewel3d.com/ring-configurator/introduction.html)** ::: --- ## Related Pages - **[Material Configurator](./material-configurator)** — Switch materials (metals, gems, textures) interactively - **[Ring Configurator (Platform)](https://docs.ijewel3d.com/ring-configurator/introduction.html)** — Advanced anchor-based configurator for production use --- # Modifiers — Object Rotation Object Rotation modifier The Object Rotation modifier duplicates an object around a circle using instanced copies. Because it creates instances (not full copies), your scene stays lightweight and fast — even with dozens of duplicates. This is especially useful for creating chain links, repeating gemstone patterns, halo settings, and other circular arrangements common in jewelry design. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the PickingPicking tab, in the **Modifiers** section. Select an object in the canvas to see the modifier controls. --- ## Settings
Enable
Checkbox — activates the Object Rotation modifier on the selected object
Rotation Count
Slider — the total number of instances placed around the circle. Higher values produce a denser ring of copies
Axis
Select (X / Y / Z) — the axis around which the copies are rotated. Choose the axis that matches your model's orientation — for example, Y for a ring viewed from above
Rotation Skip
Input — comma-separated list of instance numbers to skip (e.g., 0,1,3,5,7). Skipped positions will be empty, allowing you to create patterns with gaps. Instance numbering starts at 0
::: tip Pivot Point
Make sure your object's pivot point is at the center of the scene, not inside the object itself. If the pivot is inside the object, all copies will stack on top of each other instead of spreading around a circle.
Pivot point at the center of the scene
::: ::: info Settings not appearing? If the modifier settings don't appear after enabling the checkbox, simply deselect the object and select it again — the settings will show up. ::: --- ## Approach 1 — Single Object Use this approach when you have a single piece (like a chain link) and want to repeat it around a circle. ### Step 1: Select the Object Click on the object in the canvas that you want to duplicate. The object will be highlighted and its properties will appear in the right panel. ### Step 2: Enable the Modifier In the right panel under **Modifiers**, check the **Enable** checkbox for Object Rotation. The object will immediately be duplicated around a circle. ### Step 3: Set the Rotation Count Use the **Rotation Count** slider to control how many copies are placed around the circle. Increase the value until your ring or pattern is complete. ### Step 4: Choose the Correct Axis Select the rotation **Axis** (X, Y, or Z) that matches your model's orientation. If the copies appear in the wrong plane, try a different axis. --- ## Approach 2 — Parent Object with Rotation Skip Use this approach when you have a parent object with multiple children (e.g., a chain link with a diamond) and want to skip certain positions so that only some instances include the child objects. ### Step 1: Select the Parent Object To select the entire parent group (including all its children like diamonds and prongs), go to the PickingPicking tab, find the **Hierarchy** section, and click on the parent object's name in the hierarchy tree. This selects the parent along with all child objects beneath it. ### Step 2: Set the Rotation Count Enable the modifier and set the **Rotation Count** to the total number of positions you need. ### Step 3: Use Rotation Skip In the **Rotation Skip** field, enter the instance numbers you want to hide, separated by commas. For example, if you have 30 total positions and want diamonds only at even-numbered positions, enter all the odd numbers: `1,3,5,7,9,11,13,15,17,19,21,23,25,27,29`. Instance numbering starts at `0`. The skipped instances will be removed, creating a pattern where only certain positions show the full parent-child group. --- ## Video Tutorial ### Object Rotation Modifier
--- ## Related Pages - **[Scene Basics](./scene)** — Overview of working with 3D objects - **[Scene Hierarchy](./hierarchy)** — Understanding parent-child relationships - **[Transform Controls](./transform-controls)** — Moving, rotating, and scaling objects - **[PBR Materials](./pbr-materials)** — Physical material editor for metals and surfaces - **[Diamond Materials](./diamond-materials)** — Diamond material editor for gemstones --- # Modifiers — Object Rotation Object Rotation modifier The Object Rotation modifier duplicates an object around a circle using instanced copies. Because it creates instances (not full copies), your scene stays lightweight and fast — even with dozens of duplicates. This is especially useful for creating chain links, repeating gemstone patterns, halo settings, and other circular arrangements common in jewelry design. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the PickingPicking tab, in the **Modifiers** section. Select an object in the canvas to see the modifier controls. --- ## Settings
Enable
Checkbox — activates the Object Rotation modifier on the selected object
Rotation Count
Slider — the total number of instances placed around the circle. Higher values produce a denser ring of copies
Axis
Select (X / Y / Z) — the axis around which the copies are rotated. Choose the axis that matches your model's orientation — for example, Y for a ring viewed from above
Rotation Skip
Input — comma-separated list of instance numbers to skip (e.g., 0,1,3,5,7). Skipped positions will be empty, allowing you to create patterns with gaps. Instance numbering starts at 0
::: tip Pivot Point
Make sure your object's pivot point is at the center of the scene, not inside the object itself. If the pivot is inside the object, all copies will stack on top of each other instead of spreading around a circle.
Pivot point at the center of the scene
::: ::: info Settings not appearing? If the modifier settings don't appear after enabling the checkbox, simply deselect the object and select it again — the settings will show up. ::: --- ## Approach 1 — Single Object Use this approach when you have a single piece (like a chain link) and want to repeat it around a circle. ### Step 1: Select the Object Click on the object in the canvas that you want to duplicate. The object will be highlighted and its properties will appear in the right panel. ### Step 2: Enable the Modifier In the right panel under **Modifiers**, check the **Enable** checkbox for Object Rotation. The object will immediately be duplicated around a circle. ### Step 3: Set the Rotation Count Use the **Rotation Count** slider to control how many copies are placed around the circle. Increase the value until your ring or pattern is complete. ### Step 4: Choose the Correct Axis Select the rotation **Axis** (X, Y, or Z) that matches your model's orientation. If the copies appear in the wrong plane, try a different axis. --- ## Approach 2 — Parent Object with Rotation Skip Use this approach when you have a parent object with multiple children (e.g., a chain link with a diamond) and want to skip certain positions so that only some instances include the child objects. ### Step 1: Select the Parent Object To select the entire parent group (including all its children like diamonds and prongs), go to the PickingPicking tab, find the **Hierarchy** section, and click on the parent object's name in the hierarchy tree. This selects the parent along with all child objects beneath it. ### Step 2: Set the Rotation Count Enable the modifier and set the **Rotation Count** to the total number of positions you need. ### Step 3: Use Rotation Skip In the **Rotation Skip** field, enter the instance numbers you want to hide, separated by commas. For example, if you have 30 total positions and want diamonds only at even-numbered positions, enter all the odd numbers: `1,3,5,7,9,11,13,15,17,19,21,23,25,27,29`. Instance numbering starts at `0`. The skipped instances will be removed, creating a pattern where only certain positions show the full parent-child group. --- ## Video Tutorial ### Object Rotation Modifier
--- ## Related Pages - **[Scene Basics](./scene)** — Overview of working with 3D objects - **[Scene Hierarchy](./hierarchy)** — Understanding parent-child relationships - **[Transform Controls](./transform-controls)** — Moving, rotating, and scaling objects - **[PBR Materials](./pbr-materials)** — Physical material editor for metals and surfaces - **[Diamond Materials](./diamond-materials)** — Diamond material editor for gemstones --- # Rainbow Diamond Coloring Rainbow Diamond Coloring Rainbow Diamond Coloring creates a smooth, seamless color gradient across a series of diamonds. The gradient loops perfectly — the first color flows into the last without any visible break, producing a beautiful infinite rainbow effect. This feature is located in the **Extras** tab on the right panel. --- ## Step-by-Step Guide ### Step 1: Prepare Your Model Before using this feature, your diamonds must be named correctly in your 3D software. Each diamond should have a consistent name prefix followed by a sequential number — for example: `gem001`, `gem002`, `gem003`, … `gem040` The numbering must be sequential so the gradient follows the correct order around the model. This is the only preparation needed — once the names are in order, you're ready to go. ### Step 2: Apply a Diamond Material Select one of the gem objects in the canvas and apply a [Diamond Material](./diamond-materials) to it. Make sure all the diamonds in the sequence share the same material layer. ### Step 3: Open the Extras Tab Go to the ExtrasExtras tab on the right panel and find the **Rainbow Diamond Coloring** section. ### Step 4: Set the Object Name Prefix In the **Object Name Prefix** field, enter only the name part without the numbers. For example, if your diamonds are named `gem001` through `gem040`, type just `gem`. ### Step 5: Set the Count In the **Count** field, enter the total number of diamonds in your sequence. For example, `40` if you have `gem001` to `gem040`. ### Step 6: Set the Loops In the **Loops** field, choose how many times the color gradient should repeat across the full sequence. For example, `1` loop means one full rainbow cycle across all diamonds, `2` loops means the gradient repeats twice. ### Step 7: Choose the Starting Color Click on the color picker and select the starting color for your gradient. The gradient will automatically generate a full rainbow cycle starting from this color. Red is a common choice for a classic rainbow effect. ### Step 8: Apply Click the **Color All Items** button. The rainbow gradient will instantly be applied across all your diamonds in sequence. --- ## Settings
Object Name Prefix
Input — the shared name prefix of your diamond objects, without the sequential numbers (e.g., gem for gem001–gem040)
Count
Input — the total number of diamonds in the sequence
Loops
Input — how many times the full color cycle repeats across all diamonds. 1 produces a single seamless rainbow, higher values create a tighter repeating pattern
Color
Color picker — the starting color for the gradient. The gradient generates a full hue cycle from this color
Color All Items
Button — applies the rainbow gradient to all diamonds matching the prefix
::: warning Diamond naming matters The diamonds must be named with a consistent prefix and sequential numbers (e.g., `gem001`, `gem002`, …). If the naming is inconsistent or the numbers are not sequential, the gradient will not apply correctly. ::: --- ## Related Pages - **[Diamond Materials](./diamond-materials)** — Diamond material editor for gemstones - **[Material Presets](./material-presets)** — Browse the built-in material library - **[Material Configurator](./material-configurator)** — Create interactive material variations - **[Import Models](./import-models)** — How to import 3D models into Playground --- # Snow Fall Particles Snow Fall Particles adds a falling snow effect to your scene — soft, round particles of varying sizes drifting downward. This is a great way to add atmosphere to video exports, seasonal product showcases, or creative marketing content. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the ExtrasExtras tab, in the **Snow Fall Particles** section. --- ## Settings
enabled
Checkbox — activates the snowfall effect in the scene
Bounds size
Slider — the size of the area where particles are generated. Increase to spread snowflakes across a wider area, decrease to concentrate them around the model
Particle size
Slider — the size of individual snowflake particles. Smaller values create fine, delicate snow; larger values produce bigger, more visible flakes
Particle speed
Slider — how fast the particles fall. Lower values create a gentle, slow drift; higher values make the snow fall more rapidly
Bottom clamp
Slider — the lowest point where particles disappear. Adjust this so snowflakes vanish near the ground level rather than falling through it
Paused
Checkbox — pauses the animation. The snowflakes freeze in place, which can be useful for taking still screenshots with snow visible
::: tip Best for video exports The snowfall effect works best in [video exports](./export-videos). Enable the effect, set up your [Camera Views](./camera-views) animation, and export — the snow will be captured in the final video. ::: --- ## Related Pages - **[Export Videos](./export-videos)** — Export animated video renders - **[Camera Views](./camera-views)** — Set up camera animations - **[Background / Environment](./background-environment)** — Background and environment settings - **[Scene Settings](./scene-settings)** — Overview of all scene settings --- # Wave Ground Wave Ground transforms the ground plane into a dynamic, animated surface with wave-like motion. The ground moves like gentle ocean waves, creating a beautiful visual effect — especially on reflective or mirror-like surfaces where the waves produce shifting reflections beneath your jewelry model. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the ExtrasExtras tab, in the **Wave Ground** section. --- ## Settings
enabled
Checkbox — activates the wave animation on the ground plane
Noise scale
Slider — controls the scale of the wave pattern. Lower values create large, broad waves; higher values produce smaller, more detailed ripples
Amplitude
Slider — the height of the waves. Higher values create more pronounced, dramatic waves; lower values produce a subtle, gentle surface motion
Paused
Checkbox — pauses the wave animation. The ground freezes in its current shape, useful for still renders with a wavy surface
::: tip Reflective surfaces Wave Ground looks best when combined with a reflective ground material. The moving waves create dynamic reflections beneath your model that add depth and motion to both the viewport and video exports. ::: --- ## Related Pages - **[Ground](./ground)** — Ground plane settings, material, and blending - **[Background / Environment](./background-environment)** — Background and environment settings - **[Export Videos](./export-videos)** — Export animated video renders - **[Scene Settings](./scene-settings)** — Overview of all scene settings --- # Rhino 3dm Loader When you import a model exported from Rhino, the file may contain extra geometry that isn't part of your actual product — such as line meshes, point meshes, or construction helpers. These elements can clutter the viewport and interfere with how your model looks in the viewer. The **Rhino 3dm Loader** plugin gives you a set of checkboxes to control what gets imported and what gets hidden, so you only see the geometry you need. ## Where to Find It This section is located on the [right panel](./ui-overview#right-panel-—-professional-tools), inside the PluginsPlugins tab, in the **Rhino 3dm Loader** section. This section is always visible, but its settings are used when working with `.3dm` files imported from Rhino. --- ## Settings
importMaterials
Checkbox — imports materials defined in the Rhino file. Enabled by default
forceLayerMaterials
Checkbox — forces materials to follow Rhino layer assignments instead of per-object materials. Enabled by default
replaceWithInstancedMesh
Checkbox — replaces duplicate geometry with instanced meshes for better performance. Disabled by default
hideLineMesh
Checkbox — hides line meshes (curves, edges, wireframes) that may be exported from Rhino. Enable this to remove unwanted lines from the viewport. Enabled by default
hidePointMesh
Checkbox — hides point meshes (control points, construction dots) that may be present in the Rhino file. Enable this to keep the viewport clean. Enabled by default
loadUserDataStrings
Checkbox — loads custom user data strings attached to objects in the Rhino file. Enabled by default
::: tip Clean imports If you see unexpected lines or dots around your model after importing a `.3dm` file, check that **hideLineMesh** and **hidePointMesh** are enabled. This is the most common fix for cluttered Rhino imports. ::: --- ## Related Pages - **[Import Models](./import-models)** — How to import 3D models into Playground - **[Rhino Plugin](../integrations/rhino-plugin)** — iJewel Rhino plugin overview - **[Rhino Plugin Integration](../integrations/rhino-plugin-integration)** — Setting up the Rhino plugin - **[Scene Hierarchy](./hierarchy)** — Understanding object hierarchy in the scene --- # Frequently Asked Questions Answers to the most common questions about iJewel Playground, sourced from our community. Choose a topic below to find what you're looking for. ---
Importing Models
File formats, cameras from Blender, scaling, multi-model scenes
Materials & Diamonds
Textures, engravings, diamond sparkle, material variations
Exporting Images & Videos
Transparent backgrounds, resolution, export speed, formats
Cameras & Animation
Camera paths, Blender import, turntable, animation playback
Scene, Lighting & Environment
HDRI setup, shadows, backgrounds, gradients, ground plane
Rendering & Performance
Blur during interaction, quality settings, mobile issues
Playground & the iJewel Platform
Projects, settings transfer, VJSON, pricing, platform integration
--- ::: tip Can't find your answer? If your question isn't covered here, visit the [iJewel Discord community](https://discord.gg/ijewel3d) or submit a request through the [Helpdesk](../feedback/form). ::: --- # FAQ: Importing Models Frequently asked questions about importing 3D models into iJewel Playground. ---
What file formats does iJewel Playground support? iJewel Playground supports **GLB**, **GLTF**, **3DM** (Rhino), **FBX**, and **OBJ** formats. For the best results — including full PBR materials, textures, and animations — use **GLB/GLTF**. This is the recommended format for all major 3D software (Blender, 3ds Max, Maya, Cinema 4D, Rhino).
Can I use texture maps or vertex colors from other software? Yes. All major 3D programs (Maya, 3ds Max, Blender, Rhino) export GLTF/GLB with PBR material and texture support. iJewel Playground will read the PBR material information and apply it correctly. For the best texture/animation fidelity, always export as GLB or GLTF rather than OBJ or FBX.
My model appears black or dark after loading. What's wrong? This usually means the model is missing an environment map. By default, Playground applies a lighting environment, but if your model was exported without materials or with incorrect settings, it may appear dark. Try the following: 1. Go to **Scene → Background / Environment** and make sure an HDRI environment map is loaded 2. Check that your model's materials exported correctly from your 3D software 3. If you're loading a jewelry model with diamonds, make sure diamond layers have unique names — Playground uses layer/material names to assign diamond materials
How do I import a camera from Blender? Export your Blender scene as a **GLB file with cameras included** (check the camera export option in Blender's GLTF export settings). When you load this GLB into Playground, the camera will appear in **Scene → [Cameras (Loaded)](./cameras-loaded)**. From there, select the camera and click **Activate Main** to switch to it. Make sure to **bake the animation as keyframes** before exporting.
My camera animation from Blender doesn't play in Playground. What am I doing wrong? When creating camera animations in Blender, make sure to: 1. **Bake the animation as keyframes** — constraints and drivers don't export to GLTF 2. **Export as GLB with cameras enabled** in the export settings 3. In Playground, go to **Scene → Cameras (Loaded)**, select the camera, and click **Activate Main** 4. Play the animation using the **GLTF Animation** controls
How do I align an imported model from Rhino/Matrix with a Blender camera animation? You have two options: 1. Export the 3DM from Rhino/Matrix and convert it to GLB in Playground. Then edit this GLB in Blender to add the camera animation, and export as GLB with animations 2. Export only the camera as a separate GLB from Blender, then drag and drop both files (the 3DM model and the camera GLB) into Playground one by one
How can I scale or reposition my imported model? 1. Select your model — click on it in the viewport or find it in the [Hierarchy](./hierarchy) 2. Go to [Transform Controls](./transform-controls) and enable the gizmo 3. Switch the **Mode** to Scale (or Translate/Rotate) and use the gizmo handles to adjust You can also type exact values in the **Position**, **Rotation**, and **Scale** fields in the [Picking](./picking) panel.
Can I import multiple models into the same scene? Yes. Simply drag and drop additional files into Playground or use the import button. Each new model is added to the existing scene. You can then reposition them using [Transform Controls](./transform-controls).
How should I name layers in Blender/Rhino for automatic material assignment? iJewel uses layer/material names to automatically assign materials. The recommended naming convention is: layers named **Metal** (or Metal Yellow Gold, Metal Rose Gold, etc.) for metal parts, and **Diamond** (or Diamond Round, Diamond Princess, etc.) for diamond/gem parts — each unique diamond cut should have a unique layer name. ::: tip Video Tutorial Watch the [Layer Naming in Blender](https://www.youtube.com/watch?v=8sfDdlF4F9I) tutorial. For Rhino, see the [Preparing 3D Models](https://docs.ijewel3d.com/batchx/prepare-3dmodels.html#assigning-layers-to-objects-in-rhino) guide. :::
My model file is too large. How can I reduce it? Drop your model into Playground, then export it as GLB from the **Export** tab with **compression enabled**. This will apply Draco compression and can significantly reduce file size. You can also check individual texture sizes in **Picking → Physical Material** — large texture maps are often the main contributor to file size.
--- ## Related Pages - **[Import Models](./import-models)** — Full guide on importing 3D models - **[Import Materials](./import-materials)** — Importing material presets - **[Import Scene Settings](./import-scene-settings)** — Importing scene configurations - **[Cameras (Loaded)](./cameras-loaded)** — Working with imported cameras --- # FAQ: Materials & Diamonds Frequently asked questions about materials, diamonds, and textures in iJewel Playground. ---
How do I change the rotation of a brushed metal texture? Go to **Picking → Physical Material → Map Sampler** and adjust the **Rotation** property. The Map Sampler settings are available for any texture map (albedo, roughness, metalness, normal, etc.). Note that your model needs proper UV coordinates for this to work — make sure the Triplanar extension is disabled. ::: tip Video Tutorial Watch [Fix Brushed Textures | UV Unwrap Solution](https://www.youtube.com/watch?v=4zqofmJTq64) if your brushed textures look incorrect — this covers UV unwrapping and disabling Triplanar. :::
How do I get a deeper/clearer engraving? Use the **Simple Text** modifier along with **Parallax Mapping**: 1. Go to **Modifiers → Simple Text → Add Text** and type your engraving. Make sure to click **Apply** 2. Enable **Modifiers → Parallax Mapping** 3. To control the depth, adjust **bumpScale** in **Picking → Physical Material → Bump/Normal**
My diamond looks white/plain instead of sparkly. What's wrong? This is typically caused by a missing or inappropriate environment map for the diamond material. Try: 1. Make sure an HDRI environment map is loaded in **Scene → Background / Environment** 2. Check the **Gem Env** setting — if it's set to None, the diamond won't reflect anything. Select an appropriate diamond environment map 3. Adjust the **Bloom** parameters in **Post Processing** — this adds the sparkle/glow effect 4. Try adjusting **envRotation** values in the diamond material settings
Can I apply a different HDRI specifically for diamonds? Yes. You can set separate environment map slots for Gem/Diamond materials. Additionally, you can create a custom HDR map specifically optimized for diamond sparkle. ::: tip Video Tutorial Watch [Creating Custom HDR for Diamonds](https://www.youtube.com/watch?v=D5BV9S5izG0) for a detailed walkthrough. :::
Why do my diamonds have pixelated seams? Pixelated seams on diamonds are usually related to **normal map resolution**. The diamond mesh may have low-resolution normals or overlapping/broken geometry. Check the following: 1. Make sure your diamond mesh has clean, non-overlapping geometry 2. Check that normals are correct — avoid modifiers like mirroring that can create overlapping meshes 3. Use the diamond models provided by iJewel, which are optimized for the renderer
Unnatural black shadows appear inside my marquise-cut diamond. How do I fix this? This is often caused by **incorrect normals** or **broken/overlapping meshes** in the diamond geometry. This can happen when you use modifiers like mirroring in 3D software. Try: 1. Recalculate normals in your 3D software before exporting — see the [Fix Wrong Normals](https://www.youtube.com/watch?v=iivi9HyJpWU) tutorial 2. Check for overlapping or intersecting geometry 3. Try different HDRI environments — some environment maps produce better results with certain cuts 4. Use the diamond models provided by iJewel, which are verified to work correctly
How can I reduce diamond sparkle frequency in videos? Diamond sparkle is mainly controlled by the **Gem HDR environment maps**. To reduce sparkle frequency: 1. Try using different HDRI maps in the Gem Env setting 2. Adjust the **Bloom** parameters in Post Processing 3. Modify the **envRotation** values in the diamond material
Can I apply a different HDRI to diamonds and metal separately? Yes. In Playground, you can set separate environment map slots for **Metal** and **Gem/Diamond** materials. Go to **Scene → Background / Environment** and look for the Metal Env and Gem Env options. This lets you use a studio HDRI for metal reflections and a different, more sparkly HDRI for diamond refraction.
How do I create material variations and save them? 1. Click on an object in the viewport to select it 2. In the **Configurator** tab, click **Add Variation** — this adds a material variation icon 3. Modify the material properties (color, roughness, metalness, etc.) for each variation 4. Repeat for multiple objects and variations 5. To save all variations, click the three dots (⋯) above the Material Configurator UI and click **Download Preset** — this saves to a JSON file that can be reused across models with matching object/material names ::: tip Video Tutorials - Watch [Transfer Configurator Between Projects](https://www.youtube.com/watch?v=c_cph8q_vA8) for reusing material configurations - Watch [Quick Material Export & Import Tutorial](https://www.youtube.com/watch?v=59dNYczASqU) for downloading, exporting, and applying materials to ring components and gemstones :::
My model's file size is too large because of textures. How do I check which textures are heavy? Go to **Picking → Physical Material** and check the different texture maps (Albedo, Roughness, Metalness, Normal, etc.). You can download individual texture images to check their sizes. Large texture maps are usually the main contributor to file size — consider reducing their resolution before re-importing.
The model looks fine in Playground but terrible in Shopify. Why? Shopify's default 3D viewer does not support iJewel's advanced lighting, diamond rendering, or post-processing effects. To get the same quality on your website, embed your model using the [iJewel Viewer SDK](../viewer/introduction) or use [iframe embedding](../integrations/shopify-embedding).
--- ### Useful Video Tutorials - [Fix Brushed Textures | UV Unwrap Solution](https://www.youtube.com/watch?v=4zqofmJTq64) — Fix brushed texture issues with UV unwrapping - [Quick Material Export & Import Tutorial](https://www.youtube.com/watch?v=59dNYczASqU) — Export and import materials between projects ## Related Pages - **[Picking](./picking)** — Select objects and edit materials - **[Background / Environment](./background-environment)** — HDRI environment settings - **[Export Materials](./export-materials)** — Save and share material presets - **[Import Materials](./import-materials)** — Load saved material presets --- # FAQ: Exporting Images & Videos Frequently asked questions about exporting images and videos from iJewel Playground. ---
How do I export an image with a transparent background? Follow these steps: 1. Go to **Post Processing → Tonemapping** and set **Clip Background** to true (or set **Background Alpha** to 0) 2. Go to **Scene → Ground** and uncheck **Visible** (or set **Render to Depth** to false) 3. Go to **Scene → Progressive Shadow** and disable it 4. Choose **PNG** as the export format (JPG does not support transparency) 5. Export the image from the **Export** tab See the full guide in [Export Images — Transparent Background](./export-images#transparent-background). ::: tip Video Tutorial Watch [How to Make Pure White and Transparent Background](https://www.youtube.com/watch?v=GCJIOmcEaPo) for a step-by-step visual guide. :::
My exported image is blurry despite using high settings. What's wrong? ::: tip Video Tutorial Watch the [Common Export Issues](https://www.youtube.com/watch?v=UT4p-IFrbjI) tutorial for solutions to frequent export problems. Also see [Resolution & Export from Playground](https://www.youtube.com/watch?v=FAqfTMBAaBA) for a complete guide on resolution and export settings. ::: Try these steps: 1. Instead of using Scale, set a **custom resolution** in **Viewer → Renderer** — type the exact pixel dimensions you need 2. Try the **Tiled Export** option in **Export → Image Export** which can produce higher-quality results at large resolutions 3. Check that **Depth of Field** is disabled in Post Processing — this effect intentionally blurs parts of the image 4. Make sure **Anti-Aliasing** (TAA/Progressive) is set to a sufficient number of frames
What is the maximum export resolution? The maximum resolution depends on your device's GPU capabilities. Most devices support up to **2160px** in the standard export mode. For higher resolutions (3000×3000px and above), use the **Tiled Export** feature in **Export → Image Export**, which renders the image in tiles and stitches them together.
Video export takes 10+ minutes. How can I speed it up? Long export times are usually caused by high anti-aliasing settings with custom backgrounds. To speed things up: 1. Reduce the **Progressive** frame count in **Anti-Aliasing** settings to something like 4 or 8 (instead of 16 or 32) 2. Lower the export resolution 3. Reduce the **FPS** — 24 fps is often sufficient for smooth turntable animations 4. Don't close the browser tab during export — wait until iJewel finishes converting frames to video. You can monitor the progress in the browser console
What are the best settings for video export? There's no single "best" setting — it depends on your use case: - **Turntable product shots**: 24–30 FPS, 4–8 AA Progressive frames, 1080p or 1440p resolution - **Camera path animations**: match the FPS to your original animation (usually 24 or 30), higher AA for final renders - **Quick previews**: 24 FPS, low AA, 720p You can find all these options in **Export → Video Export**. ::: tip Video Tutorial Watch [Resolution & Export from Playground](https://www.youtube.com/watch?v=FAqfTMBAaBA) for a walkthrough of resolution and export settings. :::
How do I set the speed and direction of a turntable video? Go to **Export → Video Export** where you'll find controls for turntable rotation speed, direction (clockwise or anticlockwise), and total rotation angle. ::: tip Video Tutorial Watch [Perfect 360° Turntable In 2 Minutes](https://www.youtube.com/watch?v=304Hzog-7bg) for a quick guide on setting up turntable animations. :::
Can I export 360 still frames instead of an MP4 video? Currently, only MP4 video export is available. PNG sequence export is planned for a future release.
Can I change the export format from PNG to JPEG for quick snapshots? Yes. In the export options, you can choose between PNG and JPEG formats. PNG is the default because it supports transparency, but JPEG produces smaller files and is faster for quick captures.
How do I render a ring on a hand model? You can import a hand 3D model alongside your ring and position them together in Playground. A free downloadable hand model (Blender file) is available in the description of this tutorial: ::: tip Video Tutorial Watch the [Ring on Hand Model](https://www.youtube.com/watch?v=TJNWi6AgZk0) tutorial — includes a free hand model download link in the video description. :::
Can I add my company logo to exported videos? This feature is not available in Playground at the moment. You would need to add your logo in a video editing tool after exporting. This feature is planned for a future update.
Can I remove the encryption from an exported file? Yes. Open the encrypted file in Playground (you'll need the password), then re-export it from the **Export** tab with the encryption checkbox unchecked.
--- ## Related Pages - **[Export Images](./export-images)** — Full guide on image export settings - **[Export Videos](./export-videos)** — Full guide on video export settings - **[Export Models](./export-models)** — Exporting 3D model files - **[Renderer Settings](./renderer-settings)** — Resolution and quality configuration --- # FAQ: Cameras & Animation Frequently asked questions about cameras, camera paths, and animations in iJewel Playground. ---
How do I import a camera path from Blender? 1. Create your camera animation in Blender with keyframes 2. **Bake the animation** — constraints and drivers don't export to GLTF format 3. Export as **GLB with cameras enabled** (check the camera option in Blender's GLTF export dialog) 4. Drop the GLB file into Playground 5. Go to **Scene → [Cameras (Loaded)](./cameras-loaded)**, select your camera, and click **Activate Main** 6. Play the animation with the **GLTF Animation** controls See the full tutorial on the [Cameras (Loaded)](./cameras-loaded#tutorial-creating-a-camera-path-and-rendering-it-in-playground) page.
My camera animation from Blender doesn't play. What's wrong? The most common causes: 1. The animation wasn't **baked as keyframes** — Blender constraints (Track To, Follow Path) don't export to GLTF 2. The camera wasn't included in the GLTF export settings 3. You haven't activated the camera — go to **Scene → Cameras (Loaded)**, select it, and click **Activate Main** 4. The animation player is paused — check the GLTF Animation controls
How do I align a Rhino/Matrix model with a Blender camera path? Two approaches: 1. **Convert first**: Export 3DM from Rhino → convert to GLB in Playground → edit in Blender (add camera animation) → export as GLB with animations → load into Playground 2. **Load separately**: Export camera-only GLB from Blender, then drag both the 3DM model file and the camera GLB into Playground one by one
How do I create a turntable animation? For a simple turntable, use the built-in turntable recording feature in **Export → Video Export**. You can set rotation speed, direction, and angle there. For more complex turntable animations with custom speeds or easing, create the camera path in Blender and import it as described above. ::: tip Video Tutorial Watch [Perfect 360° Turntable In 2 Minutes](https://www.youtube.com/watch?v=304Hzog-7bg) for a quick guide on creating turntable animations. :::
How do I create a pendant animation? Create the pendant swing/movement animation in Blender, export as GLB with animations, and load into Playground. You can then play the animation back and record it. ::: tip Video Tutorial Watch the [Pendant Animation](https://www.youtube.com/watch?v=VQa6D33y8IA) tutorial for a complete walkthrough. :::
Can I create a shadow rotation animation (shadows moving around the model)? Yes. The best approach is to create **directional lights in Blender**, animate them to rotate around the model while keeping the target on the jewelry, and export as GLB with animations. In Playground, this will appear as GLTF Animations that you can play back.
How do I save and reuse a camera position? You can use **[Camera Views](./camera-views)** to save and switch between fixed camera angles. This is also useful for taking snapshots from specific positions. See the full [Camera Views documentation](./camera-views) for a step-by-step guide. ::: tip Video Tutorial Watch the [Camera Views](https://www.youtube.com/watch?v=jdePxecZRkQ) tutorial for setting up and using saved camera positions. ::: You can also export camera settings as part of a **scene preset**. Go to the scene settings and use the **Download Preset** option from the three dots menu (⋯). This saves a JSON/VJSON file that includes camera position, rotation, and other settings. Drop this file back into Playground to restore the same camera angle.
How can I create an environment map rotation animation? Playground supports environment map rotation animations. You can create them in the **Animation** tab using the environment rotation animation feature. ::: tip Video Tutorial Watch the [Environment Map Rotation Animation](https://drive.google.com/file/d/17VxPoCluLMtVONHQqjuMCrXoiFRMOStO/view?usp=sharing) guide for a step-by-step walkthrough. :::
Can I use poses to set consistent angles across different models? Poses are currently not saved between sessions. Each model has different proportions, so the same transform values (rotation/position) produce different results on different models. For consistent angles, use the **camera position** values instead — these are independent of the model and can be saved as presets.
--- ## Related Pages - **[Cameras (Loaded)](./cameras-loaded)** — Full documentation on imported cameras - **[Export Videos](./export-videos)** — Recording and exporting video animations - **[Scene Settings](./scene-settings)** — Overview of all Scene tab sections - **[Transform Controls](./transform-controls)** — Move, rotate, and scale objects --- # FAQ: Scene, Lighting & Environment Frequently asked questions about scene setup, lighting, HDRI environments, shadows, and backgrounds in iJewel Playground. ---
How do I set up an HDRI environment? Go to **Scene → [Background / Environment](./background-environment)** and load an HDRI map. You can use the built-in presets or upload your own `.hdr` or `.exr` file. The environment map controls both the background appearance and the lighting/reflections on your model. Adjust **Intensity** and **Rotation** to fine-tune the look. You can also create your own custom HDRI maps using the [HDRI Editor](https://editor.hdrmap.com/#).
How do I make the background transparent? 1. Go to **Post Processing → Tonemapping** and set **Clip Background** to true (or set Background Alpha to 0) 2. Disable **Scene → Ground → Visible** 3. Disable **Scene → Progressive Shadow** 4. Export as **PNG** (not JPG — JPG doesn't support transparency) See the full guide in [Export Images — Transparent Background](./export-images#transparent-background). ::: tip Video Tutorial Watch [How to Make Pure White and Transparent Background](https://www.youtube.com/watch?v=GCJIOmcEaPo) for a step-by-step walkthrough. :::
I get a message "Background must be same as environment." What does this mean? This message comes from the **HDRi Ground** plugin. It appears when the background texture is not the same as the environment texture. To fix it, make sure both are set to the same HDRI map, or simply confirm the dialog to sync them. If you see this message even when they seem equal, try updating to the latest Playground version.
How do I remove the ground plane? Go to **Scene → [Ground](./ground)** and uncheck the **Visible** checkbox. This removes the ground so your model appears to float — useful for pendants, earrings, or any suspended jewelry.
How do I fix the ground position? It moves when I import new models. The ground adjusts automatically to match the model's position. To lock it at a specific height, go to **Scene → [Ground](./ground) → Height** and set the value manually. This keeps the ground at a fixed level regardless of what you import.
Why do shadows rotate with my model during turntable recording? By default, progressive shadows are baked and move with the scene. To get shadows that stay fixed while the model rotates: 1. Create **directional lights in Blender** with animated rotation (keeping the target on the jewelry) 2. Export as GLB with animations 3. In Playground, these will appear as GLTF Animations — play them during recording Alternatively, you can disable baked shadows on the ground and use real-time shadows from scene lights, though this requires more setup. ::: tip Video Tutorial Watch [How to Create Custom Shadows](https://www.youtube.com/watch?v=269LnNYZDh0) for a complete guide on shadow customization. :::
Can I disable baked shadows and use real-time shadows instead? Yes. Disable baked shadows on the ground from **Scene → Ground** settings (uncheck shadow-related options). Then add lights in **Scene → [Lights](./lights)** with shadow casting enabled. When moving a light, the scene will re-render automatically with updated shadows.
How do I use a custom background image? Go to **Scene → [Background / Environment](./background-environment)** and upload an image file. Note that background images may scale differently on different screen sizes. For consistent results across devices, use a square or wide-aspect image and test at your target resolution.
My custom background image turns grayscale or black after saving. Why? This is a known issue in some versions. Try: 1. Re-uploading the background image after loading your model 2. Making sure **Tonemapping** settings aren't affecting the background color 3. Updating to the latest Playground version
What's the difference between Tonemapping and Clip Background? **Tonemapping** adjusts the color grading and exposure of the entire render (similar to a photo filter). **Clip Background** is a boolean setting within Tonemapping that controls whether the background is rendered or made transparent. When Clip Background is enabled, the background becomes transparent for export — the model itself is still tonemapped normally.
How do I create a custom gradient background? Use the **[Gradient SVG](./gradient-svg)** section in the Scene tab. Enable it, choose between Linear or Radial gradient type, pick two colors, and adjust the angle and positions. You can also apply the gradient to the scene background with the **Apply to Background** checkbox. ::: tip Video Tutorial Watch [How to Change Background & Ground Color](https://www.youtube.com/watch?v=q989o_dq7yo) for a visual guide on changing background and ground colors. :::
--- ## Related Pages - **[Background / Environment](./background-environment)** — Full environment setup guide - **[Ground](./ground)** — Ground plane settings - **[Progressive Shadow](./progressive-shadow)** — Shadow configuration - **[Lights](./lights)** — Scene lighting - **[Gradient SVG](./gradient-svg)** — Gradient backgrounds - **[HDRi Ground](./hdri-ground)** — HDRI ground projection ### Useful Video Tutorials - [How to Make Pure White and Transparent Background](https://www.youtube.com/watch?v=GCJIOmcEaPo) — Set up pure white or transparent backgrounds - [How to Change Background & Ground Color](https://www.youtube.com/watch?v=q989o_dq7yo) — Change background and ground colors - [How to Create Custom Shadows](https://www.youtube.com/watch?v=269LnNYZDh0) — Shadow customization and positioning - [Rendering Tutorial — General Setup](https://www.youtube.com/watch?v=P0R38Y2S-b0) — Overview of scene setup and rendering workflow - [Creating Custom HDR for Diamonds](https://www.youtube.com/watch?v=D5BV9S5izG0) — Build your own HDRI maps for gem materials --- # FAQ: Rendering & Performance Frequently asked questions about render quality, performance, and device-specific issues in iJewel Playground. ---
Why is my model blurry while rotating or zooming? During interaction (orbiting, zooming, panning), Playground renders at a lower quality for responsiveness and then refines the image once you stop. This is normal behavior — the final high-quality render appears after you release the mouse. If the blur persists after interaction stops, check: 1. **Renderer → Scale** — make sure it's set to 1 or higher (lower values reduce resolution for performance) 2. **Anti-Aliasing** settings — increase TAA/Progressive frame count for sharper results 3. **Depth of Field** in Post Processing — disable it if you don't need selective focus
How do I improve overall render quality? Several settings affect render quality: 1. **Renderer → Scale** — set to 1 for native resolution, or higher for supersampling 2. **Renderer → Mode** — use the highest quality mode available 3. **Anti-Aliasing (TAA)** — increase Progressive frame count (8–16 gives good results) 4. **SSAO** (Screen Space Ambient Occlusion) — adds subtle shadows in crevices 5. **SSR** (Screen Space Reflections) — improves reflection accuracy 6. **Bloom** — adds glow to bright areas (especially useful for diamonds) See [Renderer Settings](./renderer-settings) for a full explanation of quality modes. ::: tip Video Tutorial Watch [Resolution & Export from Playground](https://www.youtube.com/watch?v=FAqfTMBAaBA) for a visual walkthrough of resolution and quality settings. :::
The render looks different on mobile vs desktop. Why? Mobile devices have lower GPU power and memory, so Playground may automatically reduce quality settings. Additionally: 1. Screen size and pixel density differ — the same resolution looks different on a phone vs a monitor 2. iOS has a ~350–400 MB memory limit for WebGL — exceeding it causes the page to refresh 3. Touch interactions (drag vs scroll) may behave differently than mouse controls 4. Some post-processing effects may be disabled automatically on lower-end devices
My page refreshes/crashes on iOS when loading complex models. What's happening? iOS Safari has a strict memory limit for WebGL content (approximately 350–400 MB, depending on the iPhone model). When your scene exceeds this, iOS force-refreshes the page. To stay within limits: 1. Use smaller texture maps — resize textures to 1024×1024 or lower for mobile 2. Reduce the number of diamonds — configure **cache keys** to reuse diamond rendering resources 3. Lower the Renderer Scale on mobile 4. Use compressed GLB files (with Draco compression)
What does the Renderer Scale setting do? **Scale** controls the internal rendering resolution relative to the canvas size. A scale of 1 means native resolution. Scale 0.5 renders at half resolution (faster but blurrier). Scale 2 renders at double resolution (sharper but slower). For final exports, use Scale 1 or higher. For real-time preview, Scale 0.5–1 is usually sufficient. See [Renderer Settings](./renderer-settings) for more details.
Anti-aliasing breaks when playing model animation. Is this a known issue? Yes, this can happen because TAA (Temporal Anti-Aliasing) relies on accumulating multiple frames. During animation playback, the scene changes every frame, which prevents proper accumulation. Try: 1. Increasing the **Progressive** frame count in Anti-Aliasing settings 2. For final video exports, Playground renders each frame with full AA — so the exported video will look better than the real-time preview
How do I record high-quality videos without quality depending on my device? Use Playground's built-in video export (**Export → Video Export**) rather than screen recording. The built-in exporter renders each frame at full quality regardless of your device's real-time performance — it captures frames one by one, so even a slower device produces the same quality output (it just takes longer).
--- ### Useful Video Tutorials - [Resolution & Export from Playground](https://www.youtube.com/watch?v=FAqfTMBAaBA) — Resolution, scale, and export settings walkthrough ## Related Pages - **[Renderer Settings](./renderer-settings)** — Resolution, scale, and quality mode configuration - **[Export Images](./export-images)** — Image export with quality settings - **[Export Videos](./export-videos)** — Video export and recording - **[UI Overview](./ui-overview)** — Full interface layout --- # FAQ: Playground & the iJewel Platform Frequently asked questions about Playground features, projects, settings transfer, and general workflow within the iJewel platform. ---
Is iJewel Playground a CAD program? No. Playground is a real-time **3D rendering and visualization editor** — not a modeling tool. For a full overview of all iJewel products, watch the [iJewel Products Overview](https://www.youtube.com/watch?v=PLP0K2F1hQI) video. It's designed for creating/editing materials, optimizing models, setting up lighting and camera angles, and exporting images, videos, or viewer-ready files. You can move and transform objects, and generate simple primitives (sphere, box, torus, etc.), but it's not a replacement for 3D modeling software like Blender, Rhino, or 3ds Max.
Is Playground free to use? Playground has a **Free** tier with basic features. **Premium** (5 library slots) and **Advance** (100 library slots) tiers unlock additional features like higher export resolutions, more material presets, and advanced post-processing. For commercial use, a subscription-based license is required. See [License and Pricing](../introduction/license) for details.
How do I reopen a project I previously saved on the iJewel platform? Open Playground from the iJewel platform and load the saved project — it reopens with your model and settings. If your version doesn't list the project directly, download its GLB file and drag it into Playground.
My Playground settings don't transfer when I save a model to the iJewel platform. Why? When you export a GLB from Playground, some advanced settings (post-processing, certain plugin configurations) may not be preserved in the GLB format. For full settings transfer: 1. Export the **scene settings as VJSON** from the Export tab — this captures all environment, lighting, and plugin settings 2. Keep both the GLB model and the VJSON together when saving to the platform 3. Alternatively, save directly from Playground if that option is available in your version
How do I save and reuse scene settings across different models? 1. Set up your scene the way you want (lighting, environment, shadows, post-processing) 2. Go to the **Export** tab and download the scene preset as a **VJSON** file 3. For a new model, drop the model into Playground first, then drag and drop the VJSON file — it will apply all saved settings You can also download individual presets (materials only, animations only) using the three dots menu (⋯) above specific UI sections.
My zoom limits reset after saving. How do I fix this? Zoom limits and camera constraints are stored as part of the camera/viewer settings. When exporting, make sure to include camera settings in your VJSON export. If the issue persists, set the zoom limits again in Playground and save.
Can I save files larger than 50 MB in Playground? There is a file size limit for saving directly from Playground to the iJewel platform. For larger files: 1. Export the GLB to your local computer first (no size limit for local download) 2. Compress the file by enabling **Draco compression** in the export options 3. Check texture sizes — large textures are usually the main contributor. Reduce texture resolution in **Picking → Physical Material**
How does Playground fit into the iJewel platform? **Playground** is the 3D editor inside the **iJewel platform** — it's where you open 3D files and configure materials, lighting, cameras, and export images/videos. The wider platform is where those configured models are managed, hosted, embedded on websites, shared via links, or served through the viewer SDK.
How do I match a camera position from my 3D software to Playground? Go to the camera settings in Playground (available in the viewer/camera controls) and manually set the **Position** and **Rotation** values to match your 3D software. You can also export the camera from your 3D software as part of a GLB file, and it will appear in **Scene → [Cameras (Loaded)](./cameras-loaded)**.
Can I use Playground with multiple objects and create a configurator? Yes. Load multiple objects into the scene, then use the **Configurator** tab to set up material variations for each object. Click on an object, add variations with **Add Variation**, and configure each one. When exported, the configurator data can be used with the iJewel Viewer SDK to build interactive product configurators on your website.
--- ## Related Pages - **[Introduction](./introduction)** — What is iJewel Playground - **[Quick Start](./quick-start)** — Getting started guide - **[UI Overview](./ui-overview)** — Full interface layout - **[Export Scene Settings](./export-scene-settings)** — Exporting VJSON files - **[Import Scene Settings](./import-scene-settings)** — Importing scene configurations --- # iJewel3D BatchX ![iJewel BatchX](../assets/images/batchx_hero.webp) iJewel3D BatchX is a downloadable app for Windows and MacOS, to quickly render images and models 3D models in bulk, applying various combinations of materials, camera views, models etc. All rendering happens on your local machine, using state of the art rendering algorithms to reduce render-times by 100-500x. With BatchX, it's possible to render a `2048x2048` size, `10 sec` turn-table video in under `20 sec` on simple laptop. With a GPU desktop, it's realtime. You can try BatchX with a free 30 Day trial on every device (with no credit card or commitments) - [Download Now](https://batchx.ijewel3d.com/). ## License After 30 days of free trial, BatchX requires an yearly license to continue using the software. The license is locked to one device, and cannot be transferred to another device. The license includes all updates and fixes for the software while the license is active. Get a BatchX License Key directly from iJewel3D License Portal - [Buy Now](https://license.ijewel3d.com/payment/checkout/IJewel3D_BatchX) The images/assets exported with BatchX can be used commercially without any restrictions even after the license is expired (Not applicable to trial licenses) ::: tip To buy multiple licenses, check for discounts or for enterprise licensing, contact us at [sales@ijewel3d.com](mailto:sales@ijewel3d.com) ::: ::: warning Sharing and reselling the license keys is strictly prohibited and will result in invalidation of the license and blacklisting of the device. Any attempt to bypass or crack the licensing system will result in immediate termination of the license and legal action. ::: ::: details Transferring It is possible to transfer the license between machines in some cases by contacting us at [batchx@ijewel3d.com](mailto:batchx@ijewel3d.com). This is only allowed when the previous machine is no longer in use. ::: ## Video Tutorials To go through the entire process in detail, check out the following playlist. Watch the complete playlist on Youtube - https://www.youtube.com/watch?v=97Nu5WGWdNs&list=PLIWKi7kUUJPgoGuQUCOIeAuk9xPuuMZQh ## Getting Started The next few sections will cover the details on using BatchX for automating your media generation process. ### [1. Preparing 3D Models](./prepare-3dmodels) Learn about preparing your 3d files, properly layering them, and some other details. [![iJewel 3D](../assets/images/intro_banner.webp)](./prepare-3dmodels) ### [2. Preparing Scene Settings](./prepare-scene-settings) Learn how to prepare materials like diamonds, metals, enamels, and scene settings like shadows, reflections, ground and much more... [![iJewel 3D](../assets/images/configurator_banner.webp)](./prepare-scene-settings) ### [3. Generate Images and Videos](./generate-media) Ready to start making thousands of images and videos with a single click! [![iJewel 3D](../assets/images/batchx_hero.webp)](./prepare-3dmodels) ## System recommendation ### Mac * Apple Mac with Intel or Apple processor. Apple processor M1 and above is preferred * Mac OS 13(Ventura) and above * RAM - 16 GB or more * Internet connection for download and license validation ### Windows * Windows 10 and above * RAM - 16 GB or more * Nvidia graphics card is preferred with a video memory of 8 GB or more * Internet connection for download and license validation --- # Prepare 3D Models for BatchX iJewel BatchX supports importing multiple file formats like 3dm, fbx, obj, glb/gltf and stl. Though its not necessasry, but we recommend to use 3dm file format, as most designers work in Matrix/Matrix gold/Rhino for designing the jewellery CAD files, and you can export the CAD file as 3dm from these softwares. For Rhino users, we recommend the following guidelines ## Assigning Layers to Objects in Rhino Every 3D model in Rhino, is divided into 3D objects, and each object can have an associated layer. Here is an example screenshot of layers associated with a 3D model. ![iJewel Photo-realistic Rendering](../assets/images/rhino_layers1.webp) And all the layers present in the 3D model: ![iJewel Photo-realistic Rendering](../assets/images/rhino_layers2.webp) To prepare a batch of 3d models for rendering in BatchX, make sure that - The layers are named consistently across all the files - Unique diamond shapes(round, pear, marquise, ...) should be put in separate layers for accurate diamond cuts - Similar diamond shapes, including transforms(rotation/uniform scale/translation) should be put in same layers whenever possible - Similar diamond shapes, including transforms(rotation/uniform scale/translation) should be put in different layers, if different material needs to be assigned - Seperate layers should be created if multi tone metals needs to be created(for example head, shank...) ::: info Although not necessary, its recommended to give the following layer names to the objects: - Metals with a layer name Metal 01, Metal 02,..... - Diamonds/Gemstones with a layer name Gem 01, Gem 02,..... - Pearls with a layer name Pearl 01, Pearl 02,.... - Ceramic/Enamels with a layer name Ceramic 01, Ceramic 02,.... ::: BatchX creates a new material for each layer in the 3dm file, and creates images and videos for the combination of materials for the associated layers ## General tips for preparing 3D Models in Rhino This is not a topic of detail for this documentation, but these are some general tips to prepare files in rhino, for a better rendering process in BatchX - Try to use Block Instances for parts which are identical. For example similar diamond shapes, links in a chain, prongs, ... - When converting surfaces(NURBS) to meshes, make sure that the mesh resolution is not too high, which can cause very high file size. On the other hand it should not be too low, which will result in a poor mesh quality. The best option is to find a resolution that is detailed enough to build your model features accurately while keeping file size manageable. - For meshes having a very high resolution, use the ReduceMesh command, and adjust the polycount, while keeping good enough mesh quality - Though it depends on the specific product, try to keep the polygon count less than 200,000 - Use face normals for Diamonds/Gems in order to produce accurate cuts ## Exporting from Rhino Once your models are prepared using the above guidelines, export it as 3dm. - Before exporting, make sure that you are in the shaded mode. If there are any objects in the 3d model as surfaces(NURBS), this will convert those to meshes, which is essential for BatchX. ![Rhino Export](../assets/images/rhino_shadedmode.webp) - While exporting make sure that you don't enable the `Save small` option. This removes all the meshes from the file, and keeps the original surface(NURBS) information. For BatchX to read the 3dm files, it must have the 3d meshes present in the model. ![Rhino Export](../assets/images/rhino_export.webp) ::: warning Important Note ### Render vs Production CAD Most CAD modellers produce a CAD production file which is created for manufacturing and casting and not for rendering. the main reason is that the designer had no intention of modelling your designs for rendering purposes. They may have made short cuts in the modelling process for speed that cause issues with rendering but not for manufacturing Here are some issues with the production CAD : - Sharp edges - Sharp and long Prongs/Claws - Seams artifacts - Combined metal parts, even if the design is meant to have, for example 2 tone metals for head and shank - Penetrating surfaces All the above issues should be fixed in the file in a modelling software like rhino, and the result is what we refer as a render ready file. ::: ## Video Tutorials on Rhino Check out the following tutorials to go through the entire process in detail - Importing and Layering 3DM Files in Rhino - Layers and Properties in Rhino - Fixing Wrong Normals ## General Tips about other 3D modelling Softwares Though recommended to use Matrix/Matrix gold/Rhino, it is not necessary to create your designs in these softeares. For using any other software like Blender/3ds max/C4D, here are a few general comments - The materials are named consistently across all the files - Unique diamond shapes(round, pear, marquise, ...) should be assigned separate materials for accurate diamond cuts - Similar diamond shapes, including transforms(rotation/uniform scale/translation) should be assigned same material whenever possible - Similar diamond shapes, including transforms(rotation/uniform scale/translation) should be assigned different material, if different material needs to be assigned - Use instances to model identical, or transformed(rotation/scale/translation) parts like chain links, prongs, similar diamond shapes, etc. - Use face normals for Diamonds/Gems in order to produce accurate cuts - When creating meshes for different jewellery parts, make sure that the mesh resolution is not too high, which can cause very high file size. On the other hand it should not be too low, which will result in a poor mesh quality. The best option is to find a resolution that is detailed enough to build your model features accurately while keeping file size manageable. - Though it depends on the specific product, try to keep the polygon count less than 200,000 --- # Prepare Scene Settings for BatchX The next step after preparing your 3d files, is to prepare the scene settings for the image/video render step. This includes setting HDR environment maps for metal and diamonds, setting up metal/diamond/enamel/pearl/... materials and their variations, camera views, post processing effects and more. To prepare all the settings, you need to use the [iJewel Playground](https://playground.ijewel3d.com/v2/index.html), which is available to use for free. Following are the recommended steps to complete your scene settings. ## 1. Choosing the right HDR environment maps This is perhaps the most critical part to give your gold, diamonds/gems, and other materials the desired look. You can either use one of our free presets, which are available for download OR create your own HDR environment maps from scratch. Here are a couple of tutorials to go through the environment map setup for metal and diamonds. ::: tip #### Create environment maps from scratch using HDR Map Editor To create your own environment maps from scratch, we recommend using the [HDR Map Editor](https://hdrmap.com/). This powerful tool allows you to create your own environment maps to exactly fit your needs. To understand the process in greater detail, go through the following playlist tutorials. ::: ## 2. Create materials and material variations To create variations of your desired gold(rose, yellow, white etc), diamonds(diamond, ruby, sapphire etc), pearls(black, white,...) etc, go through the following tutorial. In this step, you need to prepare all the different variations for your gold, diamond, pearl, and other materials. These variations will later be used by BatchX to auto generate media. ## 3. Create camera views This step will define the different views for your products, so that BatchX can generate the media for each view automatically. Here is a tutorial on how to do that ## 4. Adjust scene settings In this step you can make changes to background, ground, postprocessing and many more settings. Go through the entire playlist tutorials to understand in greater detail about setting materials, background color,images, postprocessing effects and more ## 5. Export scene settings Now you are ready to export all your scene settings, and start using BatchX to generate media. You can export the scene settings by going to the Export tab. ![iJewel 3D](../assets/images/batchx_export_scenesettings.webp) this will download a json file with vjson file extension, which contains all the information about the settings you have made. ::: tip * For each product category like rings, earrings, braclet, you may need to create different scene settings. * Standing and layed down rings might need different scene settings(mostly different camera views) ::: Most of the work is done now. In the next and final step, we will go through the simple process of generating images and videos using BatchX. --- # Start Generating Images and Videos After exporting the scene settings from the previous step, you can now start using BatchX. If you haven't downloaded BatchX yet, start your free trial [here](https://batchx.ijewel3d.com/). After launching BatchX, this is how the initial screen will look like ![iJewel Photo-realistic Rendering](../assets/images/batchx_screen.webp) Follow the next couple of steps to start your batch renders ## Create folder Create a local folder and drop all your 3d files, and the prepared scene setting vjson file. Make sure that you have only one scene setting vjson file in this folder, as BatchX will pick up only one file for the settings. Drag and drop the local folder in the dedicated area: ![iJewel Photo-realistic Rendering](../assets/images/batchx_dragndrop.webp) ## Start Batch render Now press the "EXPORT VIEWS" button to start the batch rendering! ![iJewel Photo-realistic Rendering](../assets/images/batchx_exportviews.webp) BatchX will start the media rendering, and dump the results in an "output" folder created within the source folder. ## BatchX Settings ### General settings ``` HEIGHT - Height of the render canvas WIDTH - Width of the render canvas SCALE - Scale factor to mutiply the media resolution V-QUALITY - Video quality. Default is 8, which should give good quality. max allowed value is 32. V-DURATION - Video duration in seconds. max allowed value is 20. V-FRAMERATE - Video framerate. max allowed value is 60. Image Format - Image format. Can be one of png/jpg/webp Create Folders - Option to create subfolders for each 3d file ``` :::info To create images of 4000x4000, you can give height and width of 1000, and a scale value of 4. Too high scale values might result in lower performance/increased render times, depending upon the device you are rendering on. ::: ### Tabs #### Folders All 3d files present in the folders are shown here. You can also search files by names, and enable/disable batch rendering on specific files. ![iJewel Photo-realistic Rendering](../assets/images/batchx_folder_tab.webp) #### Camera Views All the camera views present in the scene settings are shown here. You can enable/disable, image/video generation by clicking on the specific item. Additionaly it is possible rename a view, and add an additional camera view for your batch rendering. ![iJewel Photo-realistic Rendering](../assets/images/batchx_camera_tab.webp) #### Materials All the materials and material variations are listed here. You can search materials by name and filter out materials for which you dont want to create the renders. ![iJewel Photo-realistic Rendering](../assets/images/batchx_material_tab.webp) :::tip Its best to use the 3dm file format for the 3d files, with consistent layer names. This will save you a lot of time ::: ## Video Tutorials To go through the entire process in detail, check out the following playlist. Watch the complete playlist on Youtube - https://www.youtube.com/watch?v=97Nu5WGWdNs&list=PLIWKi7kUUJPgoGuQUCOIeAuk9xPuuMZQh --- # Introduction ![iJewel3D Ring Try-On](../assets/images/tryon_hero.webp) Ring Try-On combines an iJewel3D ring project with live hand tracking. A customer can inspect the ring in 3D, start the camera, and see the same ring on a selected finger. This guide covers iframe integration, Mini Viewer integration, and advanced custom controls. Try-On supports these project types: - a standalone ring model; - a Ring Configurator project, including the ring assembled from its current components; and - a Wedding Band Builder project, including generated bands and catalog rings. Configurator projects do not need a separate model file for Try-On. ## Start here Choose the guide that matches where the project is stored and who owns the Try-On controls: - **Drive project with standard controls:** use [Direct Integration](./demo). - **Self-hosted Ring Configurator:** use [Using Ring Configurator](../ring-configurator/using-ring-configurator#option-4-fully-self-hosted-project). - **Self-hosted Wedding Band Builder:** use [Self-Hosted Integration](../wedding-band-builder/integration-self-hosted). - **Standalone Drive model with custom controls or product switching:** use [Advanced Integration](./advanced). - **Configurator with custom Try-On controls:** use the public [Configurator Try-On helpers](../viewer/viewer-class#configurator-try-on-helpers). For a Drive project, first [prepare the ring project](./prepare-model) and save its Try-On configuration. For a fully self-hosted project, either transfer that saved configuration through your project export pipeline or generate it with Web VTO setup mode. ## Prepare each project in iJewel3D Platform Each model or configurator project needs a saved Try-On configuration. This configuration makes Try-On available and controls the ring placement on the tracked finger. When Mini Viewer loads a Drive project, the website receives the project and its saved configuration together. You do not need to host a separate Try-On JSON file for that path. A fully self-hosted project keeps the same settings in its top-level `tryonConfig`, or loads the generated JSON directly into Web VTO. Follow [Prepare a Try-On Project](./prepare-model) before you write the website code. The guide explains how to fit the ring to the finger cylinder, preview the result, and save the configuration. ## Meet the website requirements The hosting page must use HTTPS because browsers restrict camera access on insecure pages. The camera start must follow a direct user action, such as a button selection. If the integration uses an iframe, give the iframe camera permission. If the integration uses Mini Viewer, register the production domain with iJewel3D. ## Attribution watermark Try-On works even when **Enable TryOn** is off for the domain. In this case, the camera view shows an iJewel3D attribution watermark. To hide the watermark, purchase Try-On for the domain. Then open **Settings → Domains** and turn on **Enable TryOn** for that hostname. ## API reference For custom JavaScript controls, start with [Advanced Integration](./advanced). The API reference covers [RingTryonPlugin](./ring-tryon-plugin) and [TryonUIPlugin](./tryon-ui-plugin). --- # Prepare a Try-On Project Configure each ring project before you add Try-On to a website. The configuration controls the ring size, position, and rotation on the tracked finger. It also tells Mini Viewer that Try-On is available for the project. ::: info Configurator Try-On release Configurator Try-On requires Mini Viewer `0.6.18` or later on the customer website. ::: > [Watch the Try-On setup video on YouTube](https://youtu.be/T8yf3xjKVyI?si=_rGwPXAxfw6UGI60). ## Before you start Make sure that the model, Ring Configurator, or Wedding Band Builder project is available in your Drive. The ring must have a clear inner opening. Auto Fit uses this opening to calculate the initial fit. Use the setup path for your project type: | Project type | Open the setup interface | | --- | --- | | Standalone ring model | Select the model. Then use **Open In → Editor** or **Open In → Playground**. | | Ring Configurator | Select the configurator project. Then use **Open In → Editor** or **Open In → Playground**. | | Wedding Band Builder | Select the Wedding Band project folder. Then select **Edit Default Settings**. | For a Ring Configurator, the editor fits the ring assembled from the components currently shown. For a Wedding Band Builder, select the ring that you want to use for calibration before you open Try-On settings. One saved fit applies to every ring in that Wedding Band project. ## Enable Try-On 1. Open the project with the correct setup path from the table above. 2. Open the Try-On settings. 3. Turn on **Enable AR**. 4. Select **Enter Setup**. Setup mode displays a cylinder inside the ring. The cylinder represents the tracked finger. ## Fit the ring to the cylinder Select **Auto Fit** first. Auto Fit finds the inner ring opening and provides an initial position and size. If Auto Fit finds several openings, select it again to inspect the next result. Use these controls to correct the result: | Control | Use | | --- | --- | | **Model Size** | Match the inner ring opening to the cylinder diameter. | | **Position** | Place the center of the ring opening on the cylinder axis. | | **Rotation** | Align the ring band with the cylinder. Point the ring head in the direction of the arrow. | | **Front**, **Top**, and **Side** | Inspect the fit from fixed viewpoints. | | **X 90°**, **Y 90°**, and **Z 90°** | Correct the model orientation. Use these controls for large corrections. | The cylinder must pass through the center of the ring opening. The band must surround the cylinder evenly. The arrow inside the cylinder shows the correct direction for the ring head. Check the fit from all three viewpoints. Rotate the model until the ring head points in the direction of the arrow. ## Preview and save 1. Select **Exit Setup**. 2. Select **Preview in AR**. 3. Give the browser camera access. 4. Check the ring size, position, and direction on your hand. 5. Exit the preview. 6. Correct the setup if the fit is wrong. 7. Save the project to your Drive. The saved project contains the Try-On configuration. You do not need to download or host a separate configuration file. Mini Viewer receives the project and its configuration through `loadModelById`. For a configurator, Mini Viewer sends the ring assembled by the configurator plugin to Try-On. It does not require a separate GLB for the configured ring. ::: info Public file access The file must be **Public** in its share settings. `loadModelById` cannot load a private file from your Drive. ::: ## Test the saved project After you save the project, test its file ID with the [Direct Integration](./demo) example. The Mini Viewer Try-On button appears only when the saved configuration has Try-On enabled. If the old fit appears, save the project again and reload the product page. Test the customer flow for the project type: - A Ring Configurator opens the ring that the customer assembled. - A Wedding Band Builder with one ring opens that ring. - An unlinked Wedding Band pair opens the selected ring. - A linked Wedding Band pair asks the customer which ring to try on. ## See the complete platform workflow This video shows the Try-On part of the complete iJewel Platform workflow. > [Watch this section on YouTube](https://youtu.be/_4fjOGN-lXs?si=lomQC-wtE1Zqxj4i&t=275). ## Fix common fitting problems | Problem | Correction | | --- | --- | | Auto Fit does not find the ring | Make sure that the inner opening is clear. Then adjust the ring manually. | | The ring is too large or too small | Correct **Model Size**. | | The ring is not centered | Correct **Position** from the front, top, and side viewpoints. | | The ring head does not point in the direction of the arrow | Correct **Rotation**. Use a 90-degree change when the model uses another axis. | | The configurator opens without a ring model | Wait for its components or generated bands to load before you start setup. A separate model file is not required. | | The Try-On button is missing | Turn on **Enable AR**, save the project, and reload the product page. | --- # Direct Integration Start with an iframe for most product pages. The iframe loads the configured project and the standard Try-On controls. Use Mini Viewer when your page must load the project with JavaScript or respond to viewer events. ## Before you start Complete [Prepare a Try-On Project](./prepare-model) before you add the project to your website. Make sure that the project has a saved Try-On configuration with `enabled: true`. Get the model or configurator project ID from your Drive in iJewel3D Platform. See [Find the model ID](../viewer/tutorial-embed-drive#find-the-model-id) for the same iJewel3D Platform steps. ## Option 1: Add an iframe Copy this example and replace `MODEL_ID` with the model or configurator project ID. ```html ``` The `camera` permission lets Try-On request camera access from inside the iframe. The parent page must use HTTPS. For an enterprise iJewel3D Platform instance, replace `ijewel3d.com` with the supplied domain. You can also copy the iframe from the editor **Embed (``)** tool. See [Create an iJewel viewer embed](../integrations/embedding) for the complete editor steps. If you copy the generated iframe, make sure that its `allow` attribute includes `camera`. ## Option 2: Load the model with Mini Viewer Use Mini Viewer when the website needs direct JavaScript access to the viewer. Register the hosting domain with iJewel3D before you publish the page. See [Host and domain setup](../viewer/tutorial-embed-drive#host-and-domain-setup) for the domain requirements. ::: info Public file access The file must be **Public** in its share settings. `loadModelById` cannot load a private file from your Drive. ::: ### Add the complete Mini Viewer page Copy this example into an HTML file. ```html Ring Try-On
``` ### Edit the Mini Viewer example Change only the values that apply to your page. | Value | Action | | --- | --- | | `MODEL_ID` | Replace `MODEL_ID` with the model file ID. | | `DRIVE_BASENAME` | Keep `drive` unless iJewel3D gives you an enterprise basename. | | `#viewer` size | If the viewer fills only part of the page, change the CSS. | The viewer container must have a width and height. A container without a height can make the viewer appear blank. ### Understand the Mini Viewer code The first script loads WebGi `0.22.0`. The `window.webgi` assignment gives Web VTO access to the same WebGi instance. The second script loads Mini Viewer `0.6.18`. `loadModelById` gets the model or configurator project and its saved configuration from iJewel3D Platform. Mini Viewer `0.6.18` sends configurator-owned ring geometry to Try-On without a separate model file. The standard integration does not need a Web VTO script tag. Mini Viewer loads Web VTO after the customer selects the Try-On button. ### `loadModelById` parameters | Parameter | Description | | --- | --- | | `MODEL_ID` | The unique file ID of the model or configurator project. | | `DRIVE_BASENAME` | The iJewel3D Platform instance. Standard accounts use `drive`. | | `document.getElementById("viewer")` | The element that contains Mini Viewer. | | `showUiButtons: true` | Shows the Mini Viewer control bar. | | `hideTryOn: false` | Keeps the Try-On button visible for a project that enables Try-On. | If `tryonConfig.enabled` is not `true`, Mini Viewer does not show the Try-On button. ## Do the first browser test 1. Serve the page through HTTPS. 2. Open the product page. 3. Make sure that the 3D ring appears. 4. Select the Try-On button in the viewer controls. 5. When the browser asks for permission, allow camera access. 6. Move a hand into the camera view. The ring must follow the selected finger and keep the saved project placement. ## Solve common problems | Problem | Cause | Action | | --- | --- | --- | | The viewer area is blank. | The container has no height, or the project did not load. | Give the container a height. Then inspect the browser console for a loading error. | | Mini Viewer shows a CORS or `403` error. | The hosting domain is not registered. | Send the exact production domain to iJewel3D support. | | The Try-On button is missing. | The project does not enable Try-On, or the viewer hides the controls. | Make sure that `tryonConfig.enabled` is `true`. Use `showUiButtons: true` and `hideTryOn: false`. | | The camera does not start. | The page is insecure, or the browser blocks camera access. | Use HTTPS. Then allow camera access in the browser. | | Try-On works outside an iframe only. | The iframe does not have camera permission. | Add `camera` to the iframe `allow` attribute. | | The camera view shows an iJewel3D attribution watermark. | Try-On is not purchased and enabled for the domain. | Purchase Try-On for the domain. Then turn on **Enable TryOn** under **Settings → Domains**. | If you need branded controls or product switching, continue to the [advanced integration](./advanced). For a project JSON hosted on your own server, continue in the matching configurator guide: - [Using Ring Configurator](../ring-configurator/using-ring-configurator#option-4-fully-self-hosted-project) - [Self-Hosted Wedding Band Builder](../wedding-band-builder/integration-self-hosted) --- # Advanced Integration ::: info Plan requirement Advanced Integration requires an iJewel3D Enterprise plan at the Silver tier or above. ::: If your website needs different controls, use this integration. Examples include branded buttons, finger selection, image saving, and product switching. Mini Viewer still creates the viewer and loads every model from iJewel3D Platform. Your code controls the Try-On plugin through the existing WebGi `ViewerApp`. Before you add these controls, [prepare and save the Try-On model](./prepare-model). The [Web VTO demo](https://demo.ijewel3d.com/web-vto/) shows one possible advanced Try-On experience. ::: warning Configurator projects This custom-control example targets a standalone model. For a Ring Configurator or Wedding Band Builder, call the public [Configurator Try-On helpers](../viewer/viewer-class#configurator-try-on-helpers) after applying `tryonConfig` and before `tryon.start()`. The helper prepares the selected assembled ring and restores the configurator after the session. ::: ## Understand the two viewer objects The integration uses two related objects. | Object | Purpose | | --- | --- | | `miniViewer` | The Mini Viewer wrapper returned by `loadModelById`. Use it for product changes. | | `viewerApp` | The WebGi viewer from `ijewel-viewer-ready`. Use it to get or add plugins. | Do not create another `ViewerApp`. A second `ViewerApp` creates another canvas and another render loop. ## Load the libraries The custom integration loads Web VTO with the other libraries. Keep these versions and this script order. ```html ``` WebGi provides the viewer. Mini Viewer loads the model from iJewel3D Platform. Web VTO `0.3.3` provides `RingTryonPlugin` and `TryonUIPlugin` on `window.ij_vto`. ## Use the Mini Viewer events Mini Viewer provides the data that the custom integration needs through window events. | Event | Data | Use | | --- | --- | --- | | `ijewel-file-data` | The model file and its saved configuration. | Read `tryonConfig` for the current model. | | `ijewel-viewer-ready` | The WebGi `ViewerApp`. | Add or get the Try-On plugins. | | `ijewel-scene-ready` | The completed model scene. | Apply the saved configuration after the model is ready. | Register the event listeners before you call `loadModelById`. `ijewel-file-data` can occur before the `loadModelById` promise returns. ## Add the Try-On plugins [RingTryonPlugin](./ring-tryon-plugin) controls the camera, hand tracking, ring placement, and image capture. [TryonUIPlugin](./tryon-ui-plugin) shows the loading screen, hand prompt, and camera error messages. It does not add the main Start, Stop, Flip, or Save buttons. Add `RingTryonPlugin` first because `TryonUIPlugin` requires an existing Try-On plugin. ```javascript const tryon = await viewerApp.getOrAddPlugin( ij_vto.RingTryonPlugin ); const tryonUi = await viewerApp.getOrAddPlugin( ij_vto.TryonUIPlugin ); ``` Use `configure()` to change only the required interface values. ```javascript tryonUi.configure({ loading: { title: "Preparing Try-On", subText: null }, handPrompt: { text: "Show the back of your hand" } }); ``` See the [TryonUIPlugin API Reference](./tryon-ui-plugin) for all interface properties and messages. ## Add the complete custom integration The example contains a full custom integration in one HTML file. Edit these three areas: 1. Replace `MODEL_ID` with the model file ID. 2. Change `DRIVE_BASENAME` only for an enterprise iJewel3D Platform instance. 3. Replace the control markup and CSS with your product design. Keep the event order and plugin initialization unchanged. ```html Custom Ring Try-On
``` ## Apply the saved model configuration `ijewel-file-data` can contain the configuration as an object or a JSON string. If the file configuration is empty, the example uses `defaultConfig`. `tryon.fromJSON()` applies the saved placement values to the plugin. The `type` value tells WebGi which plugin owns the configuration. See [RingTryonPlugin configuration](./ring-tryon-plugin#configuration) for all configuration groups. ## Select the active finger Web VTO `0.3.0` and later use the `finger` setter. Set the finger after `tryon.start()` initializes hand tracking. ```javascript await tryon.start(); tryon.finger = "ring"; ``` You can also change the finger while Try-On is active. ```javascript if (tryon.running) { tryon.finger = "index"; } ``` The supported values are `thumb`, `index`, `middle`, `ring`, and `pinky`. `assignMainRingToFinger` is deprecated. Do not use it in a new integration. See [RingTryonPlugin placement](./ring-tryon-plugin#placement) for the complete placement API. ## Add controls to the Try-On interface Use `tryon.running` to check whether Try-On is active. | Action | API | | --- | --- | | Start Try-On | `await tryon.start()` | | Stop Try-On | `await tryon.stop()` | | Read the state | `tryon.running` | | Change the finger | `tryon.finger = "ring"` | | Set digital zoom | `tryon.videoScale = 1.5` | | Request hardware camera zoom | `tryon.cameraZoom = 2` | | Flip the camera | `await tryon.flipCamera()` | | Select the next camera | `await tryon.selectNextCamera()` | | Save an image | `await tryon.saveImage(options)` | | Check the save state | `tryon.saveImageInProgress` | | Get an image for upload | `await tryon.getImageBlob()` | See the [RingTryonPlugin API Reference](./ring-tryon-plugin) for all lifecycle, camera, placement, and image APIs. ### Add a zoom slider Use `videoScale` for a zoom control that works without camera hardware support. The value scales the camera view and keeps the ring aligned with the hand. If your interface controls zoom, turn off automatic interaction zoom. ```html ``` ```javascript const zoomInput = document.getElementById("tryon-zoom"); zoomInput.addEventListener("input", () => { if (!tryon) { return; } tryon.interactionZoom.enabled = false; tryon.videoScale = Number(zoomInput.value); }); ``` `cameraZoom` requests optical or hardware zoom from the active camera. Camera support and available values differ between devices. Use `videoScale` as the main website zoom control. ### Respond to plugin events Use plugin events when controls can change from more than one part of the page. ```javascript tryon.addEventListener("initialized", updateControls); tryon.addEventListener("stop", updateControls); tryon.addEventListener("error", (event) => { console.error( "Try-On error:", event.detail?.error ?? event.detail ); updateControls(); }); ``` See [RingTryonPlugin events](./ring-tryon-plugin#events) for the complete event list. ## Switch products without another viewer Stop Try-On before you change the model. Then call `loadModelById` with the existing `miniViewer` in the `viewer` option. ```javascript async function loadProduct(nextModelId) { tryonButton.disabled = true; fingerSelect.disabled = true; try { if (tryon?.running) { await tryon.stop(); } const fileDataReady = waitForWindowEvent("ijewel-file-data"); const sceneReady = waitForWindowEvent("ijewel-scene-ready"); const loadedViewer = await window.ijewelViewer.loadModelById( nextModelId, DRIVE_BASENAME, container, { viewer: miniViewer // Reuses the ViewerApp from ijewel-viewer-ready. } ); if (!loadedViewer) { throw new Error("The next model did not load."); } const fileDataEvent = await fileDataReady; await sceneReady; await applyTryonConfiguration( fileDataEvent.detail.iJewelFileData ); } finally { updateControls(); } } ``` The `viewer` option reuses the canvas, WebGi viewer, and Try-On plugin. Each new model must contain its own saved Try-On configuration. ## Stop Try-On before the view closes Stop the plugin before your application hides or removes the viewer container. ```javascript async function closeTryonView() { if (tryon?.running) { await tryon.stop(); } // Close the modal or change the route here. } ``` This action releases the camera and restores the normal 3D viewer state. ## Allow camera access in an iframe If the integration runs in an iframe, add camera permission to the iframe. ```html ``` Serve the parent page and the iframe page through HTTPS. The parent website permission policy must also allow camera access. ## Solve advanced integration problems | Problem | Cause | Action | | --- | --- | --- | | `window.ij_vto` is undefined. | The Web VTO script did not load, or the script order is wrong. | Use the four script blocks from this page in the same order. | | The saved configuration is undefined. | The `ijewel-file-data` listener was added too late. | Register the event promise before `loadModelById`. | | The ring uses the wrong placement. | The code did not apply `tryonConfig` after the scene became ready. | Wait for `ijewel-scene-ready`. Then call `tryon.fromJSON()`. | | The finger does not change. | The code set `tryon.finger` before hand tracking started. | Set the finger after `await tryon.start()` or during an active session. | | Product changes create extra canvases. | The code creates a new Mini Viewer for each product. | Pass `{ viewer: miniViewer }` to `loadModelById`. | | The camera stays active after a modal closes. | The application removed the view before it stopped Try-On. | Call `await tryon.stop()` before you remove the viewer container. | --- # RingTryonPlugin API Reference `RingTryonPlugin` is the try-on engine. It takes over the WebGi viewer while running: it opens the camera, tracks the user's hand, and places the loaded ring model on the chosen finger with matching occlusion, shadows and reflections. It is a standard WebGi plugin, so everything you already know about plugins applies - `addPlugin`, `getPlugin`, `fromJSON` / `toJSON`, `addEventListener`. ```javascript const tryon = await viewer.addPlugin(ij_vto.RingTryonPlugin); await tryon.start(); ``` ::: info Where the plugin comes from The plugin lives on the `ij_vto` global from the `web-vto` bundle, not on WebGi. See [Load the libraries](./advanced.md#load-the-libraries) for the script tags and required order. ::: ## Adding the plugin #### `viewer.addPlugin(ij_vto.RingTryonPlugin, options?)` | Option | Type | Default | Description | |---|---|---|---| | `preload` | `boolean` | `true` | Start downloading the hand-tracking model and WASM runtime as soon as the plugin is added, instead of on the first `start()`. Makes starting feel instant, at the cost of a background download every page view. | ```javascript // Defer the download until the user actually presses the try-on button. const tryon = await viewer.addPlugin(ij_vto.RingTryonPlugin, { preload: false }); ``` #### `RingTryonPlugin.preload()` Static. Warms the same assets without adding the plugin - useful to trigger on hover or when a product page scrolls into view. ```javascript ij_vto.RingTryonPlugin.preload(); ``` #### `RingTryonPlugin.PluginType` Static. The string `"RingTryonPlugin"`, for `viewer.getPluginByType(...)` and for the `type` field when calling `fromJSON`. ## Lifecycle #### `async start()` Starts try-on. Prompts the user for camera access, initialises hand tracking, and switches the viewer from turntable mode into the live camera view. Must be called from a user gesture - browsers only grant camera access in response to a click or tap. ```javascript startButton.onclick = () => tryon.start(); ``` #### `async stop(force = false)` Stops try-on, releases the camera and restores the viewer to its normal 3D state. Pass `force: true` to tear down even if the plugin is mid-start. #### `get running: boolean` `true` between a successful `start()` and the matching `stop()`. Use it to drive a toggle button. #### `async pause()` / `async resume()` / `async togglePause()` Freezes the camera feed while keeping try-on active, so the user can inspect a still frame, then resumes the live view. Cheaper than a full stop/start cycle. #### `get paused: boolean` Whether the feed is currently frozen. ## Camera #### `async flipCamera()` Switches between the front (`user`) and rear (`environment`) camera. On devices with only one camera this is a no-op - check `paused`/`running` before offering the control. #### `selectNextCamera()` Cycles through every camera the browser reports, rather than just flipping the facing mode. Falls back to `flipCamera()` when the device list can't be resolved. Useful on desktops with several webcams. #### `async setVideoSize(x: number, y: number)` Requests a specific camera resolution. Lower values reduce tracking cost on weak devices. #### `videoScale: number` Zoom applied to the camera feed itself. Default `1.35`. #### `cameraZoom: number` Zoom applied to the 3D camera. Default `1`. ## Placement #### `finger: number | string` Which finger the ring sits on. Accepts a `Finger` index (`0`–`4`) or a name - any string containing `thumb`, `index`, `middle`, `ring` or `pinky` (case-insensitive). Anything unrecognised falls back to the ring finger. ```javascript tryon.finger = "index"; tryon.finger = 3; // ring finger tryon.finger = (tryon.finger + 1) % 5; // cycle ``` ::: warning Set it after `start()` The setter needs a loaded model and a live hand tracker, so it silently does nothing before `start()` resolves. Apply your default finger straight after starting, not while wiring up the page. ::: Reading it back always returns the numeric index: | Index | Finger | |---|---| | `0` | Thumb | | `1` | Index | | `2` | Middle | | `3` | Ring (default) | | `4` | Pinky | The default can also be baked into the model - set `finger` in the model's `userData` in the editor and the plugin picks it up on load. #### `getJewelryScreenPosition()` Returns the ring's current anchor as `{ x, y }` in canvas CSS pixels, or `null` if it isn't on screen. Use it to pin your own HTML overlay - a size label or a tooltip - to the ring as it moves. ```javascript const pos = tryon.getJewelryScreenPosition(); if (pos) { label.style.transform = `translate(${pos.x}px, ${pos.y}px)`; } ``` #### `resetInteractionZoom()` Cancels the automatic zoom-in that happens after the hand has been tracked steadily, returning to the default framing. ## Setup mode Setup mode is the authoring tool used to position a model on a reference finger. It is normally driven from the editor UI, but is available programmatically. Setup mode with the reference finger cylinder, centre line and transform gizmo #### `enterSetupMode(options?): boolean` Suspends try-on and shows the reference finger cylinder, the center-line plane and a transform gizmo. Returns `false` if the plugin is currently running or starting. | Option | Type | Default | Description | |---|---|---|---| | `showGizmos` | `boolean` | `true` | Show and enable the transform gizmo. Set it to `false` to create the gizmo hidden and disabled; it reappears on the next transform-mode change. | #### `exitSetupMode(): boolean` Leaves setup mode and restores the camera position saved on entry. #### `inSetupMode: boolean` Whether setup mode is currently active. See [Prepare a Try-On Project](./prepare-model.md) for the full authoring workflow, including exporting the resulting JSON. ### Prepare a configurator ring A Ring Configurator or Wedding Band Builder builds its ring at runtime, so hand the assembled ring to the plugin before setup mode or `start()`: ```javascript const session = ijewelViewer.prepareConfiguratorTryon( viewerApp, tryon ); if (!tryon.enterSetupMode()) { session.restore(); throw new Error("Try-On setup mode could not be opened."); } tryon.setup.autoFit(); ``` Calling `tryon.exitSetupMode()` restores the complete configurator. Pass a `ringId` when a Wedding Band Builder has several rings. See [Configurator Try-On Helpers](../viewer/viewer-class.md#configurator-try-on-helpers) for ring choices and the custom runtime flow. ## Configuration Placement and visual settings live on grouped config objects. Every field is serialized, so `toJSON()` / `fromJSON()` round-trip them - this is exactly how the settings authored in the editor reach the plugin at runtime. ```javascript // Apply settings authored in the editor. tryon.fromJSON({ ...tryonConfig, type: ij_vto.RingTryonPlugin.PluginType }); // Or set individual values. tryon.setup.modelScaleFactor = 1.1; tryon.contactShadow.intensity = 0.45; ``` For a configurator, call [`prepareConfiguratorTryon()`](../viewer/viewer-class#configurator-try-on-helpers) after `fromJSON()` and before `start()`. ### `setup` - model placement | Property | Type | Default | Description | |---|---|---|---| | `modelScaleFactor` | `number` | `1` | Uniform scale applied to the model. | | `modelPosition` | `Vector3` | `(0,0,0)` | Position offset. | | `modelRotation` | `Vector3` | `(0,0,0)` | Rotation offset in **radians**. | These three are also mirrored directly on the plugin as `modelScaleFactor`, `modelPosition` and `modelRotation`. ::: warning Radians here, degrees in `tracking` `setup.modelRotation` is applied straight to the model's Euler rotation, so it is in radians - the editor converts for display. The separate [`tracking.offsetRotation`](#tracking-advanced-tuning) *is* in degrees. Use `MathUtils.degToRad()` when you have a degree value for `modelRotation`. ::: ### `contactShadow` - shadow where the ring meets the finger | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Draw the contact shadow. | | `intensity` | `number` | `0.6` | Shadow strength. | | `distance` | `number` | `0.15` | How far the shadow reaches from the ring. | | `smoothness` | `number` | `0.55` | Softness of the shadow edge. | | `angle` | `number` | `0` | Light direction in screen space, in degrees. `0` puts the light above. | | `elevation` | `number` | `70` | Light elevation toward the camera, in degrees. `90` is head-on, casting no visible shadow. | | `skinWarmth` | `number` | `0.1` | Warm halo bleeding into the shadow, approximating light scattering in skin. | | `color` | `Color \| string` | black | Tint added inside the shadow. | ### `ssao` - ambient occlusion and skin shading | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `false` | Enable ambient occlusion. | | `intensity` | `number` | `0.2` | Occlusion strength. | | `radius` | `number` | `1.07` | Sampling radius. | | `falloff` | `number` | `0.33` | How quickly occlusion fades with distance. | | `smoothEnabled` | `boolean` | `true` | Blur the occlusion result. | ### `ssr` - screen-space reflections | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Reflect the hand and surroundings in the metal. | | `intensity` | `number` | `1.5` | Reflection strength. | | `radius` | `number` | `2` | Ray-march radius. | | `tolerance` | `number` | `5` | Depth tolerance when matching a reflection hit. | ### `environmentReflection` | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Apply the scene environment map to the ring while in try-on. | | `scale` | `number` | `1.67` | Environment scale. | | `stretch` | `number` | `2.675` | Environment stretch. | ### `motionBlur` | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `false` | Blur the ring along its motion as the hand moves. | | `intensity` | `number` | `1.5` | Blur strength. | | `edgeSmear` | `number` | `0.2` | How far the blur smears past the ring's edges. | ### `interactionZoom` After the hand has been tracked steadily for a moment, the view zooms in on the ring automatically. | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Enable the automatic zoom. | | `targetScale` | `number` | `1.5` | Zoom level to settle at. | | `delayMs` | `number` | `1000` | Delay before the zoom starts. | | `durationMs` | `number` | `1250` | Length of the zoom animation. | ### `tracking` - advanced tuning Defaults suit most catalogues; change these only when a model consistently sits wrong. | Property | Type | Default | Description | |---|---|---|---| | `minHandDistance` | `number` | `10` | Hide the ring when the hand is farther than this. | | `snappiness` | `number` | `0.9` | Tracking responsiveness. `0` is heavily smoothed, `1` is instant and jittery. | | `locationOffset` | `number` | `0.65` | Where along the finger segment the ring sits. | | `offsetScale` | `number` | `1` | Multiplier on the detected finger width - effectively ring size. | | `offsetPosition` | `Vector3` | `(0,0,0)` | Extra position offset applied every frame. | | `offsetRotation` | `Vector3` | `(0,0,0)` | Extra rotation offset in degrees, mirrored for the left hand. | | `zOffset` | `number` | `-3.25` | Depth offset from the finger surface. | | `worldZFactor` | `number` | `1` | Scaling applied along the depth axis. | ## Events Standard WebGi events - subscribe with `addEventListener(type, handler)`. | Event | Detail | Fired when | |---|---|---| | `start` | `{}` | `start()` was called and initialisation has begun. | | `initializationProgress` | `{ progress }` | Loading progress, `0`–`1`. Drive your own progress bar with this. | | `initialized` | `{}` | Tracking is live and the ring is ready to appear. | | `interaction` | `{}` | The hand has been tracked steadily - this is what triggers the automatic zoom. | | `stop` | `{}` | Try-on has stopped and the camera is released. | | `error` | `{ reason, error, isCameraError? }` | Something failed. See below. | ### Handling errors ```javascript tryon.addEventListener("error", ({ detail }) => { if (detail.isCameraError) { showMessage("We couldn't access your camera."); } else { showMessage("Try-on couldn't start. Please try again."); } console.error(detail.reason, detail.error); }); ``` `detail.reason` is one of: | Reason | Meaning | |---|---| | `startupFailed` | Initialisation threw - not camera-related. | | `noSupport` | The browser has no webcam API. | | `permissionDenied` | The user declined camera access. | | `notFoundError` | No camera matches the requested constraints. | | `notReadableError` | The camera is in use by another application. | | `overconstrainedError` | The camera can't satisfy the requested settings. | | `abortError` | Camera access was aborted. | | `invalidStateError` | The page was inactive when access was requested. | | `securityError` | Camera access is blocked by browser or page security settings. | | `typeError` | The camera request was rejected as invalid. | | `mediaDevicesError` | Any other failure starting the camera. | Camera reasons arrive with `isCameraError: true`. [`TryonUIPlugin`](./tryon-ui-plugin.md) already renders a message for each of these - add your own handler only if you want different behaviour. ## `canRunVTO()` A standalone pre-flight check, exported alongside the plugin. Call it before showing a try-on button so users on unsupported hardware never hit a dead end. It creates and discards a throwaway WebGL context, so it's cheap enough to call on page load. ```javascript const result = ij_vto.canRunVTO(); if (!result.ok) { tryOnButton.remove(); console.warn("Try-on unavailable:", result.reason, result.details); } else if (result.warning) { console.warn(result.warning); // runs, but may be slow } ``` ### Result | Field | Type | Description | |---|---|---| | `ok` | `boolean` | Whether try-on should be offered. | | `reason` | `string?` | Present when `ok` is `false`. One of `no_webgl2`, `weak_or_software_renderer`, `insufficient_cores`, `insufficient_memory`. | | `warning` | `string?` | Present when try-on will run but performance may suffer - for example an integrated GPU on Chrome for Windows. | | `details` | `object` | What was measured: `webgl2`, `renderer`, `vendor`, `cores`, `memoryGB`. Worth logging for support. | ### Options | Option | Type | Default | Description | |---|---|---|---| | `minCores` | `number` | `4` | Minimum CPU cores. A reported `0` (browser withheld it) never fails the check. | | `minMemoryGB` | `number` | `4` | Minimum device memory in GB, treated the same way. | | `weakRendererPatterns` | `RegExp[]` | built-in list | Renderer strings to reject - software rasterisers and known-weak GPUs. | | `powerPreference` | `string` | `"high-performance"` | Power preference used for the probe context. | ```javascript // Be stricter than the defaults. const result = ij_vto.canRunVTO({ minCores: 6, minMemoryGB: 8 }); ``` --- # TryonUIPlugin API Reference `TryonUIPlugin` is the ready-made overlay for the try-on session. It listens to [`RingTryonPlugin`](./ring-tryon-plugin.md) and renders three things over the canvas: - a **loading box** with a title, optional subheader, optional logo and a progress bar, shown while hand tracking initialises; - a **hand prompt** - an outlined hand and a line of copy - once try-on is live but no hand has been detected yet; - **error messages** for every camera and startup failure the plugin can report. Using it is optional. Everything it does can be built from the plugin's [events](./ring-tryon-plugin.md#events), but it saves you writing loading and error states for a dozen camera failure modes. The three overlays drawn by TryonUIPlugin: loading box, hand prompt and an error state ```javascript const tryon = await viewer.addPlugin(ij_vto.RingTryonPlugin); await viewer.addPlugin(ij_vto.TryonUIPlugin); ``` ::: warning Add it after the try-on plugin `TryonUIPlugin` looks for a try-on plugin on the viewer when it is added, and throws if there isn't one. Always add `RingTryonPlugin` first. ::: ::: info Alias The plugin is exported both as `ij_vto.TryonUIPlugin` and as `ij_vto.RingTryonUIPlugin`. They are the same class - the second name exists for older integrations. ::: ## Configuring Pass a config to the constructor, or update it later with `configure()`. Both take a deep-partial object that is merged onto the defaults, so you only specify what you want to change. ```javascript await viewer.addPlugin(new ij_vto.TryonUIPlugin({ loading: { title: "Preparing your try-on", subText: null, // hide the subheader logo: "https://example.com/logo.svg", align: "center", background: "#111", textColor: "#fff", progressColor: "linear-gradient(90deg, #c9a227, #f0d878)", }, handPrompt: { text: "Show the back of your hand", }, })); ``` #### `configure(partial)` Merges a partial config onto the current one and re-applies it to the live DOM immediately - safe to call while try-on is running. ```javascript const ui = viewer.getPlugin(ij_vto.TryonUIPlugin); // Switch to a different message mid-session. ui.configure({ handPrompt: { text: "Move your hand a little closer" } }); ``` #### `config` The full, resolved config object. Read it to inspect current values; mutate through `configure()` so changes reach the DOM. #### `enabled: boolean` Set to `false` to suppress the whole overlay without removing the plugin. ## `loading` The box shown while hand tracking initialises. | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Render the loading box at all. Set to `false` if you show your own loading state. | | `title` | `string` | `"Loading..."` | Main heading. | | `subText` | `string \| null` | `"Loading models..."` | Subheader. `null` or `''` hides it. | | `logo` | `string \| null` | `null` | Logo above the title. Either an image URL / data-URI, or a raw SVG or HTML string. | | `size` | `'card' \| 'half' \| 'full'` | `'card'` | Preset box size - a centered card, roughly half the container, or a full-canvas overlay. | | `width` | `string \| null` | `null` | Explicit CSS width, e.g. `'320px'` or `'60vw'`. Takes precedence over `size`. | | `align` | `'start' \| 'center' \| 'end'` | `'start'` | Horizontal alignment of logo, title and subheader. | | `background` | `string` | white, near-opaque | Any valid CSS `background` value. | | `textColor` | `string` | `'#000000'` | Title colour. | | `subTextColor` | `string` | `'#4a4a4a'` | Subheader colour. | | `showProgressBar` | `boolean` | `true` | Show the progress bar. | | `progressColor` | `string` | dark gradient | CSS colour or gradient for the progress fill. | ```javascript // Full-bleed dark loading screen with a logo and no subheader. ui.configure({ loading: { size: "full", align: "center", background: "#0b0b0b", textColor: "#ffffff", subText: null, logo: "https://example.com/logo-light.svg", }, }); ``` ## `handPrompt` The overlay shown once try-on is live but no hand has been detected yet. | Property | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Show the prompt. | | `text` | `string \| null` | `"Show your hand to start"` | Prompt copy. `null` or `''` leaves just the outline. | | `showHandOutline` | `boolean` | `true` | Draw the outlined hand graphic. | | `handSvg` | `string` | built-in outline | Replace the outline with your own SVG markup. | | `color` | `string` | near-white | Colour of the prompt text. | #### `showHandPrompt()` / `hideHandPrompt()` Show or hide the prompt imperatively. `showHandPrompt()` respects `handPrompt.enabled` and does nothing when the prompt is disabled. ```javascript // Text-only prompt, no outline. ui.configure({ handPrompt: { showHandOutline: false, text: "Hold your hand up to the camera" }, }); ``` ## `messages` Every user-facing string the plugin can display. Override any subset - for translation, or to match your store's tone. | Property | Description | |---|---| | `initialization` | Loading title (mirrors `loading.title`). | | `initializationSubText` | Loading subheader. | | `error.noSupport` | The browser has no webcam API. | | `error.permissionDenied` | The user declined camera access. | | `error.startupFailed` | Initialisation failed for a non-camera reason. | | `error.mediaDevicesError` | Generic camera start failure. | | `error.runtimeError` | Try-on failed while already running. | | `error.abortError` | Camera access was aborted. | | `error.invalidStateError` | The page was inactive when access was requested. | | `error.notFoundError` | No camera matched the requested constraints. | | `error.notReadableError` | The camera is in use by another application. | | `error.overconstrainedError` | The camera can't satisfy the requested settings. | | `error.securityError` | Camera access is blocked by security settings. | | `error.typeError` | The camera request was rejected as invalid. | | `error.unknown` | Fallback for unrecognised failures. | | `error.unknownCameraError` | Fallback for unrecognised camera failures. | ```javascript // Localise the strings users are most likely to see. ui.configure({ messages: { initialization: "Chargement…", initializationSubText: "Préparation de l'essayage virtuel.", error: { permissionDenied: "Vous avez refusé l'accès à la caméra. Autorisez-le puis réessayez.", notReadableError: "Votre caméra est utilisée par une autre application.", }, }, }); ``` ## Full example ```javascript const tryon = await viewer.addPlugin(ij_vto.RingTryonPlugin); const ui = await viewer.addPlugin(new ij_vto.TryonUIPlugin({ loading: { title: "Preparing your try-on", subText: "This takes a few seconds the first time.", logo: "https://example.com/logo.svg", size: "full", align: "center", background: "#0b0b0b", textColor: "#ffffff", subTextColor: "#a0a0a0", progressColor: "linear-gradient(90deg, #c9a227, #f0d878)", }, handPrompt: { text: "Show the back of your hand", color: "#ffffff", }, })); await tryon.start(); ``` --- # Changelog for @ijewel3d/web-vto ## [0.3.3] - 2026-09-15 ### Fixed - Hand detection now works on phones with an Adreno 8xx GPU, such as the Galaxy S25 Ultra. MediaPipe's GPU delegate returns no hands on these GPUs, so hand detection uses the CPU delegate there. All other devices keep the GPU delegate (IJ-249). ## [0.3.2] - 2026-09-07 ### Fixed - AR Setup no longer darkens editor backgrounds. The AR color conversion now applies only while an AR background is active. ## [0.3.1] - 2026-09-01 ### Fixed - Camera stop now restores the canvas scale. The canvas stayed mirrored after the rear camera stopped. ## [0.3.0] - 2026-08-02 ### Added - On-device engine ported from Pyodide/Python to TypeScript: ~15 MB smaller download. - Ribbon edge fit. - Depth-normalization fallback when edges are missing, flagged as `depthNormFallback`. - `pauseRendering` hook so inference no longer contends with the render loop. ## [0.2.9] - 2026-07-20 ### Added - Wristwear: Onbody front-end loading and support. ## [0.2.8] - 2026-07-13 ### Added - Onbody front-end loading and support. ### Changed - Move onbody handling from back-end to on-device engine. ## [0.2.7] - 2026-06-18 ### Added - `TryonUIPlugin` (`RingTryonUIPlugin`) is now fully configurable via a `TryonUIConfig` object — pass it to the constructor (`new RingTryonUIPlugin({ ... })`) or update it at runtime with `uiPlugin.configure({ ... })`, which re-applies to the live DOM. - Loading box: `enabled` (disable entirely), `title`, `subText` (`null`/`''` hides the subheader), `logo` (image URL/data-URI or raw SVG/HTML), `size` (`'card' | 'half' | 'full'`), `width` (custom CSS override), `align` (`'start' | 'center' | 'end'` for logo/title/subheader), `background`, `textColor`, `subTextColor`, `showProgressBar`, `progressColor`. - Hand prompt: `enabled` (show/hide the "show your hand" overlay), `text` (`null`/`''` for outline only), `showHandOutline`, `handSvg` (override the outline markup), `color`. - Customizable `messages` strings (initialization, save error, and all camera/error messages). - `TryonUIPlugin.showHandPrompt()` / `hideHandPrompt()` to imperatively control the hand-prompt overlay. ### Changed - `TryonUIPlugin` no longer hardcodes loading text, logo, box size/background, alignment, hand SVG, or prompt text — all driven by config (existing defaults preserved when no config is passed). ## [0.2.6] - 2026-06-18 ### Added - Try-on save-image UI with a smoother image-saving animation (ultra mode). ### Changed - Ultra-mode save: crop size now sized relative to the ring's bounding-sphere radius. - Fade shader: ring distance fade-out with more smoothness; reduced finger fade occlusion factor and increased circle fade factor. ### Fixed - Ultra-resolution save mode artifacts. - Fade shader circle fade-out being incorrect during zoom. - Ring non-uniform rotation depending on aspect ratio. - Reset on window resize. ## [0.2.5] - 2026-06-12 ### Added - High-resolution image export using camera.setViewOffset(): Super-sampled ring crop composited onto the original. - Downloading/loading image bake files for importing accurate onbody image data (for using try-on backend data such as finger edges, finger width, depth rotation, occlusion mask) - `maxSize` option to `saveImage` for ultra-mode output. ### Fixed - SSAO options not properly resetting when entering and then exiting the try-on. ## [0.2.4] - 2026-06-10 ### Added - `shadowColor` for SSS contact shadows. ### Fixed - apply/restore zoom in `_setCameraSettings()` ## [0.2.3] - 2026-06-04 ### Added - `enterSetupMode({ showGizmos: false })`: enter setup mode with the transform gizmo created but hidden/disabled. Calling `setTransformMode()` re-shows it. ### Fixed - Auto-fit: original child transforms now restored when fit fails (no inner boundary or validation failure) instead of leaving them zeroed. - Setup mode: camera position is now saved on enter and restored on exit. - Image-mode transform gizmo could disappear after resize/render-scale changes; now detaches on resize so the next update rebinds it. ## [0.2.2] - 2026-05-29 ### Fixed - Set webcam state throwing error if camera background plugin is not set. ## [0.2.1] - 2026-05-29 ### Fixed - Setting video scale changed video aspect ratio unexpectedly. ## [0.2.0] - 2026-05-28 - Try-On Backend Integration ### Added - Try-on backend: comprehensive server-side pipeline for ring placement: edge detection, depth-based yaw/pitch, finger-width estimation, per-finger visibility scoring, and health warmup, roll + many more misc additions. Opt in via `backendUrl` config or the `?backend` query parameter. - Improvements for the wristwear try-on: wrist velocity calculations and motion-prediction features in `MPHand` and `MPBody` for more stable wristwear tracking. ### Fixed - Ring landmarks no longer fade when try-on backend is in use. - Ring position and finger width mismatch when using backend predictions. - `offsetRotation` was incorrectly displacing ring position. - Incorrect transform where only the ring model was scaled, not the full setup. - Ring alignment now uses a single reference edge for consistent placement. - Fist pitch correction when backend is active. - Occluded ring finger now shows an explicit error instead of silently failing. - Cylinder occluder size reduced in image mode to prevent over-occlusion. - Auto-fit placement accuracy after the onbody-depth merge. - Share button now downloads via `getImageBlob()` with a proper filename. - Various setup mode issues and toolbar regressions. ## [0.1.11] - 2026-05-04 ### Added - Setup mode: shift key snapping override for transform controls. - Setup mode: reset functionality for all transform modes. - Setup mode: transform mode selector and auto-fit controls exposed in viewer setup (`index.ts`, `watch-index.ts`). - Watch occluder estimator: new `WatchOccluderDepthPass` for top-down depth map approach; greatly improves occluder accuracy for rings auto-fit as well. - Wrist velocity calculations and motion-prediction features in `MPHand` and `MPBody` for more stable wristwear tracking. ### Changed - Wristwear placement now uses `TrackingConfig` offsets (consistent with ring try-on). - Pose landmarker: reduced smoothing for faster response; disabled for back camera to save resources. - Pose landmarker: slightly faster convergence for still poses. - Default `videoScale` changed from 1.0 to 1.35. - Wrist width calculation in `HandAnalyzer` refined for better size estimation. - SSAO power no longer influences SSS gamma (separated concerns); SSS parameters tuned for wristwear. - Watch occluder estimation rewrote using circle-fitting for improved auto-centering and scaling. ### Fixed - Severe animation lag in `TryonUIPlugin` animations. - Incorrect wristwear yaw when hand deviates radially/ulnarly while the arm remains still. - `borderColor` / `borderImage` not applied in wristwear image mode. - Inconsistent relative wristwear placement across frames. - Transform gizmo rendering artifacts caused by `FadeShaderExtension`. - Watch occluder losing its material after estimation. - Camera depth alignment in setup mode auto-fit. ## [0.1.10] - 2026-05-01 ### Fixed - `TryonUIPlugin` failing to attach in obfuscated builds; reverted plugin lookup to use `PluginType` strings instead of mangled class names. ## [0.1.9] - 2026-05-01 ### Added - `canRunVTO()` pre-flight helper exported from the lib. Returns WebGL2/GPU/device capability check plus an optional `warning` for Chrome/Windows on integrated GPUs. ### Removed - License/key system removed from `BaseTryonPlugin`; licensing is now handled solely by the underlying webgi runtime. ## [0.1.8] - 2026-04-21 ### Fixed - Fix race condition in `stop` method by setting `_running` to `false` right away. ## [0.1.7] - 2026-04-16 ### Added - `getImageBlob(type?, quality?)` method to retrieve the current try-on image as a `Blob` (auto-cropped in image mode). - `saveImage` now accepts a file format/MIME type parameter. - Vertical border support in image mode. - Crop image in image mode when saving it. ### Changed - `startWithImage` and `setImage` now accept any `CanvasImageSource` (not just `HTMLImageElement`). - Hand analyzer resets on window resize to prevent stale tracking state. ## [0.1.6] - 2026-04-09 ### Added - Side fade-out at cylinder edges in live try-on mode to prevent floating shadow artifacts. ### Changed - Unified SSAO and contact shadows into a single SSS computation pipeline — both now drive the same warm-skin shading path independently. - Improved orbit-normal line smoothing (`irregularSmoothing`) with a refined distance mapping function. - Refactored `SSSFingerCylinderShadow`: eliminated duplicated material/uniform/extension blocks; added `updateRingTransform()` for a single-call per-frame update. - Removed SSS wrap strength and saturation boost config parameters; simplified shader accordingly. ### Fixed - Contact shadow Z-fighting artifacts between shadow cylinder and sphere end-caps. - SSAO warm-shading had no effect when contact shadows were disabled; AO now correctly activates the full SSS colour path. ## [0.1.5] - 2026-04-07 ### Added - Pose-based wristwear try-on integration for more independent wrist transform. - Screen-space contact shadows (SSCS) for more realistic shadow rendering. - Alternating tracking and model inference for better performance. - Preliminary API documentation. ### Fixed - Fix try-on running always in "IMAGE" mode. - Fix shadow rendering in wrist wear try-on. - Fix static image resize, fade shader, and default transform controls. - Fix borderColor and borderImage styling. - Fix camera moving in image mode. ### Changed - Adjust wristwear size and snappiness. - Use average landmarks for body tracking. - UI clean-ups and code refactoring. ## [0.1.4] - 2026-03-11 ### Fixed - Jewelry object visible in the first frame after entering try-on mode. ## [0.1.3] - 2026-03-11 ### Fixed - Inconsistent AO setting. ## [0.1.2] - 2026-03-08 ### Fixed - Video scale not applied correctly. - Quaternion filters improved. ## [0.1.1] - 2026-03-08 ### Fixed - Video texture lagging behind during zoom on invisible elements. - Error messages being to short. - Restore older hand tracking smoothing functions in MPHand to address degraded tracking. ## [0.1.0] - 2026-03-06 ### Added - WristwearTryonPlugin: Add a watch and bracelet try-on. - Major refactoring of the codebase. - Refactor to support future try-on plugins. - Automatic zoom in on interaction (closer zoom of 1.5 for better experience). ### Fixed - UX improvements: preloading, polling in-store try-on plugin. - Fix occlusion for bigger jewelry like the billion dollar ring demo ring. - Various improvements for artifacts in fade shader and motion blur. ## [0.0.41] - 2026-03-01 ### Added - `preferBackCamera` option on RingTryonPlugin to allow selecting the back (environment) camera on start. ## [0.0.40] - 2026-02-16 ### Fixed - Support for larger rings (e.g. billion dollar ring demo ring) with proper occlusion (faded and SSR occluders) and shadow SSAO. - Less visual occlusion artifacts for poses like fist. - Ring try-on UI: no specific error message for most common error (camera permission denied) shown. - Enable quaternion filters for smoothing rotation flickering which was especially noticeable for larger rings like the billion dollar ring demo one. - Fix strong display artifacts when entering AR mode due to interpolation with unclamped tonemapped output color. ## [0.0.39] - 2026-01-16 ### Added - A static preload function to the RingTryonPlugin. ## [0.0.38] - 2025-12-26 ### Fixed - Disable DollyFov in camera settings. ## [0.0.37] - 2025-10-02 ### Fixed - In-store: Shader crash when using segmentation. - In-store: Address not selecting the correct camera. ### Changed - In-store: More proper syncing of MP and Leap. ## [0.0.36] - 2025-08-29 ### Changed - Demo page: css changes, changed 3d model. - minDistance change in `RingTryonConfig` ## [0.0.35] - 2025-08-27 ### Changed - Demo page: check for 'edit' query parameter to show UIConfig for TryOn. - Removed setup mode UI - static variables for mediapipe libraries ## [0.0.34] - 2025-08-15 ### Fixed - Minor fix: proper button display in demo when try-on start failed. ## [0.0.33] - 2025-08-15 ### Changed - Demo page: setup mode UI, try-on buttons only showing when try-on running. ### Fixed - Setup mode UI: proper updating in scene when config changed. ## [0.0.32] - 2025-08-06 ### Changed - Update demo link and WebGi version to 0.15.2. ## [0.0.31] - 2025-08-03 ### Changed - Disable motion blur by default. - Update WebGi version to 0.15.0. ### Fix - Add backwards compatibility for motion blur and WebGi pre-0.11.0. - Resolved issues with ring fading and hiding for certain hand poses. ## [0.0.30] - 2025-08-03 ### Changed - Refactored configuration system for improved structure and maintainability. - Improved motion blur effect; cleaned up and refactored related code. - Removed `lil-gui` dependency; moved GLSL code to separate files; improved code obfuscation workflow. ### Fixed - Addressed an issue where the asset was not being hidden entirely, causing an outline to be visible. - Camera near/far planes are now constant to address a performance issue and to prevent possible clipping artifacts. ## [0.0.29] - 2025-06-17 ### Fixed - Fix camera near/far based clipping at close range. ## [0.0.28] - 2025-06-17 ### Fixed - Revert web camera background plugin to recent version. Fix scene background reset issue introduced by reverting. ## [0.0.27] - 2025-06-06 ### Fixed - Check first for video full HD resolution. ## [0.0.26] - 2025-06-06 ### Fixed - Reverted to old web camera plugin for now. ## [0.0.25] - 2025-06-06 ### Fixed - Reverted to old web camera plugin for now. ## [0.0.24] - 2025-06-06 ### Fixed - Applied custom configs and checking for in-store plugin. ### Added - Check for in-store availability in index.ts ## [0.0.23] - 2025-06-02 ### Fixed - Revert some scene config (SSR, SSAO). ## [0.0.22] - 2025-06-01 ### Fixed - Instore build deployment. ## [0.0.21] - 2025-05-31 ### Fixed - Integrate latest development changes. - Deprecate segmenter hand analyzing. Finger width detection is now based on landmarks. - Adjust config and smoothing. ## [0.0.20-dev.10] - 2025-05-30 ### Fixed - Setup mode cylinder. ## [0.0.20-dev.9] - 2025-05-15 ### Added - Deployment --- # Ring Configurator in iJewel3D ![iJewel Ring Configurator](../assets/images/ring-builder/PRC.webp) iJewel3D Ring Configurator is a powerful tool that lets you create interactive, customizable ring configurators for your jewelry business. By combining modular ring components (heads and shanks), customers can explore hundreds of ring variations in real-time 3D choosing diamond shapes, carat sizes, shank styles, and materials. Whether you want to embed a configurator on your website, share it directly with customers, or self-host it on your own server, Ring Configurator makes it simple. ### How It Works Ring Configurator uses a modular approach: instead of modeling every ring variation, you create separate **Head** and **Shank** components that iJewel combines dynamically. This means fewer 3D files to manage and endless possibilities for your customers. ## Getting Started Follow these three steps to set up your Ring Configurator: ### [1. Prepare 3D Models](./prepare-components) Learn how to prepare your ring components, assign proper layers, and set up anchor points for automatic alignment. [![Prepare Components](../assets/images/ring-builder/1P3DM.webp)](./prepare-components) **What you'll learn:** - Separating rings into Head and Shank components - Creating variations (prong counts, diamond shapes, shank styles) - Setting up anchor-based auto placement - Naming conventions and layer assignment in Rhino ### [2. Set Up in iJewel3D Platform](./ring-configurator-in-ijewel3d) Upload your components to the iJewel3D platform and configure your Ring Configurator with variations, materials, and settings. [![iJewel3D Platform](../assets/images/ring-builder/2SUIP.webp)](./ring-configurator-in-ijewel3d) **What you'll learn:** - Uploading and syncing 3D files - Configuring head and shank variations - Setting up materials and finishes - Organizing your component library ### [3. Share, Embed, or Self-Host](./using-ring-configurator) Deploy your Ring Configurator to reach customers embed it on your website, share direct links, or use templates for self-hosting. [![Ring Configurator Templates](../assets/images/ring-builder/3CTU.webp)](./using-ring-configurator) **What you'll learn:** - Embedding the configurator on your website - Sharing direct links with customers - Using ready-made templates - Self-hosting options for full control --- # Prepare Ring Components When building rings in iJewel, you don't need to model every variation from scratch. By separating a ring into **Head** and **Shank** components, you can dynamically combine them inside iJewel to generate dozens or even hundreds of unique ring designs from a small set of files. ![Ring as Modular Components](../assets/images/ring-builder/RC.webp) ### Why Separate Components? | Benefit | Description | |---------|-------------| | **Mix and Match** | Combine any head with any shank | | **Fewer Models** | Reduce total files needed | | **Easy Updates** | Add new variations without remodeling the entire ring | ## Creating Variations Each component should have multiple variations to maximize configurability. ### Head Variations | Property | Examples | |----------|----------| | **Prong Count** | 4-prong, 5-prong, 6-prong | | **Diamond Shape** | Round, Princess, Pear, Oval, Marquise | | **Carat Size** | 0.5 ct, 1 ct, 2 ct, 3 ct | ### Shank Variations | Style | Description | |-------|-------------| | **Plain** | Simple, smooth band | | **Pave** | Small diamonds set into the band | | **Channel** | Diamonds set in a channel groove | | **Split Shank** | Band splits near the head | | **Cathedral** | Arched supports rising to meet the head | By combining these, iJewel can automatically generate dozens or hundreds of ring combinations from a small set of files. ## Two Methods for Creating Components These guidelines work with any modelling software, but examples here use **Rhino** and **MatrixGold**, as they are most commonly used in the jewelry industry. ### Method 1: Pre-Positioned Components In this method: - Each Head and Shank is modeled separately - They are positioned correctly relative to each other in 3D space - When combined, they already form a complete ring ![Pre-Positioned Components](../assets/images/ring-builder/M1.webp) ::: tip When to Use - Fixed designs with limited variations - Simple setups - When exact manual positioning is preferred ::: --- ### Method 2: Anchor-Based Auto Placement (Recommended) In this method, exact positioning is handled by iJewel automatically using an **anchor object**. #### Steps (Rhino Example) 1. Create a cube or simple shape (anchor object) 2. Place it on top of the shank, exactly where the head should sit 3. Assign the anchor object to a layer named `placeholder:head` likewise it can be anything which you want to place it over `placeholder:` ![Anchor-Based Placement](../assets/images/ring-builder/M2.webp) Once this is done: - iJewel detects the `placeholder:head` layer - Any head variation is placed exactly on top of the anchor - When shank or head changes, alignment updates automatically #### How the component is seated iJewel aligns the component to the anchor by **geometry, not by pivot**: - The component is **centred over the anchor** horizontally (X/Z) - Its **base rests on the anchor** vertically (Y) This means a head whose pivot sits below (or away from) the mesh still seats correctly on the anchor instead of floating above or sinking into it — you don't need to reset or re-centre pivots before exporting. ::: info Advantages - **No manual repositioning** – Heads snap to the correct location - **Perfect alignment** – Consistent across all variations - **Pivot-independent** – Works regardless of where the model's origin/pivot is - **Highly scalable** – Ideal for large catalogs with many combinations ::: #### Multiple anchors on one shank A single shank can expose **more than one anchor**, and each component snaps to its own anchor independently. Add one anchor object per component you want to place and name each anchor layer `placeholder:`. For example, a three-stone shank that anchors both a centre head and a side component would carry two anchors: | Anchor layer | Seats the component named | |--------------|---------------------------| | `placeholder:head` | `head` | | `placeholder:second` | `second` | When variations load, `head` snaps to `placeholder:head` and `second` snaps to `placeholder:second`. Components that have **no** matching anchor on the current shank (for example the shank itself) stay where they are. ::: tip Switching shanks Anchor positions belong to the shank. When you switch to a shank that doesn't expose a given anchor, the affected component is reset back to the model origin so it never keeps the previous shank's placement, and is then re-seated on whatever the new shank does anchor. ::: ## Naming Conventions (Recommended) Good naming makes files easier to manage especially in large libraries. ### Suggested Format ``` - ``` ### Example ``` H123-Rd20 ``` | Part | Meaning | |------|---------| | `H123` | Head SKU identifier | | `Rd` | Round diamond shape | | `20` | 2.0 carat size | ::: tip This naming convention is **not mandatory**, but strongly recommended for clean, organized workflows. ::: ## When Component Separation Is Not Needed If you want to create complete ring variations (not configurable parts): - Head and shank separation is **not required** - Each variation should be a separate full ring model ### Comparison Example **5 head styles × 5 shank styles:** | Approach | Total Models | |----------|--------------| | Without separation | 25 full ring models | | With separation | 10 models (5 heads + 5 shanks) | ::: warning Component separation becomes extremely valuable as variations grow. For catalogs with many options, modular components save significant modeling time. ::: ## Assigning Layers in Rhino Every 3D model in Rhino is divided into objects, and each object can have an associated layer. Proper layering is essential for iJewel to correctly identify and apply materials to different parts of your ring. ![Rhino Layers Example](../assets/images/rhino_layers1.webp) And all layers present in the 3D model: ![Rhino Layers Example](../assets/images/rhino_layers2.webp) ### Layer Guidelines for Ring Configurator When preparing ring components for the Ring Configurator: - **Name layers consistently** across all files - **Separate diamond shapes** – Put unique shapes (round, pear, marquise) in separate layers for accurate diamond cuts - **Group similar diamonds** – Similar diamond shapes with transforms (rotation/scale/translation) should be in the same layer when possible - **Separate for materials** – Use different layers when different materials need to be assigned - **Multi-tone metals** – Create separate layers for parts that need different metals (e.g., `Head`, `Shank`) ### Recommended Layer Names | Material Type | Layer Name Format | |---------------|-------------------| | Metals | `Metal 01`, `Metal 02`, ... | | Diamonds/Gemstones | `Gem 01`, `Gem 02`, ... | | Pearls | `Pearl 01`, `Pearl 02`, ... | | Ceramic/Enamels | `Ceramic 01`, `Ceramic 02`, ... | ### Special Layers for Ring Configurator | Layer Name | Purpose | |------------|---------| | `placeholder:` | Anchor point for automatic placement of the component named `` (e.g. `placeholder:head`). Add one per component you want auto-placed. | | `Head` | The head component (top part holding the center stone) | | `Shank` | The shank component (ring band) | ## General Tips for Preparing 3D Models - **Use Block Instances** for identical parts (similar diamonds, chain links, prongs) - **Optimize mesh resolution** – Not too high (large file size), not too low (poor quality) - **Keep polygon count manageable** - Aim for under 200,000 polygons per model - **Use face normals** for diamonds/gems to produce accurate cuts - For high-resolution meshes, use Rhino's `ReduceMesh` command to lower polycount while maintaining quality ::: warning Render vs Production CAD Production CAD files are optimized for manufacturing, not rendering. Common issues include: - Sharp edges and prongs - Seam artifacts - Combined metal parts - Penetrating surfaces Fix these issues before using in Ring Configurator for best results. ::: ## Exporting from Rhino 1. **Switch to Shaded Mode** before exporting (converts NURBS surfaces to meshes) ![Rhino Shaded Mode](../assets/images/rhino_shadedmode.webp) 2. **Export as `.3dm`** format 3. **Do NOT enable "Save small"** option – this removes meshes and iJewel needs meshes to render properly ![Rhino Export Settings](../assets/images/rhino_export.webp) ## Next Steps Once your components are prepared: 1. [Upload and sync files to iJewel](./ring-configurator-in-ijewel3d) – Learn how to import your components 2. Configure variations and combinations in the Ring Configurator plugin --- # Ring Configurator inside iJewel3D ![Ring Configurator](../assets/images/ring-builder/2SUIP.webp) The iJewel3D platform provides an intuitive interface for managing your ring configurator project. Follow these detailed steps to upload your 3D models and configure your Ring Configurator. ### Step 1: Access iJewel3D Log in to [iJewel3D platform](https://ijewel3d.com/drive/login) using your account credentials. If you don't have an account, [create](https://ijewel3d.com/drive/signup) one first. ::: info Plan requirements Every plan includes the Ring Configurator, from Free upward. On any plan you can create a Ring Configurator project, upload your components, and publish it. Whitelabeling — an embed with the iJewel branding removed — needs the **Silver** plan or above. See [Whitelabeling and Branding](../integrations/whitelabeling). To upgrade, go to Settings → Billing. To request a demo, contact us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com). ::: ### Step 2: Create a New Ring Configurator Project From the My Files root folder, locate and click the **Add New** button, then select **New Ring Configurator** from the dropdown menu. ![New Ring Configurator Project](../assets/images/ring-builder/platform/create-new-project.webp) ### Step 3: Name Your Project Enter a descriptive name for your configurator project. This name will help you identify and manage the project in your dashboard. Choose a name that reflects the ring collection or product line. **Example project names:** - Solitaire Ring Collection - Diamond Engagement Rings 2025 - Custom Band Configurator ![Project Naming](../assets/images/ring-builder/platform/project-name.webp) ### Step 4: Open the Configurator Folder Double-click on your newly created configurator project to open it. This will display the project's folder structure where you can add and manage ring components. ![Open Project Folder](../assets/images/ring-builder/platform/new-component.webp) ### Step 5: Create Component Folders Create new component folders for each part of your ring design. Common components include: - **Head**: The setting that holds the gemstone - **Shank**: The band portion of the ring - **Band**: Alternative band styles or widths The folder names you create will appear directly in the configurator UI, so organize and name them carefully to provide a logical user experience. ![Create Components](../assets/images/ring-builder/platform/components.webp) ### Step 6: Upload Your 3D Files For each component folder: 1. Double-click the component folder to open it 2. Click the **Upload** button 3. Select your prepared 3D model files (from Step 1) 4. Wait for the upload to complete Repeat this process for each component and its variations. ![Upload Files](../assets/images/ring-builder/platform/upload-options.webp) ### Step 7: Automatic Synchronization The configurator will automatically sync your uploaded models. You can monitor the sync progress in the interface. For manual synchronization, click the **Sync Configurator** button located within the ring configurator project settings. ![Sync Progress](../assets/images/ring-builder/platform/upload-and-sync.webp) ### Step 8: Configure Advanced Settings and Try-On Select the Ring Configurator project. Then choose **Open In → Editor** or **Open In → Playground**. Both options open the project editor. Use the editor to: - **Configure HDR Maps**: Set up environment lighting and reflections - **Adjust Materials**: Define material properties such as colour, texture, etc - **Set Background**: Choose or upload a custom background image - **Fine-tune Lighting**: Adjust brightness, shadows, and light direction - **Configure Camera**: Set default zoom, rotation, and pan parameters - **Configure Try-On**: Fit the ring assembled from the currently selected components to the AR finger guide To configure Try-On: 1. Assemble the ring that you want to use for calibration. 2. Open **TryOn Settings** in the editor. 3. Turn on **Enable AR**. 4. Select **Enter Setup**. 5. Use **Auto Fit**, then correct the size, position, and rotation if necessary. 6. Select **Exit Setup** and **Preview in AR**. 7. Save the project. The saved Try-On fit belongs to the Ring Configurator project. The customer can try on any ring assembled from its components. You do not need a separate Try-On model file. See [Prepare a Try-On Project](../tryon/prepare-model) for the fitting controls and test procedure. Save all other editor changes too. The saved settings appear in the Viewer. ![Advanced Settings](../assets/images/ring-builder/platform/context-menu.webp) ### Step 9: Deploy Your Configurator Once you've completed all configurations, proceed to [Using Ring Configurator](./using-ring-configurator) to learn about deployment options including embedding, sharing, and custom templates. ## Advanced Configuration: Tags Tags allow you to organize and filter variations within components. This is especially useful for **Head** components where you have multiple diamond shapes and carat sizes. ### How Tags Work Tags are key-value pairs assigned to each 3D file in the iJewel3D platform. The Ring Configurator uses these tags to: - Group variations by diamond shape - Filter available sizes within each shape - Display organized UI options to customers ### Setting Up Tags 1. Right-click on a 3D file (variation) in your component folder 2. Click **Edit Tag** from the context menu 3. Add tags in the format `key:value` 4. Click **Save** to apply the tags ![Tag editing](../assets/images/ring-builder/platform/tags.webp) ### Tag Format | Tag Type | Format | Example | |----------|--------|---------| | Shape | `shape:` | `shape:round` | | Size | `size:` | `size:1ct` |¬¬ **Example:** A 1-carat round diamond head would have both tags: - `shape:round` - `size:1ct` ### Complete Example For a head component with multiple shapes and sizes: | File Name | Tags | |-----------|------| | `H001-Rd05.3dm` | `shape:round`, `size:0.5ct` | | `H001-Rd10.3dm` | `shape:round`, `size:1ct` | | `H001-Rd20.3dm` | `shape:round`, `size:2ct` | ::: tip Best Practice Always tag **all** head variations with both `shape:` and `size:` tags. This ensures the UI can properly filter and display options. ::: To learn how to use these tags in your custom template code, see [Using Tags for Filtering](./using-ring-configurator#advanced-using-tags-for-filtering). ## Advanced Configuration: Icons To update the thumbnail/icon for a variant: 1. Open the variant in **Playground** and make your adjustments 2. Save the changes 3. Return to the platform, right-click on the variant 4. Click **Update Thumbnail** to capture the new icon --- # Using Ring Configurator ![iJewel Ring Configurator](../assets/images/ring-builder/RB.webp) This guide covers how to deploy and use your ring configurator after setting it up in the iJewel3D platform. ## Deployment Options Once your Ring Configurator is configured, choose how the page and project are hosted: | Option | Best For | Complexity | |--------|----------|------------| | **Direct Embedding** | Quick integration | Low | | **Share Link** | Sending to customers | None | | **Custom page with a Drive project** | A custom storefront UI while Drive continues to store the project | Medium | | **Fully self-hosted project** | Hosting the project JSON and assets on your own infrastructure | Advanced | ### Make Your Configurator Public Direct embedding, share links, and `loadModelById` require the Drive project to be **Public**. By default, configurators are accessible only inside iJewel3D Platform. To make a Drive project available to a website: 1. Right-click on your Configurator file in the iJewel3D platform. 2. Select **Make Public**. ![Make Configurator Public](../assets/images/ring-builder/platform/make-public.webp) A fully self-hosted project does not load the Drive file at runtime. Its project JSON, component assets, and scene resources must instead be publicly readable from the host or CDN. ## Option 1: Direct Embedding Embed your ring configurator directly on any webpage using an iframe. ```html ``` Learn more about [embedding configurators](/viewer/tutorial-embed-drive). ## Option 2: Share Link Share your configurator directly with customers using the link from the iJewel3D platform. This requires no coding. Just right click on Ring configurator. Click on share. Copy the link and share it with your customers. ![Share Link](../assets/images/ring-builder/platform/share.webp) ## Option 3: Custom Page with a Drive Project Host the page and custom controls yourself while Mini Viewer loads the public Ring Configurator project from iJewel3D Drive. ### Prerequisites - Your **File ID** from the iJewel3D platform - Your **Instance Name** (provided by iJewel, e.g., `dev-2`) ### Required Scripts The mini-viewer needs **webgi** to run. Load webgi **first**, then the mini-viewer `nowebgi` build (the `nowebgi` bundle does not include webgi, so it must be provided separately): ```html ``` ::: tip Multiple anchors per shank Support for **multiple anchors on a single shank** (each component snapping to its own `placeholder:` mesh) requires **mini-viewer 0.6.10 or later**. Use the latest version shown above to get it. See [Prepare Ring Components](./prepare-components#multiple-anchors-on-one-shank) for how to author the anchors. ::: ### Basic Setup Create an `index.html` file with this minimal structure: ```html Ring Configurator

Controls

``` ### Configuration Variables | Variable | Description | |----------|-------------| | `fileId` | Your ring configurator's unique ID from the iJewel3D platform | | `instance` | Your client identifier provided by iJewel (e.g., `drive`) | ### Add Try-On to the custom page Configure Try-On on the Drive project with **Open In → Editor** or **Open In → Playground**, then save it. `loadModelById` receives the saved top-level `tryonConfig`; do not duplicate that configuration in the page. Mini Viewer `0.6.18` or later groups the visible head, shank, stones, and other components as one assembled ring for the Try-On session and restores the configurator afterward. The example already uses `showUiButtons: true` and `hideTryOn: false`, so the button appears when the Drive project enables Try-On. See [Prepare a Try-On Project](../tryon/prepare-model) for fitting instructions. ## Option 4: Fully Self-Hosted Project If your website also hosts the Ring Configurator project JSON and component assets, pass that complete project object to `new ijewelViewer.Viewer(...)`. Add the saved `tryonConfig` at the top level of that project. Mini Viewer uses the configuration and prepares the customer's assembled ring when its standard Try-On button is selected. Create the fit with **Open In → Editor** or **Open In → Playground**, then copy the saved `tryonConfig` through your normal project export. If the project does not pass through iJewel3D Platform, see [RingTryonPlugin setup mode](../tryon/ring-tryon-plugin#setup-mode). For a custom Try-On button, use the public [Configurator Try-On helpers](../viewer/viewer-class#configurator-try-on-helpers) after loading the saved configuration with `tryon.fromJSON()`. ## Core Concepts ### The RingConfigurator Plugin The `RingConfiguratorPlugin` manages ring components (heads, shanks, bands) and their variations. ```javascript // Get the plugin const ringConfigurator = viewer.getPluginByType('RingConfigurator'); // Access components ringConfigurator.components.forEach(component => { console.log(component.name); // "Heads", "Shanks", etc. console.log(component.variations); // Available variations console.log(component.selectedIndex); // Currently selected index }); // Apply a variation await component.applyVariation(variation); ``` ### The MaterialConfigurator Plugin The `MaterialConfiguratorPlugin` handles material changes (metals, gems, finishes). ```javascript // Get the plugin const materialPlugin = viewer.getPluginByType('MaterialConfiguratorPlugin'); // Access material groups materialPlugin.variations.forEach(group => { console.log(group.title); // "Metal", "Gem", etc. console.log(group.materials); // Available materials }); // Apply a material await materialPlugin.applyVariation(group, material.uuid); ``` ### Events | Event | Plugin | Description | |-------|--------|-------------| | `componentProcessed` | RingConfigurator | All components finished loading | | `refreshUi` | MaterialConfigurator | Materials updated, refresh UI | | `ijewel-viewer-ready` | Window | Viewer is initialized and ready | ## Viewer Options Customize the viewer by passing options to `loadModelById`: ```javascript ijewelViewer.loadModelById(fileId, instance, container, { showConfigurator: false, // Hide default configurator UI showCard: false, // Hide product card transparentBg: false, // Use solid background showLogo: true, // Show brand logo hideFullScreen: true, // Hide fullscreen button hideResetView: true, // Hide reset view button hideFitScene: true, // Hide fit scene button hideRotateCamera: true, // Hide camera rotation controls hideCameraViews: true, // Hide camera view presets brandingSettings: { enable: true, showLoadingScreenLogo: true } }); ``` ## Advanced: Using Tags for Filtering Variations can include tags for filtering (e.g., by shape or carat size): ```javascript function parseVariationTags(variation) { const tags = variation.tags || []; let shape = null, size = null; tags.forEach(tag => { if (tag.startsWith('shape:')) shape = tag.split(':')[1]; if (tag.startsWith('size:')) size = tag.split(':')[1]; }); return { shape, size }; } // Usage: Group heads by diamond shape const groups = {}; component.variations.forEach(variation => { const { shape } = parseVariationTags(variation); if (shape) { if (!groups[shape]) groups[shape] = []; groups[shape].push(variation); } }); ``` ## Ready-Made Templates All templates are open-source and available on GitHub: [iJewelTemplates/ringconfigurator](https://github.com/ijewel3d/iJewelTemplates/tree/main/ringconfigurator) We provide pre-built templates that you can use instantly — just pass your `fileId` and `instanceName` as query parameters in the URL. No coding required to get started! ### How It Works Append your credentials to any template URL like this: ``` https://ijewel3d.github.io/iJewelTemplates/ringconfigurator/simple/ring-configurator.html?fileId=YOUR_FILE_ID&instanceName=YOUR_INSTANCE_NAME ``` Replace `YOUR_FILE_ID` and `YOUR_INSTANCE_NAME` with the values from your iJewel3D platform. ### Available Templates #### Simple Ring Configurator ![Simple Ring Configurator](../assets/images/ring-builder/template/simple-template.webp) A minimal, clean configurator with basic component and material controls. [Open Template](https://ijewel3d.github.io/iJewelTemplates/ringconfigurator/simple/ring-configurator.html) --- #### Configurator with Size & Shape ![Configurator with Size & Shape](../assets/images/ring-builder/template/gem-size-and-shape.webp) Adds size and shape filtering using tag-based grouping. [Open Template](https://ijewel3d.github.io/iJewelTemplates/ringconfigurator/simple/configurator-with-size-shape.html) --- #### Advanced Template ![Advanced Template](../assets/images/ring-builder/template/template.webp) A feature-rich configurator with a polished UI and advanced controls. [Open Template](https://ijewel3d.github.io/iJewelTemplates/ringconfigurator/advanced/template.html) --- #### Advanced Template v2 ![Advanced Template v2](../assets/images/ring-builder/template/template-v2.webp) The latest version of the advanced template with an updated design and improved UX. [Open Template](https://ijewel3d.github.io/iJewelTemplates/ringconfigurator/advanced/template-v2.html) ::: tip Quick Start Pick any template above, append `?fileId=YOUR_FILE_ID&instanceName=YOUR_INSTANCE_NAME` to the URL, and open it in your browser to instantly preview your ring configurator with your own 3D models. ::: ### Example If your File ID is `abc123` and your instance name is `drive`, open: ``` https://ijewel3d.github.io/iJewelTemplates/ringconfigurator/advanced/template-v2.html?fileId=abc123&instanceName=drive ``` This will load the Advanced Template v2 with your ring configurator data rendered in real-time. ## Next Steps - Review the full [RingConfigurator Plugin API](./plugin-detail) - Learn about [embedding configurators](/viewer/tutorial-embed-drive) ::: details Contact For questions or assistance, email us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com) ::: --- # RingConfigurator Plugin API Reference ![Ring Configurator Plugin](../assets/images/ring-builder/PRC-1.webp) The `RingConfiguratorPlugin` is a iJewel3D plugin that enables dynamic ring configuration by managing multiple components (like heads, shanks, and bands) with interchangeable model variations. It provides the foundation for building interactive ring configurators. ## RingConfiguratorPlugin ### Plugin Type ```typescript RingConfiguratorPlugin.PluginType = 'RingConfigurator' ``` ### Properties | Property | Type | Description | |----------|------|-------------| | `enabled` | `boolean` | Whether the plugin is enabled | | `components` | `Component[]` | Array of ring components managed by the plugin | | `rootScale` | `number` | Scale factor applied to all models in the scene | ### Methods #### `setRootScale(value: number)` Sets the scale of the entire ring model root and refreshes the view. ```typescript const ringConfigurator = viewer.getPluginByType("RingConfigurator"); ringConfigurator.setRootScale(1.5); ``` #### `matchBaseHeight(comp1: Component, comp2: Component, seperation?: number)` Aligns two components by matching their base heights and optionally setting separation distance. It can be used to add matching Bands to current Ring. - **Parameters**: - `comp1`: The reference component - `comp2`: The component to align - `seperation`: Optional distance between components (defaults to 2× width of comp1) ```typescript const shank = ringConfigurator.getComponent("Shank"); const band = ringConfigurator.getComponent("Band"); ringConfigurator.matchBaseHeight(shank, band, 0.5); ``` #### `autoPositionSet(componentName?: string, modelObject?: ISceneObject)` Snaps components onto their anchors. For every component that has a matching anchor mesh in the scene — a mesh whose material is named `placeholder:` — the component is seated on that anchor by geometry (centred in X/Z, base resting on the anchor in Y, so a model's pivot offset doesn't matter). A shank can expose several anchors (e.g. `placeholder:head` and `placeholder:second`), and each named component snaps to its own. Components without a matching anchor (such as the shank itself) are left in place. This runs automatically when variations are applied, so you rarely need to call it directly. Pass a `componentName`/`modelObject` pair to register a freshly loaded model before positioning. ```typescript // Re-seat everything against the current anchors ringConfigurator.autoPositionSet(); ``` #### `resetComponentPositions(componentNames?: string[])` Resets components back to their model origin `(0, 0, 0)`, undoing any anchor auto-positioning. With no argument every component is reset; pass an array of component names to reset only those. Call this before switching shanks so a component (e.g. a head) doesn't keep the previous shank's anchor position on a shank that has no matching anchor; `autoPositionSet` then re-seats whatever the new shank does anchor. ```typescript // Reset a specific component before loading a new shank ringConfigurator.resetComponentPositions(["head"]); // Reset all components ringConfigurator.resetComponentPositions(); ``` #### `createComponent(name: string): Component` Creates a new component with the specified name and adds it to the plugin. ```typescript const headComponent = ringConfigurator.createComponent("Head"); ``` #### `removeComponent(name: string)` Removes and disposes of a component by name. ```typescript ringConfigurator.removeComponent("Head"); ``` #### `getComponent(name: string): Component | undefined` Retrieves a specific component by name. ```typescript const shank = ringConfigurator.getComponent("Shank"); if (shank) { await shank.applyVariation(shank.variations[0]); } ``` #### `getComponents(): Component[]` Returns all components managed by the plugin. ```typescript const allComponents = ringConfigurator.getComponents(); allComponents.forEach(comp => console.log(comp.name)); ``` ### Events | Event | Description | |-------|-------------| | `componentProcessed` | Fired when all components have finished loading their variations | ```typescript ringConfigurator.addEventListener("componentProcessed", () => { console.log("All components are ready!"); }); ``` ## Component Class The `Component` class represents a single configurable part of the ring (e.g., head, shank, band). ### Properties | Property | Type | Description | |----------|------|-------------| | `name` | `string` | Unique identifier for the component | | `title` | `string` | Display title for UI | | `selectedIndex` | `number` | Index of the currently selected variation (-1 if none) | | `position` | `Vector3` | Position offset of the component | | `rotation` | `Euler` | Rotation of the component | | `visible` | `boolean` | Visibility state | | `variations` | `ModelVariation[]` | Array of available model variations | | `fileId` | `string \| number` | File identifier for the component | ### Methods #### `setPosition(position: Vector3)` Sets the position of the component in 3D space. ```typescript import { Vector3 } from 'webgi'; component.setPosition(new Vector3(0, 1, 0)); ``` #### `setRotation(rotation: Euler)` Sets the rotation of the component. ```typescript import { Euler } from 'webgi'; component.setRotation(new Euler(0, Math.PI / 4, 0)); ``` #### `setVisible(visible: boolean)` Shows or hides the component. ```typescript component.setVisible(false); // Hide component.setVisible(true); // Show ``` #### `isVisible(): boolean` Returns the current visibility state. ```typescript if (component.isVisible()) { console.log("Component is visible"); } ``` #### `getBounds(): Box3B` Returns the bounding box of the component. ```typescript const bounds = component.getBounds(); const size = bounds.getSize(new Vector3()); console.log(`Width: ${size.x}, Height: ${size.y}, Depth: ${size.z}`); ``` #### `addVariation(variation: ModelVariation)` Adds a model variation to the component's available options. ```typescript component.addVariation({ name: "round-diamond", title: "Round Diamond", modelUrl: "https://cdn.example.com/models/round-diamond.glb", fileId: "abc123", iconUrl: "https://cdn.example.com/icons/round-diamond.png" }); ``` #### `removeVariation(variation: ModelVariation)` Removes a variation from the component. ```typescript const variation = component.findVariationByName("round-diamond"); if (variation) { component.removeVariation(variation); } ``` #### `findVariationByName(name: string): ModelVariation | undefined` Finds a variation by its name. ```typescript const variation = component.findVariationByName("solitaire-head"); ``` #### `applyVariation(variation: ModelVariation, applyMaterial?: boolean): Promise` Applies a variation to the component, loading the 3D model and optionally applying materials. - **Parameters**: - `variation`: The variation to apply - `applyMaterial`: Whether to reapply materials (default: `true`) ```typescript const variation = component.findVariationByName("princess-cut"); if (variation) { await component.applyVariation(variation); } ``` --- #### `dispose()` Disposes of the component and frees resources. ```typescript component.dispose(); ``` ## ModelVariation Interface Defines the structure for a model variation option. ```typescript interface ModelVariation { name: string; // Unique identifier title?: string; // Display name for UI tags?: string[]; // Tags for filtering/categorization selected?: string; // Selection state identifier uuid?: string; // Unique identifier modelUrl: string; // URL to the 3D model file iconUrl?: string; // URL to the thumbnail/icon fileId: string | number; // File identifier } ``` ## Integration with MaterialConfiguratorPlugin The RingConfiguratorPlugin works seamlessly with the `MaterialConfiguratorPlugin` to handle material changes. When a variation is applied, materials are automatically reapplied unless explicitly disabled: ```typescript // Apply variation without reapplying materials await component.applyVariation(variation, false); // Apply variation with materials (default behavior) await component.applyVariation(variation, true); ``` ::: tip For optimal performance, set `applyMaterial` to `false` when making multiple rapid changes, then manually trigger material application once all changes are complete. ::: ## Next Steps - Learn how to [embed your configurator](/viewer/tutorial-embed-drive) on your website - Check out the [Ring Configurator setup guide](./ring-configurator-in-ijewel3d) ::: details Contact For questions or assistance with the RingConfigurator integration, email us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com) ::: --- # Wedding Band Builder ### A real time wedding band configurator with physically based rendering. No pre rendered catalog. No static images. Every ring your customers design is generated in real time: unique geometry, real materials, accurate pricing, directly in the browser. Full Wedding Band Builder interface — His & Her bands with configuration panel, real-time 3D preview, and pricing summary ## Three Pillars ### Photorealistic 3D in the Browser Customers see a real time 3D model with physically accurate materials, lighting, and reflections. White gold looks like white gold. A hammered finish catches light differently than polished. Material properties are tuned to match real metal alloys. ### Parametric Design, No 3D Models to Manage Every ring is built from parameters, not pre made files. The current Drive starter provides 7 profile shapes, 3 metals, 7 finishes, 3 partition modes, 4 diamond settings, and continuous width/height dimensions. You can replace or extend those catalogs in your project, and the engine generates the selected geometry on demand. ### From Screen to CNC Every design your customers create can be exported as a detailed specification sheet: profile cross section, exact dimensions in millimeters, ring size (US/EU/UK), metal composition, diamond count and carat weight, and pricing breakdown. Ready for your CAD team or CNC machine. ## Who Is This For? | | | |---|---| | **Jewelry Brands** | Offer a premium, interactive wedding band experience on your website. Your customers design their own rings with real time photorealistic preview. | | **Online Retailers** | Drop a configurator into your Shopify, WooCommerce, or Magento store. Customers configure, see the price, and add to cart, all without leaving your site. | | **Luxury Jewellers** | Build a fully custom interface that matches your brand identity. Use the headless SDK to control every pixel while the engine handles the 3D. | | **Manufacturers** | Customers design. You manufacture. The spec sheet bridges the gap: accurate dimensions and materials, ready for production. | ## What Makes It Different | Traditional Configurators | Wedding Band Builder | |---|---| | Pre rendered image swaps | Real time 3D geometry generation | | Fixed catalog of options | Parametric: every combination is unique | | Separate pricing spreadsheets | Volume based pricing from actual 3D geometry | | Desktop-only or app-required | Web based, mobile ready, AR capable | | Generic white label UI | Fully customizable SDK with theming | | Single pricing model | Western markup, Indian making charges, Gulf per-gram | ## Get Started Want runnable code first? Open the [Wedding Band starter templates](./templates), where every example includes both a live page and its GitHub source. --- # Why Wedding Band Builder ## The Problem Most online jewelry stores present wedding bands as static image catalogs with a fixed set of pre made options. This creates several issues for jewellers: - **Lost sales**: customers can't visualize exactly what they want, so they hesitate or leave - **Returns and remakes**: what looked good in a photo doesn't match expectations - **Limited catalog**: every new option requires new photography, new 3D models, new SKUs - **No at-home experience**: customers still need to visit a store to see the ring in context ## The Solution The Wedding Band Builder replaces static catalogs with a **real time design engine**. Customers design their ring by adjusting dimensions, materials, and details that update live in 3D. The rendered preview reflects physically based materials and lighting. ## Competitive Advantages ### Runs in the Browser, No App Needed The configurator runs entirely in the browser on desktop, tablet, and phone. No app install or plugin is required. Reducing friction between browsing and purchasing tends to improve conversion rates. The same configurator running in a laptop browser and on a phone, with no app installed ### AR Try On Customers can preview their designed ring on their hand using camera-based live hand tracking. This gives a sense of scale and appearance before purchasing. ### Spec Sheets for Manufacturing Every design produces a precise specification sheet: profile cross section diagram, dimensions in millimeters, ring size across three international systems, metal composition, diamond count and carat weight, and complete pricing breakdown. Your CAD team or CNC machine gets exactly what was designed on screen. ### His & Her Paired Band Configuration Customers design both bands together. Linked mode keeps both rings in sync: change the metal on one, both update. Independent mode lets each band be unique. The pricing shows individual and combined totals. ### Global Pricing Not every jeweller prices the same way. The engine supports: - **Western model**: markup multiplier (1.5×–2.5×) covering all costs - **Indian model**: explicit making charges (8–35% of metal cost) - **Gulf model**: per-gram making charges ($5–$50/gram) Per-metal pricing (white gold costs more than yellow due to palladium), finish surcharges, diamond setting labor costs, and configurable rounding are all built in. ### Physically Based Rendering The 3D engine uses PBR materials with image-based lighting and real time gem refraction. White gold has the reflectance of a palladium alloy. A hammered finish displaces the surface geometry. Diamonds refract light through computed facets. This isn't a texture swap on a generic 3D model. ### No Vendor Lock In Your configuration data is JSON. Export it, store it, migrate it. The headless API means your frontend is yours: your team or agency builds and maintains the UI without depending on a third party for every change. Switch hosting, switch CMS, switch developer. The data and the integration stay portable. ### Works With Any Manufacturer The spec sheet is manufacturer-independent. It outputs profile cross sections, exact dimensions in millimeters, ring size across three international systems, metal composition, and diamond specs. Send it to any workshop, any CAD team, any CNC machine. ### Your Brand, Your Design Use the built-in UI with one of 11 theme presets, or build your own interface from scratch using the headless SDK. The configurator is a white label engine. Your customers see your brand, not ours. No billable hours to a vendor for branding changes or layout updates. ### Mobile Optimized The 3D engine is optimized for mobile GPUs. Touch gestures such as pinch to zoom and swipe to rotate work natively. On compatible devices, camera Try-On lets customers preview the ring on their hand in current Safari on iOS and Chrome on Android. ### Predictable Costs One-time onboarding plus an annual subscription. No opaque project pricing, no change orders for every UI tweak. You know what you'll pay. ### Dedicated Onboarding Setup assistance is included. Documentation, email support, and a partner network for integrations. You're not left to figure it out from a wiki. ### Ecommerce Ready Drop in integrations for the platforms your business already uses: | Platform | Integration | |---|---| | **Shopify** | Liquid section, iframe embed, add-to-cart bridge | | **WooCommerce** | Shortcode or custom product template | | **Magento** | Custom block with Storefront API | | **BigCommerce** | Stencil theme template | | **Wix** | HTML embed with Velo integration | Or integrate directly with any website using a ` ``` Best for: custom websites, React/Vue/Angular apps, full API access. → [Full script tag guide](./integration-direct) · [Framework examples](./frameworks/vanilla) ## What's Next? Choose your path based on what you need: | I want to... | Go to | |---|---| | Customize the look and feel | [Theming & Branding](./theming) | | Build my own UI from scratch | [Custom UI (Headless)](./integration-headless) | | Set up pricing | [Pricing Engine](./pricing) | | Add to Shopify / WooCommerce / etc. | [E-Commerce Platforms](./ecommerce/shopify) | | See the full API | [API Reference](./api-reference) | | Understand the measurement system | [Ring Measurements Guide](./measurement-guide) | --- # Wedding Band Starter Templates Use these maintained examples as implementation starting points. Every row includes a live GitHub Pages build and the exact source currently published from the `main` branch of [`iJewelTemplates`](https://github.com/ijewel3d/iJewelTemplates). | Template | Use it when | Live | Code | | --- | --- | --- | --- | | Built-in Wedding Band UI | You want to load a complete Wedding Band project and use the standard iJewel3D interface. | [Open live](https://ijewel3d.github.io/iJewelTemplates/wedding-band/wedding-band.html) | [View HTML](https://github.com/ijewel3d/iJewelTemplates/blob/main/wedding-band/wedding-band.html) | | Published Drive project | You have a public Drive file ID and want the smallest `loadModelById` example. | [Open live](https://ijewel3d.github.io/iJewelTemplates/wedding-band/wedding-band-default.html) | [View HTML](https://github.com/ijewel3d/iJewelTemplates/blob/main/wedding-band/wedding-band-default.html) | | Custom UI | You want same-page controller access and a fully custom storefront interface. | [Open live](https://ijewel3d.github.io/iJewelTemplates/wedding-band/custom-ui/index.html) | [Browse source](https://github.com/ijewel3d/iJewelTemplates/tree/main/wedding-band/custom-ui) | | iframe host integration | You want custom host-page controls around a published Drive embed using `postMessage`. | [Open live](https://ijewel3d.github.io/iJewelTemplates/wedding-band/iframe-demo/index.html) | [Browse source](https://github.com/ijewel3d/iJewelTemplates/tree/main/wedding-band/iframe-demo) | The folder-based examples depend on their adjacent JavaScript, CSS, JSON, and image assets, so copy the whole folder rather than only `index.html`. ::: info Release baseline The documentation examples use Mini Viewer `0.6.18`, which adds configurator Try-On on top of the material variants, outside and inside material features, and Modern Metals layout from `0.6.17`. The linked templates are maintained in a separate repository and may still show an earlier pinned version. Check the script URL in the source you copy and use `0.6.18` or later when the project offers Try-On. The hosted iframe uses the Viewer version deployed by `ijewel3d.com`. ::: ::: warning Hosted iframe version requirement The iframe host controls require the `ijewel3d.com` embedded application to be deployed with Mini Viewer `0.6.11` or newer. If the rings render inside the iframe but the host remains on **Loading iframe…**, the hosted application is still serving an older Viewer. Update that deployment or use the self-hosted iframe viewer from the [iframe guide](./integration-iframe). ::: ## Choose the right starting point - Start with **Published Drive project** when your Wedding Band configurator already exists in iJewel Drive. Replace its `fileId` and `instance`. If it does not exist yet, start with [Create a Project](./drive-setup). - Start with **Built-in Wedding Band UI** when you are loading a complete project JSON and want the standard controls. - Start with **Custom UI** when your controls and viewer run on the same page. The implementation reads catalogs from the controller instead of hard-coding profile, material, variant, finish, and diamond choices. - Start with **iframe host integration** when the viewer and host page have different origins or when a CMS owns the outer page. ## Before production 1. Replace demo project URLs, Drive file IDs, instance names, prices, and cart behavior with your own values. 2. Compare the template's pinned SDK URL with the version required by this documentation. Configurator Try-On requires Mini Viewer `0.6.18` or later. 3. For iframe integrations, restrict `postMessage` to the exact viewer origin. 4. Serve the page over HTTPS and retain `allow="camera"` if Try-On runs inside an iframe. 5. Test desktop and mobile layouts with the actual catalog and project size. Continue with [Assets Setup](./assets-setup) to prepare your own profiles, materials, icons, and models, or go directly to the [integration guides](./deployment). --- # Setting Up Assets on iJewel Platform Before deploying your Wedding Band Builder, you need to configure all the building blocks on the iJewel platform. This page covers each asset type and how to prepare it. When these assets are ready, [Create a Project](./drive-setup) shows the complete creation flow, the generated folder structure, exact Sync rules, version migration, and which configuration fields Sync preserves. ## 2D Profiles Profiles are **2D cross section curves** that define the shape of the wedding band. The builder extrudes these curves along a circular torus path to generate the 3D ring geometry in real time. The platform includes several built-in profiles: | Profile | Description | |---------|-------------| | D-Shape | Classic rounded exterior, flat interior | | Flat | Flat exterior and interior | | Comfort | Rounded on both exterior and interior | | Knife Edge | Pointed peak on the exterior | | Beveled | Angled flat facets on the exterior | | Concave | Inward-curving exterior surface | | Round | Fully circular cross section | **Custom profiles** can be uploaded as `.3dm` (Rhino) files containing a single closed 2D curve. The curve defines the cross section shape, which the builder then extrudes and scales based on the user's width and thickness settings. Custom profile upload needs the **Silver** plan or above. The profiles in the table above are the built-in library, available on every plan. See [Create a Project](./drive-setup) for the upload steps. ::: warning The 2D profile curve must be drawn in accurate millimeter dimensions. The engine uses the curve's actual size as the base measurement for width and thickness. If your profile is drawn at the wrong scale, all dimensions, weight calculations, and pricing will be incorrect. ::: ## Material Library The material library models the real combinations your catalog offers instead of assuming a complete metal-by-finish grid: ```text base material → variant/quality → finish PMAT ``` Examples include Yellow Gold → 14k/18k/22k → Polished/Brush/Hammered, Carbon → pattern 1/pattern 2 → a single default PMAT, and Wood → species → a single default PMAT. The standard Drive folder layout is: ```text materials///.pmat ``` Each `.pmat` is a self-contained PBR material that controls color, reflectivity, roughness, maps, and embedded textures. Variant folder names are the qualities shown in the UI, so carat/karat choices belong between the base colour and surface finish axes rather than being encoded in the finish name. ### Material roles `materials//material.json` classifies a material: ```json { "name": "Yellow Gold", "kind": "metal", "usage": ["band", "inlay", "overlay", "sleeve"], "defaultVariant": "18k", "defaultFinish": "polished" } ``` | Role | Where it appears | | --- | --- | | `band` | Main ring colour/body picker | | `inlay` | Inlay material picker | | `overlay` | Overlay material picker | | `sleeve` | Inside/bore sleeve picker | Omitting `material.json` does not prevent Sync, but the fallback exposes the material to every role. Always add metadata for role-specific materials. The reference Viewer material library uses these classifications: | Material | Usage | | --- | --- | | Yellow, White, and Rose Gold | `band`, `inlay`, `overlay`, `sleeve` | | Carbon | `band` | | Marble and Wood | `inlay`, `overlay` | | Ceramic and Turquoise | `sleeve` | These roles explain why the main color picker can contain only the three gold colors and Carbon while the Outside and Inside pickers expose other materials. ### Surface finishes Surface finishes control the texture and appearance of the ring's exterior. Common finishes include: | Finish | Description | |--------|-------------| | Polished | Mirror-smooth reflective surface | | Hammered | Hand-hammered texture with organic dimples | | Brush | Fine directional brushing lines | | Ice | Crystalline frost-like texture | | Nature | Organic bark like texture | | Sand | Fine granular matte texture | | Linear | Straight-line brushing pattern | The PMAT filename is the finish ID. For example, `materials/yellow/18k/hammered.pmat` offers Hammered only for Yellow Gold 18k. The `finishes/hammered/` Drive folder supplies its picker icon; it does not hold the PMAT. Use `default.pmat` when a variant has no finish axis. Prefix a PMAT with `_` when the renderer needs it structurally but it must stay out of the picker; `_polished.pmat` is the common polished-interior fallback. If an explicit `polished.pmat` also exists, it takes precedence. ### Sources versus published assets `materials/_sources/` is optional authoring storage and is ignored by Drive Sync. It is not required on Packs/CDN and is never referenced by the runtime manifest. Publish only the current PMATs inside visible base/variant folders, plus their icons and metadata. PMAT files are runtime assets, not JavaScript dependencies. Mini Viewer and Mini Editor builds contain URL strings, not the PMAT bytes. The browser loads the selected PMAT from iJewel Drive, Packs, or your CDN when required. ::: details Reference repository material scripts The Viewer development fixture has two maintainer scripts with different jobs: - `materials/_sources/build-tree.py` derives the reference runtime tree from authored PMAT sources. It creates gold karats, finish variants, role metadata, and hidden polished-interior files. It replaces generated gold PMAT files, so do not run it against a manually curated customer tree. - `build-materials.mjs` scans the completed runtime tree, validates PMAT texture references, derives swatches and catalogs, then rewrites the material blocks in the development `wedding-band-project.json`. Drive users do not run either script. Drive Sync performs catalog publication from the uploaded folder tree. Neither script runs as part of a Mini Viewer or Mini Editor bundle build. The reference gold catalog preserves `brush` and `linear` as separate saved finish IDs. It does not rename either one to `satin`. Ceramic can define its own independent `satin.pmat` finish. ::: ## Ring Catalog Pre-modelled rings that customers can add to the compilation next to the parametric wedding bands. The catalog lives in the project manifest under `ringCatalog`, with one list per ring type: ```json "ringCatalog": { "engagement": [ { "id": "ring-1", "name": "Solitaire I", "file": "engagement/ring-1.glb", "thumbnail": "engagement/ring-1.png" } ], "memoire": [ { "id": "eternity-1", "name": "Eternity I", "file": "eternity/eternity-1.glb", "thumbnail": "eternity/eternity-1.png", "scaleAdjust": 1.12 } ] } ``` | Field | Description | |-------|-------------| | `id` | Stable identifier, used by the API and for model swapping | | `name` | Display name shown in the picker and on selection | | `file` | The `.glb` model — absolute URL or relative to `assetBaseUrl` | | `thumbnail` | Preview image for the picker (optional; a generic glyph is shown without it) | | `scaleAdjust` | Optional multiplier on the automatic size matching. Use when the model's bounding box overstates the hoop — for example, eternity prongs pointing outward | **Preparing the models:** - Export as `.glb` with real-world millimeter dimensions. The builder auto-scales each model so its hoop matches the wedding bands, but sane authoring scale keeps the measurement logs meaningful - **Name the metal material** `Metal` (or any name starting with `Metal`/`Material`). Those materials are swapped when the customer picks white, yellow, or rose gold — using the same `.pmat` files as the wedding bands, so colors always match - **Leave diamond materials unnamed or gem-named** and apply the diamond material before export. Every stone mesh must have it — a stone left on the metal material will be recolored with the metal - Merging all stones into one mesh (or instancing one stone) keeps files small and loading fast ## Option Catalogs Every option list the UI shows has a built-in default. A manifest key overrides one list. Omit the key and the built-in catalog applies, so a project declares only the lists it wants to rename, reorder, or restrict. Each entry round-trips through the project JSON, so the Mini Editor can edit any value here and `editor.getConfig()` persists it. | Key | Controls | Entry shape | |---|---|---| | `settingTypes` | Stone-setting types on top of the band | `{ id, name, iconUrl? }` | | `sideSettingTypes` | Stone settings on the flat side face | `{ id, name, iconUrl? }` | | `diamondSpans` | How far a stone run reaches around the ring | `{ id, name, iconUrl? }` | | `diamondSpacings` | Gap rule between stones | `{ id, name, iconUrl? }` | | `diamondPositionSnaps` | Snap presets above the fine-position slider | `{ id, name, value }` | | `eyeOrientations` | Eye-setting orientations | `{ id, name, value }` | | `freeStonePresets` | Curated free-stone patterns | `{ id, name, stones, iconUrl? }` | | `edgeTypes` | Edge treatments applied to both edges | `{ id, name, iconUrl? }` | | `edgeSides` | Which edges an edge treatment covers | `{ id, name, iconUrl? }` | | `sideEdgeTypes` | Treatments for one independent edge | `{ id, name, iconUrl? }` | | `grooveTypes` | Groove cross sections | `{ id, name, type?, angle?, iconUrl? }` | | `grooveFinishes` | Interior finish of a groove or joint | `{ id, name, iconUrl? }` | | `grooveDirections` | Groove direction around or across the band | `{ id, name, iconUrl? }` | | `divisionTypes` | Color-division orientations | `{ id, name, partitionCount?, iconUrl? }` | | `relationshipPresets` | Named segment-width ratios, such as 2:1:1 | `{ name, ratios }` | | `ringTypes` | Ring types a compilation accepts | `{ id, name, iconUrl? }` | `id` is the value the API accepts, and `name` is the label the UI prints. A `grooveTypes` entry adds `type`, which names the engine groove, and `angle`, which sets the opening angle of a V groove. A `divisionTypes` entry adds `partitionCount` to restrict an option to one exact partition count. ```json { "grooveTypes": [ { "id": "v60", "name": "V 60°", "type": "v", "angle": 60 }, { "id": "u", "name": "U-round", "type": "u" }, { "id": "convex-u", "name": "Dome", "type": "convex-u" } ], "relationshipPresets": [ { "name": "Even", "ratios": [1, 1] }, { "name": "Wide left", "ratios": [2, 1] } ] } ``` Read any catalog back at runtime with its matching `getAvailable…()` method. See the [API reference](./api-reference#catalog-methods). ## Scene Settings Scene settings control the 3D preview environment: - **Lighting** controls the environment map, light intensity, and shadows - **Camera** sets the default viewing angle, zoom level, and orbit constraints - **Ground** configures the ground plane appearance and shadow baking - **Post-processing** handles tone mapping, bloom, and other visual effects Scene settings are stored as `.vjson` files and can be configured through the iJewel platform or uploaded directly. The manifest points at that file with the `sceneSettings` key, which holds a URL, absolute or relative to `assetBaseUrl`. ## Pricing Configuration Pricing parameters determine how ring prices are calculated based on material weight and diamond specifications: - **Metal prices** set the price per unit for each metal type (supports grams, ounces, and troy ounces) - **Metal density** is the density in g/cm3 for accurate weight calculation (e.g., 15.5 for 18K gold) - **Diamond pricing** sets the price per carat for diamond settings - **Markup** is a multiplier applied to the subtotal For programmatic pricing control, see the [Pricing API](./pricing). ::: tip Continue on iJewel3D See [Create a Project](./drive-setup) for step-by-step project creation and folder-backed catalog management. For help preparing custom assets, contact [contact@ijewel3d.com](mailto:contact@ijewel3d.com). ::: --- # Deployment & Integration Once you've created a Wedding Band Configurator on the iJewel platform, you can deploy it in several ways. This page gives an overview, and each approach has its own detailed guide linked below. If the project does not exist yet, start with [Create a Project](./drive-setup). ## Make Your Configurator Public Before embedding or sharing, make your configurator public: 1. Open **iJewel3D Dashboard** 2. Right-click your Wedding Band Configurator file 3. Select **Make Public** ## Share Link The simplest option is to share your configurator directly with customers: 1. Open **iJewel3D Dashboard** 2. Right-click your Wedding Band Configurator 3. Select **Share** and copy the link The link opens the configurator in a standalone page with the full built-in UI. No code required. ## Integration Options For embedding on your website, choose the approach that fits your needs: | Approach | What You Get | Effort | Best For | |----------|-------------|--------|----------| | [**Direct Integration**](./integration-direct) | 3D viewer + built-in config panel on your page | Add script tags + a few lines of JS | Your own website with full control | | [**iframe Embedding**](./integration-iframe) | Self-contained viewer in an iframe | Drop in an ` ``` Use `hideWbbUi=true` for a host-page custom UI. The bundle version inside this hosted iframe is controlled by the deployed iJewel3D application. If you need to pin the viewer version yourself, use a self-hosted viewer page instead. **Custom UI (Headless)** uses either approach above but hides the built-in panel. You build your own interface using the API's catalog methods and write methods. Best for brands that need pixel-perfect control over the UI design. ## Scripts & CDN Self-hosted integrations currently use the verified WebGI and Mini Viewer release pair: ```html ``` Load WebGI first. Mini Viewer `0.6.18` is the documented baseline. It adds material variants, the outside and inside material features, the Modern Metals layout, and configurator Try-On. It also keeps the Wedding Band teardown and iframe lifecycle fixes introduced in `0.6.11`. Upgrade the pinned Viewer release only after validating it against your project. ## API Access Regardless of which integration you choose, you get full API access: | Integration | How to Access the API | |-------------|----------------------| | Direct (same page) | `viewer.getPluginByType('WeddingBandBuilder').controller`, where `viewer` comes from the `ijewel-viewer-ready` event | | iframe (same origin) | Use the postMessage protocol, or forward the viewer from a listener inside the iframe page to a parent callback registered before the iframe loads | | iframe (cross origin) | `postMessage` protocol from the parent page | The global `ijewelViewer` is the library namespace. It holds `Viewer` and the `loadModelBy*` functions. The viewer instance itself arrives on the `ijewel-viewer-ready` event. See the [API Reference](./api-reference) for the complete method and event documentation. --- # Script Tag (Direct Integration) Two maintained direct-integration examples are available: | Starting point | Live page | Source code | | --- | --- | --- | | Complete project with the built-in Wedding Band UI | [Open live](https://ijewel3d.github.io/iJewelTemplates/wedding-band/wedding-band.html) | [View source](https://github.com/ijewel3d/iJewelTemplates/blob/main/wedding-band/wedding-band.html) | | Published Drive file loaded with `loadModelById` | [Open live](https://ijewel3d.github.io/iJewelTemplates/wedding-band/wedding-band-default.html) | [View source](https://github.com/ijewel3d/iJewelTemplates/blob/main/wedding-band/wedding-band-default.html) | Add the Wedding Band Builder directly to your website with a single script tag. You get full JavaScript access to the viewer and API on the same page, with no iframes or message passing needed. ![Wedding Band Builder with the 3D viewer and the built-in configuration panel](../assets/images/wbb-full-interface.webp) *What a direct integration renders: the 3D viewer and the built-in configuration panel, on your own page.* ## When to Use This - You own the page and can add `
``` **2. Initialize the viewer:** ```html ``` **3. Access the API:** ```javascript window.addEventListener('ijewel-viewer-ready', async (e) => { const viewer = e.detail.viewer; const api = viewer.getPluginByType('WeddingBandBuilder').controller; // Change ring properties api.setWidthMultiplier(1.1); await api.setMaterialRef(1, { base: 'yellow', variant: '18k', finish: 'polished', }); // Listen for price changes api.events.on('price:updated', (data) => { document.getElementById('price').textContent = `$${data.pricing.totalUsd.toFixed(2)}`; }); }); ``` See the [documented complete example](./examples/direct-integration), or start from either maintained live template above. ## Headless Mode (Custom UI) Set `hideWbbUi: true` in the viewer options to hide the built-in panel and build your own controls: ```javascript { showCard: false, showConfigurator: false, hideWbbUi: true, } ``` The 3D viewer renders full width with no overlaid UI. You control everything through the API by populating dropdowns from catalog methods, wiring controls to setters, and listening for events. See [Custom UI (Headless)](./integration-headless) for a full guide on building custom controls. ## Theming Customize the built-in panel's appearance to match your brand: ```javascript api.setTheme('luxury-gold'); // Or with custom colors and fonts api.setTheme({ preset: 'modern-minimal', colors: { primary: '#2E5B3C', background: '#F5F7F5' }, fonts: { body: "'Cormorant Garamond', serif", googleFonts: ['Cormorant+Garamond:wght@400;500;600'], }, }); ``` The builder interface under the Default, Luxury Gold, Fresh Teal and iJewel theme presets Available presets: `default`, `luxury-gold`, `modern-minimal`, `dark`, `rose-elegant`, `coral-modern`, `fresh-teal`, `minimal-blue`, `warm-beige`, `classic-gold`, `ijewel`. See [Theming & Branding](./theming) for full customization options. ## Framework Examples | Framework | What You Get | Example | |-----------|-------------|---------| | **Vanilla JS** | Plain HTML/JS, no build step | [View example](./frameworks/vanilla) | | **React** | Component + hooks, headless variant | [View example](./frameworks/react) | | **Vue 3** | Composable + SFC, headless variant | [View example](./frameworks/vue) | | **Next.js** | Client component, App Router + Pages Router | [View example](./frameworks/nextjs) | | **Angular** | Service + Component, RxJS observables | [View example](./frameworks/angular) | | **Svelte** | Component with slots, headless variant | [View example](./frameworks/svelte) | ## Error Handling ```javascript api.events.on('error', (err) => { console.error(`[${err.source}] ${err.message}`); }); ``` ## Multiple Viewers You can have multiple viewers on one page. Each gets its own API instance: ```javascript const viewer1 = new ijewelViewer.Viewer(root1, project1, options); const viewer2 = new ijewelViewer.Viewer(root2, project2, options); ```
Configuration Reference ### Project Options | Property | Type | Description | |----------|------|-------------| | `name` | `string` | Display name shown in the loading screen | | `version` | `string` | Project version (use `'v5'`) | | `basePath` | `string` | Base URL for resolving asset paths in the manifest | | `plugins.WeddingBandBuilder.manifestUrl` | `string` | URL to the manifest JSON file (relative to `basePath`) | ### Viewer Options | Property | Type | Default | Description | |----------|------|---------|-------------| | `showCard` | `boolean` | `false` | Show the product info card | | `showSwitchNode` | `boolean` | `false` | Show the model switcher | | `showUiButtons` | `boolean` | `true` | Show viewer control buttons (quality, reset view, etc.) | | `showConfigurator` | `boolean` | `false` | Show the generic configurator panel (not needed since WBB has its own) | | `showZoomButtons` | `boolean` | `true` | Show +/- zoom controls | | `enableZoom` | `boolean` | `true` | Allow scroll/pinch zoom | | `hideWbbUi` | `boolean` | `true` | Hide the built-in Wedding Band panel; set to `false` to show it |
Container Sizing & Mobile Layout ### Container Sizing The viewer fills its container. Make sure the container has explicit dimensions: ```css /* Full viewport */ #viewer-root { width: 100vw; height: 100vh; } /* Fixed size */ #viewer-root { width: 800px; height: 600px; } /* Responsive (4:3 aspect ratio) */ #viewer-root { width: 100%; height: 0; padding-bottom: 75%; position: relative; } ``` ::: danger The viewer fills its container. If the container has zero height, nothing renders. Always set height explicitly: ```html
``` This is the most common cause of a blank viewer. ::: ### Mobile Responsiveness The built-in panel automatically switches to a stacked layout on screens narrower than 768px. The 3D viewer sits on top and the configuration panel goes below, each taking 50% of the viewport height. Tab labels collapse to icons only. The builder on a laptop with the viewer left and panel right, beside a phone with the viewer on top and the panel below
## URL Parameters The viewer page accepts these query parameters: | Parameter | Default | Description | |-----------|---------|-------------| | `manifest` | `wedding-band-project.json` | URL to the manifest JSON file | | `basePath` | (viewer page directory) | Base URL for resolving asset paths | | `ui` | `true` | Set to `false` for [headless mode](./integration-headless) | ## Next Steps - [Custom UI (Headless)](./integration-headless) to build a fully custom UI - [Theming & Branding](./theming) to customize the look and feel - [API Reference](./api-reference) for complete method documentation - [Pricing Engine](./pricing) to configure the pricing engine --- # iframe Embedding [View the tested iframe host demo](https://ijewel3d.github.io/iJewelTemplates/wedding-band/iframe-demo/index.html) or [browse its source](https://github.com/ijewel3d/iJewelTemplates/tree/main/wedding-band/iframe-demo). The published source includes the host HTML, styles, and `postMessage` controller. Copy the complete `iframe-demo` folder so its relative asset URLs continue to resolve. Embed the Wedding Band Builder in an ` ``` The hosted route is: ```text https://ijewel3d.com//files//embedded ``` Supported display parameters are case-sensitive: | Parameter | Effect | | --- | --- | | `isAutoplay=true` | Start the viewer automatically | | `hideWbbUi=true` | Hide the built-in Wedding Band controls | | `showUiButtons=true` | Show the viewer action buttons | The mini-viewer version inside a hosted iframe is controlled by the deployed iJewel3D application. The parent page cannot pin that internal version. ::: warning Viewer `0.6.11` or newer required for host controls The cross-origin `ready` handshake and reliable teardown require Mini Viewer `0.6.11` or newer inside the hosted application. Material variants, the outside and inside material features, and the Modern Metals layout need `0.6.17` or newer. If the 3D rings render but the parent never receives `ready`, the embed deployment is older than the documented protocol. Upgrade the hosted application or use the self-hosted viewer page below, where you control the Viewer release. ::: ### Self-Hosted Viewer Page Create an HTML file that loads the mini-viewer inside the iframe. This page handles all the postMessage bridging automatically. **[View full viewer page source](./examples/iframe-viewer)** and host this file on your server or CDN. ::: tip The viewer page reads `?manifest=`, `?basePath=`, and `?ui=` from URL parameters, making it reusable across different product pages without code changes. ::: ### Embed the Self-Hosted Page ```html ``` The `camera` permission lets Try-On start the camera inside the iframe. ::: warning Without `camera` in the iframe's `allow` attribute, the Try-On button can appear but the camera request is blocked. Always include it: ```html ``` The page must also be served over HTTPS for camera access. ::: The iframe with the builder’s built-in panel visible ### Communicate via postMessage ```javascript const iframe = document.getElementById('wbb-iframe'); const viewerOrigin = new URL(iframe.src).origin; let requestId = 0; // Send a command function send(method, args = []) { iframe.contentWindow.postMessage({ id: `req-${++requestId}`, method, args, }, viewerOrigin); } // Listen for events window.addEventListener('message', (e) => { if (e.source !== iframe.contentWindow) return; if (e.origin !== viewerOrigin) return; if (e.data?.event === 'ready') { send('setProfile', [0]); send('setMaterialRef', [1, { base: 'yellow', variant: '18k', finish: 'polished', }]); } if (e.data?.event === 'price:updated') { document.getElementById('price').textContent = `$${e.data.data.pricing.totalUsd.toFixed(2)}`; } }); ``` The bridge also exposes the outside-feature methods. For example, send `setOutsideFeatures` with one feature object and the optional band name: ```javascript send('setOutsideFeatures', [{ inlays: [{ centerZ: 0, widthMm: 1, metal: 'yellow', variant: '18k', finish: 'polished', }], overlays: [], }]); ``` It forwards `inlays:changed`, `overlays:changed`, and `sleeve:changed` events to the parent with the same `{ event, data }` envelope. ### Ready lifecycle The Wedding Band plugin installs its global and postMessage exposure before it emits `{ event: 'ready', data: {} }`. It emits `ready` exactly once for each successful project initialization. Wait for that event before sending commands or queries. Importing another project or reloading the iframe starts a new lifecycle and produces a new `ready` event. Disposing or resetting the plugin removes its message listener and event forwarding, so an old controller cannot reply after teardown. **[View complete host page example](./examples/iframe-host)** for a full page with profile/material buttons and live price display. ## Headless Mode For a self-hosted viewer page, load the iframe with `?ui=false` to hide the built-in panel and build all controls on the host page: ```html ``` For the hosted iJewel3D route, use `hideWbbUi=true`: ```html ``` Use `postMessage` to query the catalog and control everything from your page. See [Custom UI (Headless)](./integration-headless) for a full guide on building custom controls. Built-in panel inside the iframe versus headless mode with host page controls ## postMessage Protocol **Sending commands** (all [API methods](./api-reference) are available): ```javascript // Command: { id: 'req-1', method: 'setWidth', args: [5.0] } // Success: { id: 'req-1', result: null } // Error: { id: 'req-1', error: { message: '...', source: 'api' } } ``` **Receiving events** (forwarded automatically from the viewer): ```javascript // { event: 'price:updated', data: { bandName: 'her', pricing: { totalUsd: 1250.00, ... } } } ```
Promise-based query helper ```javascript function query(method, args = []) { return new Promise((resolve, reject) => { const id = `req-${++requestId}`; const timeout = setTimeout(() => { cleanup(); reject(new Error(`Timed out waiting for ${method}`)); }, 8000); const cleanup = () => { clearTimeout(timeout); window.removeEventListener('message', handler); }; const handler = (e) => { if (e.source !== iframe.contentWindow) return; if (e.origin !== viewerOrigin) return; if (e.data?.id !== id) return; cleanup(); if (e.data.error) reject(new Error(e.data.error.message)); else resolve(e.data.result); }; window.addEventListener('message', handler); iframe.contentWindow.postMessage({ id, method, args }, viewerOrigin); }); } // Usage const price = await query('getPrice', ['her']); const snapshot = await query('getSnapshot'); ```
## E-Commerce Platform Examples Ready-to-use integration examples for popular platforms. Each includes the iframe embed, live price display, and Add to Cart wiring. | Platform | What You Get | Example | |----------|-------------|---------| | **Shopify** | Liquid section + cart integration | [View example](./ecommerce/shopify) | | **WooCommerce** | Shortcode + AJAX cart handler | [View example](./ecommerce/woocommerce) | | **Magento** | PHTML block + layout XML + controller | [View example](./ecommerce/magento) | | **BigCommerce** | Stencil template + Storefront API | [View example](./ecommerce/bigcommerce) | | **Wix** | HTML embed + Velo code | [View example](./ecommerce/wix) | Live price and Add to Cart below the embedded viewer
Security: Restrict Origins In production, always use the exact target origin and validate both the source window and origin of every incoming message: ```javascript const viewerOrigin = new URL(iframe.src).origin; iframe.contentWindow.postMessage({ id, method, args }, viewerOrigin); window.addEventListener('message', (event) => { if (event.source !== iframe.contentWindow) return; if (event.origin !== viewerOrigin) return; // Handle the validated message. }); ```
Responsive Sizing ```css .viewer-container { position: relative; width: 100%; padding-bottom: 75%; /* 4:3 aspect ratio */ } .viewer-container iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; } ```
AR Support Add `camera` to the iframe's `allow` attribute. Try-On uses the camera and live hand tracking; it does not require WebXR. Without camera permission, the button can appear but the camera cannot start.
Same-Origin Shortcut If the iframe and host page are on the same origin, you can skip postMessage entirely: ```javascript const iframe = document.getElementById('wbb-iframe'); const viewer = iframe.contentWindow.ijewelViewer; const api = viewer.getPluginByType('WeddingBandBuilder').controller; api.setWidthMultiplier(1.1); ```
URL Parameters The self-hosted viewer page accepts these query parameters: | Parameter | Default | Description | |-----------|---------|-------------| | `manifest` | `wedding-band-project.json` | URL to the manifest JSON file | | `basePath` | (viewer page directory) | Base URL for resolving asset paths | | `ui` | `true` | Set to `false` to hide the built-in panel (headless mode) | ```html ```
Hosted Embed URL Parameters The iJewel3D hosted route uses `isAutoplay`, `hideWbbUi`, and `showUiButtons`. Parameter names are case-sensitive; for example, `isAutoPlay` is not equivalent to `isAutoplay`. ```html ```
## Next Steps - [Custom UI (Headless)](./integration-headless) to build your own controls - [API Reference](./api-reference) for complete method documentation - [Pricing Engine](./pricing) to configure the pricing engine --- # Custom UI (Headless) [View the tested Custom UI template](https://ijewel3d.github.io/iJewelTemplates/wedding-band/custom-ui/index.html) or [browse its source](https://github.com/ijewel3d/iJewelTemplates/tree/main/wedding-band/custom-ui). The source is a multi-file template. The Drive-backed page uses `script-drive.js`; the self-hosted page uses `script-self-hosted.js` and `wedding_band_project.json`. Copy the matching HTML, script, stylesheet, and project JSON instead of mixing files from the two variants. Build your own fully custom interface for the Wedding Band Builder. Hide the built-in panel, use the API's catalog methods to populate your controls, and wire them to the write methods. Your team or agency owns the UI entirely. No dependency on a third party for branding changes, layout updates, or feature additions. Wedding Band Builder with a completely custom-designed interface ## Overview Set `hideWbbUi: true` in Mini Viewer's options to run in **headless mode**. The 3D viewer renders with no built-in panel. This works with both integration approaches: | Integration | How to Enable | How to Access API | |-------------|--------------|-------------------| | [Script Tag](./integration-direct) | `hideWbbUi: true` in viewer options | `viewer.getPluginByType('WeddingBandBuilder').controller` | | [iframe](./integration-iframe) | `?ui=false` URL parameter | `postMessage` from the host page | This page covers the Script Tag approach. For iframe-based custom UI, the same concepts apply but you wrap each API call in `postMessage`. See [iframe headless mode](./integration-iframe#headless-mode). ## Getting Started ```javascript let api; let wbbPlugin; // Initialize in headless mode new ijewelViewer.Viewer(document.getElementById('viewer'), { name: 'Wedding Band Builder', version: 'v5', basePath: 'https://your-cdn.com/wbb-assets/', plugins: { WeddingBandBuilder: { manifestUrl: 'wedding-band-project.json', }, }, }, { showCard: false, showSwitchNode: false, showUiButtons: false, showConfigurator: false, showZoomButtons: false, enableZoom: true, hideWbbUi: true, }); // Wait for API, then build your UI window.addEventListener('ijewel-viewer-ready', (e) => { wbbPlugin = e.detail.viewer.getPluginByType('WeddingBandBuilder'); api = wbbPlugin.controller; // Read the catalog to see what's available in your manifest const profiles = api.getAvailableProfiles(); const materials = api.getAvailableMaterials('band'); // Wire your controls to the API buildProfileSelector(profiles); buildMaterialSwatches(api, materials); buildWidthSlider(); buildPriceDisplay(); }); ``` The 3D viewer rendering full width with no UI overlays ## Building Controls Each control follows the same pattern: read options from the catalog, create your UI, and call an API setter on interaction.
Profile Selector ```javascript function buildProfileSelector(profiles) { const container = document.getElementById('profile-selector'); profiles.forEach((profile) => { const btn = document.createElement('button'); btn.textContent = profile.name; // Use thumbnail from manifest if available if (profile.thumbnail) { btn.style.backgroundImage = `url(${profile.thumbnail})`; } btn.addEventListener('click', async () => { await api.setProfile(profile.index); container.querySelectorAll('button').forEach(b => b.classList.remove('active')); btn.classList.add('active'); }); container.appendChild(btn); }); } ``` Profile buttons with ring cross section silhouettes
Material Swatches ```javascript function buildMaterialSwatches(api, materials) { const container = document.getElementById('metal-selector'); materials.forEach((material) => { const swatch = document.createElement('button'); swatch.className = 'swatch'; swatch.title = material.name; if (material.iconUrl) { swatch.style.backgroundImage = `url(${material.iconUrl})`; swatch.style.backgroundSize = 'cover'; } else if (material.swatch) { swatch.style.backgroundColor = material.swatch; } swatch.addEventListener('click', async () => { const variants = api.getAvailableVariants(material.id); const variant = variants.find(v => v.id === material.defaultVariant) || variants[0]; const finishes = api.getAvailableFinishesFor(material.id) .filter(f => !variant?.files || variant.files[f.id]); const finish = finishes.find(f => f.id === material.defaultFinish) || finishes[0]; await api.setMaterialRef(1, { base: material.id, variant: variant?.id, finish: finish?.id, }); }); container.appendChild(swatch); }); } ``` Circular metal swatches with the selected one highlighted
Outside Features and Inside Sleeve Read each feature picker with its usage role. Push a complete group with one `setOutsideFeatures()` call when several controls change together. ```javascript const inlayMaterial = api.getAvailableMaterials('inlay')[0]; const sleeveMaterial = api.getAvailableMaterials('sleeve')[0]; if (api.areOutsideFeaturesAvailable() && inlayMaterial) { await api.setOutsideFeatures({ inlays: [{ centerZ: 0, widthMm: 1, metal: inlayMaterial.id, variant: inlayMaterial.defaultVariant, }], overlays: [], sleeve: sleeveMaterial ? { enabled: true, metal: sleeveMaterial.id, variant: sleeveMaterial.defaultVariant, full: true, } : null, }); const bounds = api.getInlayBounds(0); const inlayPosition = document.getElementById('inlay-position'); inlayPosition.min = bounds.centerMin; inlayPosition.max = bounds.centerMax; } ``` Re-read bounds after width or feature changes. Inlay indices can change because the controller sorts them by center position.
Dimension Sliders ```javascript function buildDimensionSliders() { const widthSlider = document.getElementById('width-slider'); const widthLabel = document.getElementById('width-value'); const widthLimits = api.getLimits().width; widthSlider.min = widthLimits.min; widthSlider.max = widthLimits.max; widthSlider.step = widthLimits.step || 0.05; const dims = api.getDimensions(); widthSlider.value = dims.widthMm; widthLabel.textContent = `×${dims.widthMm.toFixed(2)}`; widthSlider.addEventListener('input', (e) => { const multiplier = parseFloat(e.target.value); api.setWidthMultiplier(multiplier); widthLabel.textContent = `×${multiplier.toFixed(2)}`; }); } ``` ```html ×1.00 ```
Diamond Controls ```javascript function buildDiamondControls() { const container = document.getElementById('diamond-controls'); const types = api.getAvailableSettingTypes(); // "None" option const noneBtn = document.createElement('button'); noneBtn.textContent = 'No Diamonds'; noneBtn.addEventListener('click', () => api.setDiamonds(null)); container.appendChild(noneBtn); types.filter(type => type.id !== 'none').forEach((type) => { const btn = document.createElement('button'); btn.textContent = type.name; btn.addEventListener('click', () => api.setDiamonds({ settingType: type.id })); container.appendChild(btn); }); } ```
Ring Size ```javascript function buildRingSizeControl() { const slider = document.getElementById('ring-size'); const label = document.getElementById('ring-size-value'); // Ring size: inner diameter in mm, snapping to standard half-sizes slider.min = 14.04; // US 3 slider.max = 22.32; // US 13 slider.step = 0.4; // ~half-size increments slider.addEventListener('input', (e) => { const diamMm = parseFloat(e.target.value); api.setRingSize(diamMm / 2); // API takes radius label.textContent = `${diamMm.toFixed(1)} mm`; }); } ```
Live Price Display ```javascript function buildPriceDisplay() { const el = document.getElementById('price'); api.events.on('price:updated', (data) => { const p = data.pricing; let text = `$${p.totalUsd.toFixed(2)}`; if (p.diamonds) { text += ` (${p.diamonds.count} diamonds, ${p.diamonds.totalCarats.toFixed(2)}ct)`; } el.textContent = text; }); // Show initial price const price = api.getPrice(); if (price) el.textContent = `$${price.totalUsd.toFixed(2)}`; } ```
## Staying in Sync Listen for events to keep your UI in sync when the ring state changes: ```javascript api.events.on('band:switched', (data) => { const snapshot = api.getSnapshot(data.to); updateProfileHighlight(snapshot.profile.index); updateMetalHighlight(snapshot.materials.slots[0].metal); updateWidthSlider(snapshot.dimensions.widthMm); }); api.events.on('build:started', () => showSpinner()); api.events.on('build:complete', () => hideSpinner()); ``` ::: tip When the user switches bands (`her` / `his`), all your controls should update to reflect the new band's state. Call `getSnapshot()` to get the full configuration. ::: ## Batch Updates & Presets Use `batch()` to apply multiple changes in one geometry rebuild: ```javascript await api.batch({ profile: { name: 'D-Shape' }, dimensions: { widthMm: 1.0, heightMm: 1.0 }, materials: { partition: 1, slots: [{ slot: 1, metal: 'Yellow', finish: 'Polished' }], }, diamonds: null, edge: { type: 'None' }, }); ``` ![Styled preset cards: Classic Gold, Diamond Elegance, Two-Tone Modern](../assets/images/wbb-preset-cards.webp) ## Save & Restore Configurations ```javascript // Save the complete plugin state, including variants and outside features const config = api.toJSON(); localStorage.setItem('wbb-config', JSON.stringify(config)); // Restore through the plugin const saved = localStorage.getItem('wbb-config'); if (saved) await wbbPlugin.fromJSON(JSON.parse(saved)); // Send to backend for order processing const herConfig = api.getSnapshot('her'); const herPrice = api.getPrice('her'); await fetch('/api/cart/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ state: config, summary: herConfig, price: herPrice }), }); ``` ## Complete Example A full working page with profile buttons, material swatches, width slider, diamond options, band toggle, and live price: **[View complete custom UI example](./examples/custom-ui)** The custom UI on a mobile device: viewer on top, controls and price bar below
Design Tips **Keep it simple.** You don't need to expose every API option. Start with profile, metal, and width. **Use thumbnails.** Catalog methods return `thumbnail` URLs when available. Use them for visual selectors. **Show loading state.** Profile changes require geometry loading. Listen for `build:started` / `build:complete`. **Debounce sliders.** For continuous sliders, debounce to avoid excessive rebuilds: ::: tip Debounce slider inputs. The `input` event fires on every pixel of drag, which can trigger 60+ geometry rebuilds per second. A 50ms debounce keeps the UI responsive: ```javascript let timer; slider.addEventListener('input', (e) => { clearTimeout(timer); timer = setTimeout(() => api.setWidthMultiplier(parseFloat(e.target.value)), 50); }); ``` ::: **Test on mobile.** Make sure your custom controls work on touch devices. The 3D viewer handles touch/pinch natively.
## Next Steps - [API Reference](./api-reference) for complete method and event documentation - [Pricing Engine](./pricing) to configure the pricing engine - [Theming & Branding](./theming) if you want to customize the built-in panel instead - [Script Tag (Direct)](./integration-direct) for built-in panel integration - [iframe Embedding](./integration-iframe) for CMS and e-commerce platforms --- # Shopify Integration: Complete Example Add the Wedding Band Builder to a Shopify store using a custom Liquid section. [Back to iframe Embedding guide](../integration-iframe) ```html
``` --- # WooCommerce Integration: Complete Example Embed the Wedding Band Builder on a WooCommerce (WordPress) product page using a shortcode and custom template. [Back to iframe Embedding guide](../integration-iframe) ## Option 1: Shortcode (Simplest) Add this to your theme's `functions.php`: ```php // functions.php function wbb_shortcode($atts) { $atts = shortcode_atts(array( 'height' => '70vh', 'src' => 'https://your-cdn.com/wbb-viewer.html', ), $atts); ob_start(); ?>
Loading...
admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('wbb_nonce'), 'cart_url' => wc_get_cart_url(), )); } add_action('wp_enqueue_scripts', 'wbb_enqueue_scripts'); ``` Then use the shortcode on any page or product: ``` [wedding_band_builder height="70vh" src="https://your-cdn.com/wbb-viewer.html"] ``` ## Option 2: Custom Product Template Create a WooCommerce product template for the configurator: ```php

Loading... is_in_stock()) : ?>
``` ## AJAX Handler for Add to Cart ```php // functions.php add_action('wp_ajax_wbb_add_to_cart', 'wbb_handle_add_to_cart'); add_action('wp_ajax_nopriv_wbb_add_to_cart', 'wbb_handle_add_to_cart'); function wbb_handle_add_to_cart() { check_ajax_referer('wbb_nonce', 'nonce'); $config = sanitize_text_field($_POST['config']); $product_id = intval($_POST['product_id'] ?? 0); // Add to cart with ring configuration as meta data $cart_item_data = array( 'wbb_config' => $config, ); $cart_item_key = WC()->cart->add_to_cart($product_id, 1, 0, array(), $cart_item_data); if ($cart_item_key) { wp_send_json_success(array('cart_item_key' => $cart_item_key)); } else { wp_send_json_error(array('message' => 'Could not add to cart')); } } ``` --- # Magento (Adobe Commerce) Integration: Complete Example Embed the Wedding Band Builder on a Magento product page using a custom block and PHTML template. [Back to iframe Embedding guide](../integration-iframe) ## Custom Block Template Create a PHTML template for the configurator: ```php getProduct() ? $block->getProduct()->getId() : ''; $addToCartUrl = $block->getUrl('wedding-band/cart/add'); ?>
Loading...
``` ## Layout XML Add the block to your product page layout: ```xml ``` ## Controller for Add to Cart ```php jsonFactory->create(); $productId = (int) $this->request->getParam('product_id'); $wbbConfig = $this->request->getParam('wbb_config'); try { $product = $this->productRepository->getById($productId); $params = new \Magento\Framework\DataObject([ 'qty' => 1, 'wbb_config' => $wbbConfig, ]); $this->cart->addProduct($product, $params); $this->cart->save(); return $result->setData(['success' => true]); } catch (\Exception $e) { return $result->setData([ 'success' => false, 'message' => $e->getMessage(), ]); } } } ``` --- # BigCommerce Integration: Complete Example Embed the Wedding Band Builder on a BigCommerce storefront using a custom product template. [Back to iframe Embedding guide](../integration-iframe) ## Custom Product Template In BigCommerce's Stencil theme, create or edit a product template: ```html {{#partial "page"}}

{{product.title}}

Loading...
{{/partial}} {{> layout/base}} ``` ## Assigning the Template 1. In BigCommerce admin, go to **Products** and edit (or create) your wedding band product 2. Under **Template**, select `wedding-band` from the custom template dropdown 3. Save the product The configurator will now appear on that product page instead of the default product layout. --- # Wix Integration: Complete Example Embed the Wedding Band Builder on a Wix site using Wix's HTML embed (iframe) component. [Back to iframe Embedding guide](../integration-iframe) ## Using the HTML Embed Component 1. In the Wix Editor, click **Add Elements** (+) → **Embed & Social** → **HTML iframe** 2. Drag it onto your page and resize it (recommended: full width, 600–700px height) 3. Click **Enter Code** and paste: ```html ``` 4. Click **Update** and publish ## Adding Price Display with Velo (Wix Code) To show the price on the Wix page and wire up an Add to Cart button, use Wix Velo: ```javascript // Page code (Velo) import wixStores from 'wix-stores'; $w.onReady(function () { // Listen for price updates from the HTML embed $w('#html1').onMessage((event) => { if (event.data.type === 'wbb-price') { $w('#priceText').text = '$' + event.data.price.toFixed(2); } }); // Add to cart button $w('#addToCartButton').onClick(async () => { // Send a query to the iframe to get the config $w('#html1').postMessage({ action: 'getConfig' }); }); // Receive config back from iframe $w('#html1').onMessage(async (event) => { if (event.data.type === 'wbb-config') { // Add to Wix Stores cart const productId = 'your-product-id'; // Replace with actual product ID await wixStores.cart.addProducts([{ productId: productId, quantity: 1, options: { choices: {}, customTextFields: [{ title: 'Ring Configuration', value: JSON.stringify(event.data.config), }], }, }]); } }); }); ``` Update the HTML embed to handle config requests: ```html ``` ## Notes - Wix HTML embeds run in their own iframe, so there are **two iframe layers**: Wix embed → your viewer page. The postMessage bridge handles this transparently. - For Wix eCommerce (Wix Stores), ring configuration is stored as a custom text field on the cart item. - Wix must delegate `camera` permission through both iframe layers. If its HTML embed does not do so, Try-On may be unavailable on the Wix-hosted page. ::: warning Wix HTML embeds run inside their own iframe, creating a double iframe layer (Wix embed → your viewer page). If postMessage communication isn't working, check the browser DevTools console for cross origin errors. AR try on is also likely unavailable inside Wix embeds due to permission restrictions on nested iframes. ::: --- # Self-Hosted Integration A self-hosted integration loads a Wedding Band project that you create and serve from your own site or CDN. It does not need a published iJewel Drive file at runtime. [Open the working self-hosted example](https://ijewel3d.github.io/iJewelTemplates/wedding-band/custom-ui/self-hosted.html) or [inspect its source](https://github.com/ijewel3d/iJewelTemplates/tree/main/wedding-band/custom-ui). Use the example to compare behavior; build your own project JSON with the steps below instead of copying its catalog. ## What You Will Host A typical deployment contains: ```text wedding-band/ ├── index.html ├── app.js ├── wedding-band-project.json ├── scenes/ │ └── wedding-band.vjson └── assets/ ├── profiles/ ├── materials/ ├── diamonds/ └── icons/ ``` The two configuration files have different jobs: | File | Purpose | | --- | --- | | `wedding-band-project.json` | Catalog, default rings, asset locations, and a reference to the scene file | | `wedding-band.vjson` | Environment, lighting, ground, post-processing, and optionally the camera exported from Playground | ::: info Self-hosted does not have to mean one server The page, project JSON, scene VJSON, and assets can use different hosts. Use absolute HTTPS URLs and allow cross-origin requests when files are served from a different origin. ::: ## 1. Create the Project Shell Create `wedding-band-project.json` and begin with the top-level project and an inline `WeddingBandBuilder` plugin: ```json { "name": "My Wedding Band Builder", "version": "v1", "basePath": "", "tryonConfig": { "enabled": false, "modelScaleFactor": 1, "modelPosition": { "x": 0, "y": 0, "z": 0, "isVector3": true }, "modelRotation": { "x": 0, "y": 0, "z": 0, "isVector3": true } }, "plugins": { "WeddingBandBuilder": { "type": "WeddingBandBuilder", "version": 2, "assetBaseUrl": "https://cdn.example.com/wedding-band/assets/", "profiles": [], "materials": [], "finishes": [], "diamonds": {}, "separationPresets": {}, "ui": { "layout": "boutique" }, "defaults": { "rootScale": 0.1, "autoFit": false, "bands": [] } } } } ``` This is a structure to fill in, not yet a loadable project. Keep Try-On disabled until you replace the placeholder transform with the fit generated for your band and preview it successfully. The required catalogs and opening band are added in the next steps. Omit `tryonConfig` entirely if the project will not offer Try-On. `ui.layout` chooses the built-in layout. UI visibility remains outside the project JSON: the same project can power either the built-in controls or a [Custom UI](./integration-headless). Choose visibility with Mini Viewer's `hideWbbUi` option when you create the viewer in step 6. ::: warning Two unrelated version fields Keep the top-level viewer project field as `"version": "v1"`. The Wedding Band plugin carries its own numeric field, `plugins.WeddingBandBuilder.version: 2`. The two describe different formats, so never copy one value into the other. ::: ### How asset URLs are resolved `assetBaseUrl` is the prefix for relative paths inside the Wedding Band plugin: ```json "assetBaseUrl": "https://cdn.example.com/wedding-band/assets/" ``` - `profiles/d-shape.3dm` becomes `https://cdn.example.com/wedding-band/assets/profiles/d-shape.3dm`. - An absolute `https://...` URL is used unchanged. - Include the trailing `/` in `assetBaseUrl`. This lets you keep the manifest readable while still overriding an individual asset with an absolute URL when necessary. ## 2. Form the Asset Catalogs Build each catalog from the options you actually want to offer. IDs are stable values used by configuration and code; names are customer-facing labels. ### Profiles Add one object to `profiles` for every band cross-section: ```json "profiles": [ { "id": "d-shape", "name": "D-Shape", "file": "profiles/d-shape.3dm", "iconUrl": "icons/profile-d-shape.svg", "engravingVOffset": { "oneColor": 0.25, "multiColor": 0.78 } }, { "id": "flat", "name": "Flat", "file": "profiles/flat.3dm", "iconUrl": "icons/profile-flat.svg", "engravingVOffset": { "oneColor": 0.72, "multiColor": 0.69 } } ] ``` `profileIndex` in a band's default state is the zero-based position in this array. If you reorder `profiles`, update every `profileIndex` that refers to it. ### Materials, qualities, and finishes The material catalog lists the combinations that actually exist. A base material owns its variants/qualities, and each variant maps finish IDs to PMAT URLs: ```json "finishes": [ { "id": "polished", "name": "Polished", "iconUrl": "icons/finish-polished.png" }, { "id": "brush", "name": "Brush", "iconUrl": "icons/finish-brush.png" } ], "materials": [ { "id": "yellow", "name": "Yellow Gold", "kind": "metal", "usage": ["band", "inlay", "overlay", "sleeve"], "iconUrl": "icons/metal-yellow.png", "variants": [ { "id": "14k", "name": "14k", "files": { "polished": "materials/yellow/14k/polished.pmat", "brush": "materials/yellow/14k/brush.pmat" } }, { "id": "18k", "name": "18k", "files": { "polished": "materials/yellow/18k/polished.pmat", "brush": "materials/yellow/18k/brush.pmat" } } ], "defaultVariant": "18k", "finishes": ["polished", "brush"], "defaultFinish": "polished" }, { "id": "wood", "name": "Wood", "kind": "organic", "usage": ["inlay", "overlay"], "variants": [ { "id": "koa", "name": "Koa", "file": "materials/wood/koa/default.pmat" } ], "defaultVariant": "koa", "finishes": [], "defaultFinish": null } ] ``` `usage` controls where the material can appear. Omit it only when the material is valid for every role. `files` is the selectable finish map. Use singular `file` for a variant such as wood that has no finish axis. The older `metals` plus `finishes[].files` format is still normalized by the viewer for compatibility. Write new manifests with `materials` and `plugins.WeddingBandBuilder.version: 2`. ### Diamond models The builder reuses these two models when it places stones and prongs: ```json "diamonds": { "singleModelFile": "diamonds/diamond-single.glb", "prongsModelFile": "diamonds/diamond-prongs.glb" } ``` Keep this block in the manifest even when the opening design has no diamonds. ## 3. Define Color Separation `separationPresets` describes how the generated band is divided into material regions. Start with a one-color preset, then add two- and three-color presets if your catalog needs them: ```json "separationPresets": { "1 Color": { "divisions": [1, 1], "horizontalSep": false, "useGrooveEdges": false, "regions": [ { "slotIndex": 1, "usePolished": false, "respectInsidePolished": false }, { "slotIndex": 1, "usePolished": false, "respectInsidePolished": false }, { "slotIndex": 1, "usePolished": true, "respectInsidePolished": true }, { "slotIndex": 1, "usePolished": true, "respectInsidePolished": true } ] } } ``` The object key (`"1 Color"`) is also the value used by `defaults.bands[].state.partition` and `setPartitionByName()`. `slotIndex` is one-based and chooses the customer's material slot for that region. ## 4. Define the Opening Band Add at least one band to `defaults.bands`. Form its state using IDs already declared in the catalogs: ```json "defaults": { "rootScale": 0.1, "autoFit": false, "bands": [ { "name": "main", "displayName": "Wedding Band", "defaultWidthMm": 4, "defaultHeightMm": 1.8, "position": [0, 0, 0], "rotation": [0, 0, 0], "state": { "profileIndex": 0, "profileWidth": 1, "profileHeight": 1, "ringSize": 8.26, "partition": "1 Color", "activeMetalTab": 0, "metals": ["yellow", "yellow", "yellow"], "variants": ["18k", "18k", "18k"], "surfaces": ["polished", "polished", "polished"], "diamond": "none", "diamondPlacement": 0.5, "stoneSize": 1.5, "engravingText": "", "engravingFont": "Sacramento", "engravingFontSize": 80, "edgeType": "None", "edgeSide": "Both", "settingType": "none", "diamondSpan": "Full Ring", "diamondSpacing": "Stone to Stone", "diamondCount": 0, "insidePolished": true, "splitGroove": false, "wavyGrooves": false, "wavySplit": false, "wavyFrequency": 6, "wavyAmplitude": 0.3 } } ] } ``` The important references are: | State field | Must refer to | | --- | --- | | `profileIndex` | Position of an entry in `profiles` | | `partition` | A key in `separationPresets` | | `metals` | Base IDs from `materials` whose `usage` includes `band` | | `variants` | Variant IDs belonging to the corresponding base material | | `surfaces` | Finish IDs available in the corresponding variant's `files` map | | `inlays[].metal` | Base IDs whose `usage` includes `inlay` | | `overlays[].metal` | Base IDs whose `usage` includes `overlay` | | `sleeve.metal` | A base ID whose `usage` includes `sleeve` | `name` is the `bandName` passed to API methods. Add another object to `bands` for a matching pair, giving it a unique `name`, state, position, and rotation. ### Optional outside and inside features Add these fields inside a band's `state` when the opening design needs inlays, rim overlays, or an inside sleeve: ```json { "inlays": [ { "centerZ": 0, "widthMm": 1.2, "metal": "wood", "variant": "koa" } ], "overlays": [ { "side": "left", "widthMm": 0.8, "metal": "rose", "variant": "18k", "finish": "polished", "rimCoverage": 0.5 } ], "sleeve": { "enabled": true, "metal": "yellow", "variant": "18k", "finish": "polished", "full": false, "widthMm": 3 } } ``` An inlay is a free-positioned stripe on the outer surface. An overlay starts at the named rim and runs inward. `rimCoverage` ranges from `0` to `1` and controls the overlay on the flat rim face. A partial sleeve is centered across the bore. The viewer clamps overlapping or overflowing feature dimensions. These features render only with a circular path and a vertical-style material division. They remain material regions, so they do not change ring weight. `autoFit: false` prevents the builder from replacing the opening camera. This is important when the camera comes from your Playground scene or from a top-level `cameraConfig`. ## 5. Get Scene Settings from Playground Create the visual environment in [iJewel Playground](../playground/what-is-playground): 1. Load a representative wedding band model so lighting decisions are made against the right material and scale. 2. Use **Scene** in the right panel to set the environment, background, ground, shadows, and lights. See [Scene Settings](../playground/scene-settings). 3. Configure the required post-processing and camera view. 4. Open **Export** in the left panel. 5. Under **Scene Settings**, click **Download VJSON**. The downloaded `.vjson` contains the complete scene look. Playground also has an advanced export in **right panel → Export → Asset Export → Preset Config Export** when you need to choose which plugins are included. See [Export Scene Settings](../playground/export-scene-settings) for both flows. Upload the downloaded file to your site or CDN, for example: ```text https://cdn.example.com/wedding-band/scenes/wedding-band.vjson ``` ### Add the Playground scene to the project JSON Add `sceneConfig` as a top-level sibling of `plugins`. Reference the hosted `.vjson`; do not paste the VJSON's contents into the Wedding Band plugin: ```json { "name": "My Wedding Band Builder", "version": "v1", "basePath": "", "plugins": { "WeddingBandBuilder": { "type": "WeddingBandBuilder" } }, "sceneConfig": { "type": "PresetLibraryPlugin", "VJSON": { "path": "https://cdn.example.com/wedding-band/scenes/wedding-band.vjson", "name": "wedding-band.vjson", "isCustom": true, "config": { "usePresetCamera": true, "usePresetLoadingPlugin": false, "usePresetInteractionPlugin": false, "usePresetParallaxMappingPlugin": false, "usePresetRendererUiPlugin": false, "usePresetCameraViewPlugin": false, "usePresetMaterialConfiguratorPlugin": false, "usePresetSwitchNodePlugin": false } } } } ``` The short `WeddingBandBuilder` block above only shows where `sceneConfig` goes; keep the catalogs and defaults you formed in the earlier steps. With `usePresetCamera: true`, the opening camera comes from the Playground VJSON. Keep `defaults.autoFit` set to `false` so the Wedding Band Builder does not reframe it. To manage the opening camera separately, set `usePresetCamera` to `false` and add a top-level `cameraConfig`: ```json "cameraConfig": { "position": { "x": -2.5, "y": 3.5, "z": 4.5, "isVector3": true }, "target": { "x": 0, "y": 0, "z": 0, "isVector3": true } } ``` ::: warning Scene file access The `.vjson` and every HDR, texture, or other URL referenced inside it must be publicly readable by the browser. Configure CORS on a different-origin CDN and avoid URLs that require dashboard cookies or authentication. ::: ## 6. Load the Project Serve the project over HTTP or HTTPS; `fetch()` will not reliably work from a `file://` URL. Add the verified viewer scripts and a container to your page: ```html
``` Load your JSON in `app.js` and pass the complete object to Mini Viewer. This example shows the built-in Wedding Band controls: ```javascript const useBuiltInWbbUi = true; async function start() { const response = await fetch('./wedding-band-project.json'); if (!response.ok) { throw new Error(`Project request failed: ${response.status}`); } const project = await response.json(); new ijewelViewer.Viewer( document.getElementById('viewer'), project, { showCard: false, showSwitchNode: false, showUiButtons: true, hideTryOn: false, showConfigurator: false, showZoomButtons: true, enableZoom: true, hideWbbUi: !useBuiltInWbbUi } ); } window.addEventListener('ijewel-viewer-ready', ({ detail }) => { const plugin = detail.viewer.getPluginByType('WeddingBandBuilder'); const api = plugin.controller; console.log(api.getAvailableProfiles()); }, { once: true }); start().catch(console.error); ``` `hideWbbUi` controls the Wedding Band configuration panel. It is independent from `showUiButtons`, which controls viewer actions such as fullscreen and camera buttons. `hideTryOn: false` keeps the Try-On action visible when the top-level `tryonConfig.enabled` value is `true`. Mini Viewer isolates the selected band while Try-On is active and restores the complete Wedding Band project when the session ends. A linked pair asks the customer which ring to use; an unlinked pair uses the active ring. Create the fit in iJewel3D Platform by selecting the Wedding Band project and choosing **Edit Default Settings**, then copy its top-level `tryonConfig` into the self-hosted project. If the project does not pass through the Platform, see [RingTryonPlugin setup mode](../tryon/ring-tryon-plugin#setup-mode). For a custom Try-On button, use [Configurator Try-On helpers](../viewer/viewer-class#configurator-try-on-helpers) to list the available bands, load `tryonConfig`, and prepare the selected band before `tryon.start()`. | Experience | `useBuiltInWbbUi` | Result | | --- | --- | --- | | Built-in controls | `true` | Mini Viewer renders the standard Wedding Band panel | | Custom/headless controls | `false` | Only the 3D viewer renders; your code builds the controls | For a headless integration, change `useBuiltInWbbUi` to `false`. Keep the `ijewel-viewer-ready` listener registered before `start()` so your code can read the controller and build its UI as soon as the viewer is ready. ## Validate Before Adding More Options Build and test in this order: 1. One profile, one metal, one finish, one separation preset, and one band. 2. The Playground `.vjson` and its referenced resources. 3. Additional profiles and finish/metal combinations. 4. The calibrated Try-On fit with `tryonConfig.enabled` set to `true`. 5. A second band, diamonds, icons, pricing, and custom UI controls. When the first ring does not render, inspect the browser Network panel. A project can be valid JSON while still containing a missing `.3dm`, `.pmat`, `.glb`, `.vjson`, HDR, or texture URL. Common checks: - Validate `wedding-band-project.json` with a JSON validator; JSON does not allow comments or trailing commas. - Confirm all URLs return `200` over HTTPS. - Confirm every finish contains a file for every offered metal. - Confirm `profileIndex`, `partition`, metal IDs, and finish IDs point to entries that exist. - Confirm `sceneConfig` is outside `plugins` and `VJSON.path` points to the exported Playground file. - If the Try-On button is missing, confirm that `tryonConfig.enabled` is `true`, `showUiButtons` is `true`, and `hideTryOn` is `false`. Continue with [Script Tag (Direct Integration)](./integration-direct) for same-page API usage or [Custom UI (Headless)](./integration-headless) to build your own controls. --- # Vanilla JavaScript: Complete Example A plain HTML/JS setup with no frameworks. This is the simplest way to integrate the Wedding Band Builder. [Back to Script Tag guide](../integration-direct) ## With Built-in UI ```html Wedding Band Builder
``` ## Headless with Custom Controls ```html Custom Wedding Band Configurator
Profile
Metal
Width x1.00
Diamonds
-
``` --- # React Integration: Complete Example A React component that loads the Wedding Band Builder with full API access. [Back to Script Tag guide](../integration-direct) ## Component ```jsx // WeddingBandBuilder.jsx import { useEffect, useRef, useState } from 'react'; // Load WebGI before the Mini Viewer nowebgi bundle const SCRIPT_URLS = [ 'https://releases.ijewel3d.com/libs/webgi-v0/bundle-0.22.0.js', 'https://releases.ijewel3d.com/libs/mini-viewer/0.6.18/bundle.nowebgi.iife.js', ]; let scriptLoaded = false; async function loadScript() { if (scriptLoaded) return Promise.resolve(); for (const src of SCRIPT_URLS) { await new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } scriptLoaded = true; } export default function WeddingBandBuilder({ manifestUrl = 'wedding-band-project.json', basePath = 'https://your-cdn.com/wbb-assets/', showUI = true, theme = null, onReady = null, onPriceChange = null, }) { const containerRef = useRef(null); const apiRef = useRef(null); const [price, setPrice] = useState(null); useEffect(() => { let disposed = false; async function init() { await loadScript(); if (disposed || !containerRef.current) return; const project = { name: 'Wedding Band Builder', version: 'v5', basePath, plugins: { WeddingBandBuilder: { manifestUrl }, }, }; new window.ijewelViewer.Viewer(containerRef.current, project, { showCard: false, showSwitchNode: false, showUiButtons: showUI, showConfigurator: false, showZoomButtons: showUI, enableZoom: true, hideWbbUi: !showUI, }); } function handleReady(e) { const viewer = e.detail.viewer; const api = viewer.getPluginByType('WeddingBandBuilder')?.controller; if (!api) return; apiRef.current = api; if (theme) api.setTheme(theme); api.events.on('price:updated', (data) => { if (data.pricing) { setPrice(data.pricing.totalUsd); onPriceChange?.(data.pricing); } }); onReady?.(api); } window.addEventListener('ijewel-viewer-ready', handleReady); init(); return () => { disposed = true; window.removeEventListener('ijewel-viewer-ready', handleReady); }; }, [manifestUrl, basePath, showUI]); return (
); } ``` ## Usage ```jsx // App.jsx import WeddingBandBuilder from './WeddingBandBuilder'; function App() { const handleReady = (api) => { console.log('WBB ready, available profiles:', api.getAvailableProfiles()); }; const handlePrice = (pricing) => { console.log(`Total: $${pricing.totalUsd.toFixed(2)}`); }; return (
); } ``` ## Headless with Custom Controls ```jsx import { useState, useCallback } from 'react'; import WeddingBandBuilder from './WeddingBandBuilder'; function CustomConfigurator() { const [api, setApi] = useState(null); const [price, setPrice] = useState(null); const [activeProfile, setActiveProfile] = useState(0); const handleReady = useCallback((wbbApi) => { setApi(wbbApi); }, []); const profiles = api?.getAvailableProfiles() || []; const materials = api?.getAvailableMaterials('band') || []; const selectMaterial = async (material) => { const variants = api.getAvailableVariants(material.id); const variant = variants.find(v => v.id === material.defaultVariant) || variants[0]; const finishes = api.getAvailableFinishesFor(material.id) .filter(f => !variant?.files || variant.files[f.id]); const finish = finishes.find(f => f.id === material.defaultFinish) || finishes[0]; await api.setMaterialRef(1, { base: material.id, variant: variant?.id, finish: finish?.id, }); }; return (
setPrice(p.totalUsd)} />
{profiles.map((p) => ( ))}
{materials.map((m) => ( ))}
{price && (
${price.toFixed(2)}
)}
); } ``` --- # Vue 3 Integration: Complete Example A Vue 3 composable and component for the Wedding Band Builder. [Back to Script Tag guide](../integration-direct) ## Composable ```javascript // useWeddingBandBuilder.js import { ref, onMounted, onUnmounted } from 'vue'; const SCRIPT_URLS = [ 'https://releases.ijewel3d.com/libs/webgi-v0/bundle-0.22.0.js', 'https://releases.ijewel3d.com/libs/mini-viewer/0.6.18/bundle.nowebgi.iife.js', ]; let scriptLoaded = false; async function loadScript() { if (scriptLoaded) return Promise.resolve(); for (const src of SCRIPT_URLS) { await new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } scriptLoaded = true; } export function useWeddingBandBuilder(containerRef, options = {}) { const api = ref(null); const price = ref(null); const ready = ref(false); const { manifestUrl = 'wedding-band-project.json', basePath = 'https://your-cdn.com/wbb-assets/', showUI = true, theme = null, } = options; function handleReady(e) { const viewer = e.detail.viewer; const controller = viewer.getPluginByType('WeddingBandBuilder')?.controller; if (!controller) return; api.value = controller; ready.value = true; if (theme) controller.setTheme(theme); controller.events.on('price:updated', (data) => { if (data.pricing) price.value = data.pricing; }); } onMounted(async () => { await loadScript(); if (!containerRef.value) return; window.addEventListener('ijewel-viewer-ready', handleReady); new window.ijewelViewer.Viewer(containerRef.value, { name: 'Wedding Band Builder', version: 'v5', basePath, plugins: { WeddingBandBuilder: { manifestUrl }, }, }, { showCard: false, showSwitchNode: false, showUiButtons: showUI, showConfigurator: false, showZoomButtons: showUI, enableZoom: true, hideWbbUi: !showUI, }); }); onUnmounted(() => { window.removeEventListener('ijewel-viewer-ready', handleReady); }); return { api, price, ready }; } ``` ## Component with Built-in UI ```vue ``` ## Usage ```vue ``` ## Headless with Custom Controls ```vue ``` --- # Next.js Integration: Complete Example A Next.js component for the Wedding Band Builder. Uses `next/dynamic` to avoid SSR issues since the viewer requires browser APIs. [Back to Script Tag guide](../integration-direct) ## Component (Client-Only) ```jsx // components/WeddingBandBuilder.jsx 'use client'; import { useEffect, useRef, useState } from 'react'; const SCRIPT_URLS = [ 'https://releases.ijewel3d.com/libs/webgi-v0/bundle-0.22.0.js', 'https://releases.ijewel3d.com/libs/mini-viewer/0.6.18/bundle.nowebgi.iife.js', ]; let scriptLoaded = false; async function loadScript() { if (scriptLoaded) return Promise.resolve(); for (const src of SCRIPT_URLS) { await new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } scriptLoaded = true; } export default function WeddingBandBuilder({ manifestUrl = 'wedding-band-project.json', basePath = 'https://your-cdn.com/wbb-assets/', showUI = true, theme = null, onReady = null, onPriceChange = null, style = {}, }) { const containerRef = useRef(null); const [loading, setLoading] = useState(true); useEffect(() => { let disposed = false; function handleReady(e) { if (disposed) return; const viewer = e.detail.viewer; const api = viewer.getPluginByType('WeddingBandBuilder')?.controller; if (!api) return; setLoading(false); if (theme) api.setTheme(theme); api.events.on('price:updated', (data) => { if (data.pricing) onPriceChange?.(data.pricing); }); onReady?.(api); } async function init() { await loadScript(); if (disposed || !containerRef.current) return; window.addEventListener('ijewel-viewer-ready', handleReady); new window.ijewelViewer.Viewer(containerRef.current, { name: 'Wedding Band Builder', version: 'v5', basePath, plugins: { WeddingBandBuilder: { manifestUrl }, }, }, { showCard: false, showSwitchNode: false, showUiButtons: showUI, showConfigurator: false, showZoomButtons: showUI, enableZoom: true, hideWbbUi: !showUI, }); } init(); return () => { disposed = true; window.removeEventListener('ijewel-viewer-ready', handleReady); }; }, [manifestUrl, basePath, showUI]); return (
{loading && (
Loading 3D viewer...
)}
); } ``` ## Page (App Router) ```jsx // app/configurator/page.jsx 'use client'; import { useState } from 'react'; import WeddingBandBuilder from '@/components/WeddingBandBuilder'; export default function ConfiguratorPage() { const [price, setPrice] = useState(null); const [api, setApi] = useState(null); return (

Design Your Wedding Band

setPrice(p)} />
{price ? `$${price.totalUsd.toFixed(2)}` : 'Loading...'}
); } ``` ## Pages Router (Legacy) If using the Pages Router, use `next/dynamic` to disable SSR: ```jsx // pages/configurator.jsx import dynamic from 'next/dynamic'; const WeddingBandBuilder = dynamic( () => import('@/components/WeddingBandBuilder'), { ssr: false, loading: () =>
Loading...
} ); export default function ConfiguratorPage() { return (
); } ``` ## API Route ```javascript // app/api/cart/route.js import { NextResponse } from 'next/server'; export async function POST(request) { const config = await request.json(); // Save to your database, Stripe, or order system console.log('Ring config:', config); return NextResponse.json({ success: true }); } ``` --- # Angular Integration: Complete Example An Angular component and service for the Wedding Band Builder. [Back to Script Tag guide](../integration-direct) ## Service ```typescript // wedding-band.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; const SCRIPT_URLS = [ 'https://releases.ijewel3d.com/libs/webgi-v0/bundle-0.22.0.js', 'https://releases.ijewel3d.com/libs/mini-viewer/0.6.18/bundle.nowebgi.iife.js', ]; @Injectable({ providedIn: 'root' }) export class WeddingBandService { private scriptLoaded = false; api$ = new BehaviorSubject(null); price$ = new BehaviorSubject(null); ready$ = new BehaviorSubject(false); async loadScript(): Promise { if (this.scriptLoaded) return Promise.resolve(); for (const src of SCRIPT_URLS) { await new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = () => resolve(); script.onerror = reject; document.head.appendChild(script); }); } this.scriptLoaded = true; } initViewer(container: HTMLElement, options: { basePath?: string; manifestUrl?: string; showUI?: boolean; theme?: string | object; } = {}) { const { basePath = 'https://your-cdn.com/wbb-assets/', manifestUrl = 'wedding-band-project.json', showUI = true, theme = null, } = options; const handleReady = (e: Event) => { const viewer = (e as CustomEvent).detail.viewer; const api = viewer.getPluginByType('WeddingBandBuilder')?.controller; if (!api) return; if (theme) api.setTheme(theme); api.events.on('price:updated', (data: any) => { if (data.pricing) this.price$.next(data.pricing); }); this.api$.next(api); this.ready$.next(true); window.removeEventListener('ijewel-viewer-ready', handleReady); }; window.addEventListener('ijewel-viewer-ready', handleReady); new (window as any).ijewelViewer.Viewer(container, { name: 'Wedding Band Builder', version: 'v5', basePath, plugins: { WeddingBandBuilder: { manifestUrl }, }, }, { showCard: false, showSwitchNode: false, showUiButtons: showUI, showConfigurator: false, showZoomButtons: showUI, enableZoom: true, hideWbbUi: !showUI, }); } } ``` ## Component ```typescript // wedding-band-builder.component.ts import { Component, ElementRef, Input, Output, EventEmitter, ViewChild, AfterViewInit, OnDestroy } from '@angular/core'; import { WeddingBandService } from './wedding-band.service'; import { Subscription } from 'rxjs'; import { filter, take } from 'rxjs/operators'; @Component({ selector: 'app-wedding-band-builder', template: `
`, styles: [` .wbb-wrapper { width: 100%; height: 100%; } .wbb-viewer { width: 100%; height: 100%; } `], }) export class WeddingBandBuilderComponent implements AfterViewInit, OnDestroy { @ViewChild('viewer') viewerEl!: ElementRef; @Input() basePath = 'https://your-cdn.com/wbb-assets/'; @Input() showUI = true; @Input() theme: string | object | null = null; @Output() wbbReady = new EventEmitter(); @Output() priceChange = new EventEmitter(); private subs: Subscription[] = []; constructor(private wbb: WeddingBandService) {} async ngAfterViewInit() { await this.wbb.loadScript(); this.wbb.initViewer(this.viewerEl.nativeElement, { basePath: this.basePath, showUI: this.showUI, theme: this.theme, }); this.subs.push( this.wbb.ready$.pipe(filter(Boolean), take(1)).subscribe(() => { this.wbbReady.emit(this.wbb.api$.value); }), this.wbb.price$.pipe(filter(Boolean)).subscribe((pricing) => { this.priceChange.emit(pricing); }), ); } ngOnDestroy() { this.subs.forEach(s => s.unsubscribe()); } } ``` ## Usage ```typescript // app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `
{{ price ? '$' + price.toFixed(2) : 'Loading...' }}
`, }) export class AppComponent { price: number | null = null; api: any = null; onReady(api: any) { this.api = api; console.log('Profiles:', api.getAvailableProfiles()); } onPrice(pricing: any) { this.price = pricing.totalUsd; } } ``` ## Module Declaration ```typescript // app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { WeddingBandBuilderComponent } from './wedding-band-builder.component'; @NgModule({ declarations: [AppComponent, WeddingBandBuilderComponent], imports: [BrowserModule], bootstrap: [AppComponent], }) export class AppModule {} ``` --- # Svelte Integration: Complete Example A Svelte component for the Wedding Band Builder. [Back to Script Tag guide](../integration-direct) ## Component ```svelte
{#if price}
${price.totalUsd.toFixed(2)}
{/if}
``` ## Usage ```svelte
``` ## Headless with Custom Controls ```svelte
{ api = e.detail; }} on:pricechange={(e) => { price = e.detail; }} />
{#if api}
{#each profiles as p} {/each}
{#each materials as m} {/each}
x{width.toFixed(2)}
{#if price}
${price.totalUsd.toFixed(2)}
{/if}
{/if}
``` --- # Pricing Engine Prices that update in real time as your customers design their ring, calculated from actual 3D geometry, not lookup tables. When a customer widens the band by 0.5mm, the price changes because the volume changed. When they add diamonds, the cost reflects real carat weight derived from stone diameter. The Pricing Engine supports both **Western** (markup based) and **Indian/Middle Eastern** (making-charge-based) pricing models used by jewellers worldwide. You set the metal prices, markup, and making charges. The engine handles the math. ## Quick Overview ``` metalCost = weight × pricePerGram ← auto-selected per metal makingCharge = based on mode (none / % / per-gram) finishSurcharge = flat fee per finish type stoneCost = totalCarats × pricePerCarat settingCost = stoneCount × costPerStone ───────────────────────────────────────────── subtotal = sum of all above total = subtotal × markupMultiplier final = round(total, roundingStep) ``` ## Two Pricing Models | | **Western** | **Indian / Middle Eastern** | |---|---|---| | Regions | US, Europe, luxury | India, Dubai, Gulf, Asia | | Making charge | None, baked into markup | Explicit (% or per-gram) | | Markup | 1.5×–2.5× | 1.0× | | Setting cost | Bundled in markup | Per-stone, itemized | ```javascript // Western - markup covers everything api.setPricingParams({ markupMultiplier: 2.0, }); // Indian - making charge + setting cost, no markup api.setPricingParams({ makingChargeMode: 'percent', makingChargePercent: 18, settingCostPerStone: 25, markupMultiplier: 1.0, }); ``` ## Reading Prices ```javascript const price = api.getPrice('her'); // price.totalUsd → final rounded price // price.metalPrice → { name, densityGcm3, pricePerGram, totalUsd } // price.makingCharge → { mode, percent, perGram, totalUsd } // price.diamonds → { count, totalCarats, pricePerCarat, totalUsd } | null // price.settingCost → { costPerStone, count, totalUsd } | null // price.finishSurcharge → { name, totalUsd } | null ``` Listen for real time updates: ```javascript api.events.on('price:updated', ({ bandName, pricing }) => { document.getElementById('price').textContent = `$${pricing.totalUsd}`; }); ``` ## Configuring Pricing All parameters are optional. Only provided values are updated. ```javascript api.setPricingParams({ // Metal pricing (see Per-Metal Pricing below) metalPrices: { 'White': { density: 15.8, pricePerGram: 48.0 }, 'Yellow': { density: 15.5, pricePerGram: 45.0 }, 'Rose': { density: 15.2, pricePerGram: 43.0 }, }, // Finish surcharges (see Finish Surcharges below) finishSurcharges: { 'Polished': 0, 'Brush': 0, 'Hammered': 75, 'Nature': 120, }, // Making charge makingChargeMode: 'percent', // 'none' | 'percent' | 'per-gram' makingChargePercent: 18, // Diamonds & setting diamondPricePerCarat: 1500, settingCostPerStone: 25, // Markup & rounding markupMultiplier: 1.0, roundingEnabled: true, roundingStep: 5, }, 'her'); // optional: per-band ``` ## Detail Sections ::: details Per-Metal Pricing ### Why Different Metals Have Different Prices All 18K gold alloys contain 75% pure gold, but the remaining 25% differs: | Metal | Alloy Composition (18K) | Density (g/cm³) | Relative Cost | |---|---|---|---| | **Yellow Gold** | 75% Au, 12.5% Ag, 12.5% Cu | ~15.5 | Base | | **White Gold** | 75% Au, 25% Pd/Ni/Zn | ~15.8 | +5–15% (palladium) | | **Rose Gold** | 75% Au, 22.5% Cu, 2.5% Ag | ~15.2 | -2–5% (copper) | ### Configuration When `metalPrices` is set, the engine automatically looks up density and price based on the active metal (primary slot): ```javascript api.setPricingParams({ metalPrices: { 'White': { density: 15.8, pricePerGram: 48.0 }, 'Yellow': { density: 15.5, pricePerGram: 45.0 }, 'Rose': { density: 15.2, pricePerGram: 43.0 }, }, }); ``` ### Fallback behavior | Priority | Source | |---|---| | 1st | `metalPrices[activeMetal]` | | 2nd | Flat `metalDensityGcm3` / `metalPricePerGram` | | 3rd | Defaults (density 15.5, price $97/g) | The flat fields still work for jewellers who price all golds equally. ### Multi color rings For 2-color or 3-color rings, the **primary metal (slot 1)** is used for pricing. The alloy difference between slots is negligible at the volume level. This matches real world practice. ::: tip If your store offers different metals per slot in a multi color ring, make sure your UI communicates that pricing is based on the primary metal (slot 1) only. This avoids customer confusion when a rose gold accent doesn't change the price. Material qualities do not select prices automatically. The `density` and `pricePerGram` fields on a `MaterialVariant` are reserved and the current runtime does not read them. If 14k, 18k, and 22k require different prices, use your external pricing service or update runtime pricing parameters after the selected variant changes. ::: ::: ::: details Finish Surcharges ### How Finishes Affect Price Most jewellers charge a flat surcharge for specialty finishes over the baseline (polished): | Finish | Typical Surcharge | Reason | |---|---|---| | **Polished** | $0 (baseline) | Standard buffing | | **Brush** | $0–$25 | Simple, often included | | **Sand** | $25–$50 | Blasting equipment | | **Linear** | $25–$50 | Precise directional work | | **Ice** | $30–$75 | Specialized texturing | | **Hammered** | $50–$100 | Skilled hand labour | | **Nature** | $50–$150 | Artisan carving/casting | ### Configuration ```javascript api.setPricingParams({ finishSurcharges: { 'Polished': 0, 'Brush': 0, 'Sand': 35, 'Linear': 40, 'Ice': 50, 'Hammered': 75, 'Nature': 120, }, }); ``` Unlisted finishes default to $0. The surcharge is a flat fee added to the subtotal before markup. ::: ::: details Making Charges ### Three Modes | Mode | Formula | Typical Use | |---|---|---| | `'none'` | No charge | Western model (profit in markup) | | `'percent'` | `metalCost × (percent / 100)` | India (8–35%, typical 15–18%) | | `'per-gram'` | `weight × perGramRate` | Dubai/Gulf ($5–$50/gram) | ### Examples ```javascript // Indian jeweller - 18% of metal cost api.setPricingParams({ makingChargeMode: 'percent', makingChargePercent: 18, markupMultiplier: 1.0, }); // Dubai jeweller - flat $12/gram api.setPricingParams({ makingChargeMode: 'per-gram', makingChargePerGram: 12, markupMultiplier: 1.0, }); // Western jeweller - no making charge, 2× markup api.setPricingParams({ makingChargeMode: 'none', markupMultiplier: 2.0, }); ``` ::: ::: details Diamond & Setting Costs ### Stone Pricing Diamond cost is calculated from total carat weight: ``` stoneCost = (caratPerStone × stoneCount) × pricePerCarat ``` The carat weight per stone is derived from the `stoneSize` parameter using the round brilliant approximation. ```javascript api.setPricingParams({ diamondPricePerCarat: 1500, }); ``` ### Setting Labour Setting cost covers physically mounting each stone. Rates vary by setting type: | Setting Type | Typical Range | |---|---| | Pave | $10–$25/stone | | Prong | $15–$40/stone | | Channel | $20–$50/stone | | Bezel | $25–$60/stone | ```javascript api.setPricingParams({ settingCostPerStone: 30, }); ``` The setting cost is added to the subtotal before markup. ::: ::: details Rounding ### Configuration Rounding is enabled by default with a step of $5: ```javascript // Disable rounding (exact calculated price) api.setPricingParams({ roundingEnabled: false }); // Round to nearest $10 api.setPricingParams({ roundingStep: 10 }); ``` ### Examples | Raw Price | Step 1 | Step 5 | Step 10 | Step 50 | |-----------|--------|--------|---------|---------| | $1,247.32 | $1,247 | $1,245 | $1,250 | $1,250 | | $2,998.50 | $2,999 | $3,000 | $3,000 | $3,000 | | $523.80 | $524 | $525 | $520 | $500 | ::: ::: details Weight Units The `metalPricePerGram` field accepts prices in different units. Set `weightUnit` and the engine converts internally: ```javascript // Price in troy ounces (common for precious metals) api.setPricingParams({ metalPricePerGram: 1800, weightUnit: 'troy_ounce', // divided by 31.1035 internally }); ``` | Unit | Grams per Unit | |------|---------------| | `'gram'` | 1 (default) | | `'ounce'` | 28.3495 | | `'troy_ounce'` | 31.1035 | ::: warning When using `metalPrices` (per-metal pricing), values are always in price-per-gram. The `weightUnit` conversion only applies to the flat `metalPricePerGram` field. ::: ::: details Per-Band Pricing Each band can have independent pricing parameters: ```javascript // Her - diamond ring with setting cost api.setPricingParams({ diamondPricePerCarat: 1500, settingCostPerStone: 25, }, 'her'); // His - plain band, no diamonds api.setPricingParams({ markupMultiplier: 1.8, }, 'his'); ``` ::: ::: details Manifest-Based Defaults When loading from the iJewel platform, pricing defaults come from the project manifest: ```json { "pricing": { "metals": { "Yellow": { "density": 15.5, "pricePerGram": 45.0 }, "White": { "density": 15.8, "pricePerGram": 48.0 }, "Rose": { "density": 15.2, "pricePerGram": 46.0 } } } } ``` Manifest values are used as defaults and can be overridden at runtime with `setPricingParams()`. ::: ## Server Side Validation ::: warning The pricing engine runs in the browser for real time display. A user could modify the DOM or intercept API calls to change the price. Always recalculate the price on your server before processing payment. Never trust client-submitted prices for checkout. ::: The recommended flow: 1. Customer configures ring → client shows live price 2. Customer adds to cart → your backend receives the config JSON via `getSnapshot()` 3. Your backend recalculates price using the config dimensions, metal prices, and diamond specs 4. Payment is processed against the server-calculated price The `PriceBreakdown` object includes all inputs (volume, weight, metal density, price per gram, carat weight, markup) so your backend can verify the math. ```javascript // Server-side price validation (Node.js) function validatePrice(snapshot, pricingParams) { const { weightGrams, metal, finish } = snapshot; const metalInfo = pricingParams.metalPrices[metal]; const metalCost = weightGrams * metalInfo.pricePerGram; // Making charge (percent mode shown; adapt for 'per-gram' or 'none') const makingCharge = pricingParams.makingChargeMode === 'percent' ? metalCost * (pricingParams.makingChargePercent / 100) : 0; const finishSurcharge = pricingParams.finishSurcharges?.[finish] ?? 0; // Diamonds (null when no stones are set) const diamonds = snapshot.diamonds; const stoneCost = diamonds ? diamonds.totalCarats * pricingParams.diamondPricePerCarat : 0; const settingCost = diamonds ? diamonds.count * (pricingParams.settingCostPerStone ?? 0) : 0; const subtotal = metalCost + makingCharge + finishSurcharge + stoneCost + settingCost; const total = subtotal * (pricingParams.markupMultiplier ?? 1); return total; } ``` ## Custom Pricing (Bring Your Own Formula) If you want to bypass the built in pricing engine and calculate prices entirely on your own, the API gives you all the physical measurements you need. Set `markupMultiplier: 0` or ignore the `PriceBreakdown` output and read the raw data instead. ### What the API gives you These are the physical/geometric values computed from the actual 3D model. You cannot get these without the engine. | Data | Source | Example | |---|---|---| | Ring volume (mm³) | `getPrice().volumeMm3` | `142.7` | | Ring weight (grams) | `getPrice().weightGrams` | `2.21` | | Metal density (g/cm³) | `getPrice().metalPrice.densityGcm3` | `15.5` | | Active metal | `getMaterials().slots[0].metal` | `'White'` | | Active finish | `getMaterials().slots[0].finish` | `'Hammered'` | | Diamond count | `getDiamonds().count` | `12` | | Diamond total carats | `getPrice().diamonds.totalCarats` | `0.36` | | Stone diameter (mm) | `getSpecSheetData().diamondSizeInfo.diameterMm` | `1.5` | | Setting type | `getDiamonds().settingType` | `'Channel'` | | Physical profile width and height (mm) | `getActualDimensionsMm()` | `{ widthMm: 4.0, heightMm: 1.8 }` | | Ring radius (mm) and profile scale | `getDimensions()` | `{ widthMm: 1.0, heightMm: 1.0, radiusMm: 8.5 }` | | Profile name | `getSnapshot().profile.name` | `'D-Shape'` | | Partition count | `getMaterials().partition` | `2` | | Band name | `getActiveBand()` | `'her'` | ### What you supply yourself Your own rates, margins, and business logic: - Metal price per gram (per alloy, per karat, per market) - Diamond price per carat (by size, cut, clarity, color) - Making charges or labor cost - Finish surcharges - Setting labor per stone - Markup or margin - Tax, shipping, rounding ### Example ```javascript // Client side: extract physical data from the engine const price = api.getPrice('her'); const materials = api.getMaterials('her'); const diamonds = api.getDiamonds('her'); const orderData = { volumeMm3: price.volumeMm3, weightGrams: price.weightGrams, metal: materials.slots[0].metal, finish: materials.slots[0].finish, diamondCount: diamonds?.count ?? 0, diamondCarats: price.diamonds?.totalCarats ?? 0, settingType: diamonds?.settingType ?? 'none', profile: api.getSnapshot('her').profile.name, dimensions: api.getActualDimensionsMm('her'), }; // Send to your backend const response = await fetch('/api/price', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(orderData), }); const { total } = await response.json(); // Display your own price document.getElementById('price').textContent = `$${total.toFixed(2)}`; ``` ```javascript // Server side: your own pricing logic (Node.js) function calculatePrice(order, catalog) { const metal = catalog.metals[order.metal]; const metalCost = order.weightGrams * metal.pricePerGram; const laborCost = order.weightGrams * metal.laborPerGram; const finishFee = catalog.finishFees[order.finish] ?? 0; const diamondCost = order.diamondCarats * catalog.diamondRate; const settingCost = order.diamondCount * catalog.settingFeePerStone; return metalCost + laborCost + finishFee + diamondCost + settingCost; } ``` This approach gives you full control. The engine handles the 3D geometry and measurement. You handle the business logic. ## Full PriceBreakdown Reference See [API Reference → PriceBreakdown](./api-reference#pricebreakdown) for the complete type definition. ::: tip Coming Soon - Per-karat gold pricing (10K, 14K, 18K, 24K) - Tiered diamond pricing based on size and quality - Tax calculation hooks - Multi-currency support ::: --- # Ring Measurements Guide This guide explains the measurements displayed in the wedding band builder and how to use them to configure a ring that matches real world specifications. ## Understanding Ring Size Ring size tells you whether a ring will fit a specific finger. Different countries use different sizing standards, but they all describe the same physical measurement: the **inner circumference** (or equivalently, the inner diameter) of the ring. ### Sizing Systems | System | How it works | Example | |--------|-------------|---------| | **US** | Numbered 3 through 13, including half sizes | US 7 = 0.68 inches inner diameter | | **EU** | Inner circumference in millimeters | EU 54 = 17.3mm inner diameter | | **UK** | Letter-based, from F through Z | UK N1/2 = 17.3mm inner diameter | The builder lets you switch between these systems using the **US / EU / UK** toggle buttons below the ring size slider. ### How to Measure Ring Size If you already know your ring size in one system, use the conversion table below. If not, the most accurate method is to visit a jeweler who can measure your finger with a ring mandrel. For at-home estimation: 1. Wrap a thin strip of paper snugly around the finger 2. Mark where the paper overlaps 3. Measure the length in millimeters -- this is the circumference 4. Divide by 3.14159 to get the inner diameter 5. Find the closest match in the table below ### Quick Conversion Table | US | EU | UK | Inner Diameter | |----|----|----|---------------| | 4 | 47 | H | 14.9mm / 0.59in | | 5 | 49 | J1/2 | 15.7mm / 0.62in | | 6 | 52 | L1/2 | 16.5mm / 0.65in | | 7 | 54 | N1/2 | 17.3mm / 0.68in | | 8 | 57 | P1/2 | 18.2mm / 0.72in | | 9 | 59 | R1/2 | 18.9mm / 0.74in | | 10 | 62 | T1/2 | 19.8mm / 0.78in | | 11 | 65 | V1/2 | 20.7mm / 0.81in | | 12 | 67 | X1/2 | 21.5mm / 0.85in | For the complete table with all half sizes, see the [Measurement System](./measurement-system#size-conversion-reference) reference. ## Ring Width Ring width is the measurement across the top of the band, from one edge to the other. This is the most visible dimension and has the biggest impact on how the ring looks on the hand. | Width | Description | |-------|-------------| | 2--3mm | Narrow, delicate look | | 4--5mm | Classic medium width | | 6--8mm | Wide, bold appearance | The width slider shows the actual millimeter value on the tape ruler. The range depends on the selected profile shape -- different profiles have different base widths. ## Ring Thickness Ring thickness (also called height or gauge) is the measurement from the inside surface to the outside surface. Thicker rings feel more substantial but also use more metal. | Thickness | Description | |-----------|-------------| | 1--1.5mm | Slim, lightweight | | 1.5--2mm | Standard comfort | | 2--3mm | Heavy, solid feel | The thickness slider works the same way as the width slider and controls a profile scale multiplier. Use `getActualDimensionsMm()` when displaying the resulting physical thickness in millimeters. ## Diamond Stone Size When diamonds are added to the band, the stone size control determines how large each individual diamond is. ### Display Units The stone size can be viewed in two units using the **ct / mm** toggle: **Millimeters** -- the physical diameter of each stone across its widest point (the girdle). **Carats** -- the weight unit used in the jewelry industry. Carat weight is approximated from the diameter using standard round brilliant proportions. The relationship is cubic: doubling the diameter roughly multiplies the carat weight by 8. | Diameter | Approx. Carats | Visual reference | |----------|---------------|-----------------| | 0.5mm | 0.001 ct | Grain-sized accent stones | | 1.0mm | 0.004 ct | Small melee stones | | 1.5mm | 0.012 ct | Standard melee | | 2.0mm | 0.029 ct | Large melee | ### Stone Count The number of diamonds placed on the ring depends on three factors: - **Diamond span** -- what portion of the ring is covered (Full, 1/2, 1/3, 1/4, or Custom count) - **Diamond spacing** -- the gap between stones (Touching, 1/2 Stone, Full Stone, Double) - **Stone size** -- larger stones mean fewer fit in the same span The actual stone count is computed automatically and displayed in the diamond panel. ## Price Breakdown The total price shown at the bottom of the builder is the sum of **metal cost** and **diamond cost**, multiplied by an optional markup. ### Metal Price Metal cost is based on the physical volume of the ring: 1. The ring's cross section area and radius determine the total metal volume 2. Volume is converted to weight using the metal's density (default: 18K gold at 15.5 g/cm3) 3. Weight is multiplied by the price per gram (default: $97/gram) Changing the ring size, width, or thickness all affect the metal volume and therefore the price. ### Diamond Price Diamond cost is based on total carat weight: 1. Each stone's carat weight is computed from its diameter 2. Total carats = carat per stone x number of stones 3. Total diamond cost = total carats x price per carat (default: $1,200/ct for melee diamonds) Changing stone size, count, span, or spacing all affect the diamond cost. ### Reading the Price Bar The price bar at the bottom shows a breakdown for each ring: ``` Her 3.2g 18K Gold ($310) + 12 dia 0.14ct ($168) $478.00 His 4.1g 18K Gold ($398) $398.00 Total $876.00 ``` ## Configuring Pricing Defaults All pricing parameters can be customized through the API: ```javascript // Set pricing for a specific band controller.setPricingParams({ metalDensityGcm3: 21.4, // Platinum density metalPricePerGram: 32, // Platinum price per gram diamondPricePerCarat: 1500, // Higher quality diamonds markupMultiplier: 1.3, // 30% retail markup }, 'her') ``` See the [API Reference](./api-reference) for full pricing parameter details, and the [Measurement System](./measurement-system) page for technical implementation details. --- # Measurement System ## Overview The wedding band builder uses a measurement system grounded in real world millimeter dimensions. All 3D geometry -- ring profiles, diamond models, and engraving paths -- is authored in millimeters, typically exported from Rhino `.3dm` files. A rendering scale factor (`rootScale = 0.1`) is applied to the 3D scene for visual purposes, but all measurement calculations operate in the original millimeter coordinate space. This document covers how each measurement type works, what units are available, and how conversions between units are performed. ::: tip User-Facing Guide For a higher-level overview of measurements aimed at end users (how to read ring sizes, understand diamond carats, and interpret the price breakdown), see the [Ring Measurements Guide](./measurement-guide). ::: --- ## Ring Dimensions (Width and Thickness) ### How It Works Ring width and thickness are controlled through **multiplier sliders** rather than absolute millimeter inputs. Each ring profile has a raw bounding-box dimension measured from the imported geometry: - **Raw width** -- the horizontal span of the profile cross section in mm - **Raw height** -- the vertical span (thickness) of the profile cross section in mm The slider value is a multiplier on these raw dimensions: ``` actualMm = rawDimension x multiplier ``` ### Slider Ranges | Dimension | Multiplier min | Multiplier max | Example (4mm raw profile) | |-----------|---------------|---------------|--------------------------| | Width | 0.5x | 2.0x | 2mm -- 8mm | | Thickness | 0.5x | 1.5x | 2mm -- 6mm | ::: warning Width and thickness sliders apply multipliers (0.5x to 2.0x) to the profile's base dimensions. A multiplier of 1.5x on a profile with a 3mm base width gives 4.5mm, but the same 1.5x on a different profile with a 4mm base width gives 6mm. If building custom UI, convert to actual millimeters before displaying to users. ::: ### UI Display The tape ruler slider shows actual millimeter values at the min and max ends, computed from the raw profile dimensions and the multiplier range. The current value is displayed as the actual mm measurement. --- ## Ring Size ### How It Works Ring size is stored internally as the **inner radius in millimeters**. The sizing slider operates on inner diameter (radius x 2) and snaps to standard jeweler reference values. When a ring size changes in a multi-band configuration, `matchBaseHeight()` is called to keep all bands aligned at their base edges. ### Supported Sizing Systems The UI provides a toggle between three international sizing systems: | System | Range | Diameter display unit | |--------|----------|-----------------------| | US | 3 -- 13 (half sizes) | Inner diameter in inches | | EU | 44 -- 69 | Inner diameter in mm | | UK | F -- Z | Inner diameter in mm | Default ring size: radius of ~10mm (approximately US size 10). ### Display Format Each size is shown as: `[size label] . [inner diameter]` - US example: `7 . 0.68 in` - EU example: `54 . 17.3 mm` - UK example: `N1/2 . 17.3 mm` US sizes display the inner diameter in inches (diameter mm / 25.4), while EU and UK sizes display it in millimeters. --- ## Size Conversion Reference The following table maps between all three sizing systems. Inner radius is the value stored internally; inner diameter is what the user sees. | US Size | EU Size | UK Size | Inner Radius (mm) | Inner Diameter (mm) | |---------|---------|---------|-------------------|---------------------| | 3 | 44 | F | 7.02 | 14.04 | | 3.5 | 45 | G | 7.22 | 14.44 | | 4 | 47 | H | 7.43 | 14.86 | | 4.5 | 48 | I | 7.64 | 15.28 | | 5 | 49 | J1/2 | 7.85 | 15.70 | | 5.5 | 50 | K | 8.05 | 16.10 | | 6 | 52 | L1/2 | 8.26 | 16.52 | | 6.5 | 53 | M | 8.46 | 16.92 | | 7 | 54 | N1/2 | 8.67 | 17.34 | | 7.5 | 56 | O | 8.87 | 17.74 | | 8 | 57 | P1/2 | 9.10 | 18.20 | | 8.5 | 58 | Q | 9.27 | 18.54 | | 9 | 59 | R1/2 | 9.45 | 18.90 | | 9.5 | 61 | S | 9.68 | 19.36 | | 10 | 62 | T1/2 | 9.92 | 19.84 | | 10.5 | 64 | U1/2 | 10.13 | 20.26 | | 11 | 65 | V1/2 | 10.34 | 20.68 | | 11.5 | 66 | W | 10.54 | 21.08 | | 12 | 67 | X1/2 | 10.74 | 21.48 | | 12.5 | 68 | Y | 10.95 | 21.90 | | 13 | 69 | Z | 11.16 | 22.32 | --- ## Diamond Stone Size ### How It Works Diamond size is controlled through a **multiplier** on a base reference diameter. The base diamond model (`diamond_single.glb`) has a bounding-box diameter of **0.616mm** at `stoneSize = 1`. ``` diameterMm = 0.616 x stoneSize ``` ### Slider Range | Multiplier | Diameter (mm) | |-----------|--------------| | 0.5x (min) | 0.31mm | | 1.0x | 0.616mm | | 3.0x (max) | 1.85mm | ### Display Units The UI provides a toggle between two unit systems: **Millimeters** -- Shows the actual computed diameter: ``` diameterMm = 0.616 x stoneSize ``` **Carats** -- Approximated using a round brilliant formula: ``` carats = diameterMm^3 x 0.00366 ``` ::: tip The carat formula (`diameter³ × 0.00366`) is a standard round brilliant approximation accurate to ±5%. For certified stones, use the actual carat weight from your supplier rather than this computed value. ::: This cubic approximation models the relationship between a round brilliant diamond's diameter and its carat weight. It has been verified against standard gemological reference charts: | Diameter (mm) | Computed carats | Standard reference | |--------------|----------------|-------------------| | 4.0 | ~0.23 ct | 0.25 ct | | 5.0 | ~0.46 ct | 0.50 ct | | 6.5 | ~1.00 ct | 1.00 ct | | 8.0 | ~1.88 ct | 2.00 ct | --- ## Price Calculation ### How It Works Ring pricing is computed from the physical volume of metal, using a three-step process based on Pappus's centroid theorem. ### Step 1: Volume (Pappus's Theorem) The ring is a solid of revolution. Its volume is computed as: ``` volumeMm3 = crossSectionArea x 2pi x radius ``` Where: - `crossSectionArea` is the area of the ring's profile cross section in mm squared - `radius` is the ring's inner radius in mm This is exact for any profile shape revolved around a central axis. ### Step 2: Metal Weight Volume is converted to weight using the metal's density: ``` volumeCm3 = volumeMm3 / 1000 weightGrams = volumeCm3 x densityGcm3 ``` The default density is **15.5 g/cm cubed**, which corresponds to 18K gold. Different metals use different densities (e.g., platinum is approximately 21.4 g/cm cubed). ### Step 3: Price ``` priceUsd = weightGrams x pricePerGram ``` The default price per gram is **$97/gram**. This value is configurable and can be adjusted per metal type. ### Weight Units The pricing service supports three weight units for price input: | Unit | Grams per unit | |-----------|---------------| | Gram | 1.0 | | Ounce | 28.3495 | | Troy ounce | 31.1035 | When a price is specified per ounce or per troy ounce, it is internally converted to price-per-gram before the final calculation. --- ## Coordinate System Notes - All geometry is authored in **millimeters** in the source CAD files (Rhino `.3dm`) - Diamond models share the same mm coordinate space as ring profiles - A `rootScale = 0.1` is applied at the scene level for rendering, but this does not affect any measurement or pricing calculations - Profile dimensions are measured from the geometry's axis-aligned bounding box - The cross section area used for pricing is computed from the actual profile polygon, not the bounding box --- # Spec Sheet & Manufacturing The Spec Sheet is a print ready summary of a ring's configuration: profile, dimensions, materials, diamonds, engraving, and pricing. It opens in a new browser tab and can be saved as PDF or printed directly. The spec sheet is manufacturer-independent. Send it to any workshop, any CAD team, any CNC machine. No proprietary format or vendor-specific tooling required. ::: tip Dimensions on the spec sheet are computed from the actual 3D geometry, not from a size chart or lookup table. The width, height, and volume are exact values from the parametric model. Communicate this to your manufacturing partners so they know the numbers are geometry derived, not catalog approximations. ::: ## Quick Start ```javascript // Get all data needed for the spec sheet const { snapshot, price, diamondSizeInfo, actualDimsMm } = api.getSpecSheetData('her'); // Open in a new window (built-in UI does this automatically) import { renderSpecSheetHTML } from '@ijewel3d/common'; const html = renderSpecSheetHTML(specData, { accent: '#8B6914' }); const win = window.open('', '_blank'); win.document.write(html); win.document.close(); ``` The built-in UI includes a **"View Spec Sheet"** button below the price total that handles this automatically. ## What's Included | Section | Details | |---|---| | **Header** | Logo, date, reference number | | **Profile** | Cross section diagram with dimension lines | | **Dimensions** | Width, height, ring size (US/EU/UK), inner diameter | | **Materials** | Metal name(s), finish, color swatches, partition info | | **Edges** | Edge type and side (if applied) | | **Top View** | Birds eye diagram showing metal zones and diamond placement | | **Diamonds** | Setting type, count, stone diameter, per-stone carats, total carat weight, span, band diagram | | **Engraving** | Engraved text and font | | **Pricing** | Full breakdown: metal cost, making charge, diamond cost, setting cost, finish surcharge, markup, total | ## Generating the Data `getSpecSheetData()` bundles everything the spec sheet needs in a single call: ```javascript const data = api.getSpecSheetData('her'); // data.snapshot → full RingSnapshot (profile, dimensions, materials, diamonds, etc.) // data.price → PriceBreakdown or null (if pricing not configured) // data.diamondSizeInfo → { diameterMm, carats } or null (if no diamonds) // data.actualDimsMm → { widthMm, heightMm } (actual mm after multiplier) ``` ## Rendering Options `renderSpecSheetHTML()` produces a complete standalone HTML document: ```javascript const html = renderSpecSheetHTML(specData, { accent: '#8B6914', // accent color for diagrams and headings reference: 'ORDER-2024-001', // custom reference number logoUrl: '/my-logo.svg', // custom logo (defaults to iJewel3D logo) themeVars: { // inject CSS custom properties '--rb-color-primary': '#8B6914', }, }); ``` | Option | Type | Default | Description | |---|---|---|---| | `accent` | `string` | `#1a1a1a` | Accent color for SVG diagrams and section titles | | `reference` | `string` | Auto-generated | Reference number shown in the header (format: `WBB-YYYYMMDD-001`) | | `logoUrl` | `string` | iJewel3D logo | URL to a custom logo image | | `themeVars` | `Record` | - | CSS custom properties injected into the document | ::: tip Light accent colors If the accent color is too light for the cream background, the renderer automatically falls back to `#1a1a1a` for readability. ::: ::: details SpecSheetData Type Reference The full `SpecSheetData` interface accepted by both the React component and the HTML renderer: ```typescript interface SpecSheetData { bandName: string profile: { index: number; name: string } dimensions: { widthMm: number; heightMm: number; radiusMm: number } materials: { partition: number slots: { slot: number; metal: string; finish: string }[] } diamonds: { settingType: string count: number span?: string stoneSize?: number position?: number diameterMm?: number carats?: number totalCarats?: number } | null edge: { type: string; side: string } engraving: { text: string; font?: string } | null pricing: { volumeMm3: number weightGrams: number metalPrice: { name: string; totalUsd: number } makingCharge: { mode: string; percent: number; perGram: number; totalUsd: number } diamonds: { count: number; totalCarats: number; pricePerCarat: number; totalUsd: number } | null settingCost: { costPerStone: number; count: number; totalUsd: number } | null finishSurcharge: { name: string; totalUsd: number } | null subtotalUsd: number markupMultiplier: number totalUsd: number } | null actualWidthMm?: number actualHeightMm?: number } ``` ::: ::: details Building SpecSheetData Manually If you're using the headless API and want full control, you can assemble `SpecSheetData` from individual API calls: ```javascript const snapshot = api.getSnapshot('her'); const price = api.getPrice('her'); const dims = api.getActualDimensionsMm('her'); const diamondInfo = snapshot.diamonds?.stoneSize ? api.getDiamondSizeInfo(snapshot.diamonds.stoneSize) : null; const specData = { bandName: snapshot.bandName, profile: snapshot.profile, dimensions: snapshot.dimensions, materials: snapshot.materials, diamonds: snapshot.diamonds ? { ...snapshot.diamonds, diameterMm: diamondInfo?.diameterMm, carats: diamondInfo?.carats, totalCarats: diamondInfo ? diamondInfo.carats * snapshot.diamonds.count : undefined, } : null, edge: snapshot.edge, engraving: snapshot.engraving, pricing: price ? { volumeMm3: price.volumeMm3, weightGrams: price.weightGrams, metalPrice: price.metalPrice, makingCharge: price.makingCharge, diamonds: price.diamonds, settingCost: price.settingCost, finishSurcharge: price.finishSurcharge, subtotalUsd: price.totalBeforeRounding ?? price.totalUsd, markupMultiplier: price.markupMultiplier, totalUsd: price.totalUsd, } : null, actualWidthMm: dims.widthMm, actualHeightMm: dims.heightMm, }; ``` ::: ::: details Diagrams The spec sheet includes three SVG diagrams rendered inline: | Diagram | Shows | |---|---| | **Profile Diagram** | Cross section silhouette (D-Shape, Flat, Comfort, etc.) with width/height dimension lines | | **Top View Diagram** | Birds eye ring view showing metal partition zones and diamond dot positions | | **Diamond Band Diagram** | Flat band showing stone placement pattern for the active setting type | All diagrams use the `accent` color and adapt to the ring's actual configuration. They render as inline SVGs, with no external image dependencies. ::: ::: details Customizing the Header The spec sheet header shows a logo, title, date, and reference number: ```javascript // Custom branding const html = renderSpecSheetHTML(specData, { logoUrl: 'https://yourstore.com/logo.svg', reference: 'INV-2024-0042', }); ``` - **Logo**: Pass a URL to `logoUrl`. If omitted, the iJewel3D logo is used. - **Reference**: Auto-generated as `WBB-YYYYMMDD-001` if not provided. Pass your own order/invoice number for production use. - **Date**: Always uses the current date when the sheet is generated. ::: ## React Component For React-based integrations, the `SpecSheet` component can be rendered directly: ```jsx import { SpecSheet } from '@ijewel3d/ui'; ``` This renders the same layout as the HTML version, using React components for the SVG diagrams. ## Print & PDF The spec sheet includes a toolbar (hidden when printing) with **Download PDF** and **Print** buttons. Both trigger the browser's print dialog. Use "Save as PDF" for PDF export. The stylesheet includes `@media print` rules that: - Hide the toolbar - Use a cream background (`#FAF9F6`) - Optimize layout for A4/Letter paper - Ensure diagrams render cleanly in print --- # Theming & Branding Customize the configurator's appearance to match your brand identity, from a quick preset to pixel-level control. ## Layouts The built-in Wedding Band UI ships three independently registered layouts: | Layout ID | Intended experience | Opening rings created by Drive | | --- | --- | --- | | `panel` | Complete toolset in the classic side panel | Her, His, or both | | `boutique` | Customer-facing storefront; the default when no valid layout is named | Her, His, or both | | `modern-metals` | Focused dark workflow for one individual ring | One neutral ring; no His/Her or add-ring control | The New Wedding Band Configurator dialog in Drive, with the Panel, Boutique and Modern Metals layout options iJewel Drive asks for the layout when the project is created and stores it in the manifest: ```json { "ui": { "layout": "modern-metals", "linkBands": false, "theme": { "preset": "dark", "showRingToggle": false } } } ``` For a self-hosted Modern Metals project, also define exactly one entry in `defaults.bands`. Setting the layout name by itself changes presentation; it does not delete extra bands from a hand-authored manifest. The Modern Metals layout with its six tabs and the Style tab open Modern Metals organizes the single-ring workflow into **Style**, **Material**, **Outside**, **Inside**, **Stones**, and **Engrave** tabs. Its Material tab shows the base color, then Quality when the base has multiple variants, then only the finishes supported by that material and variant. The Outside tab has left, center, and right slots. The outer slots can be floating inlays or rim-anchored overlays. The center slot is always an inlay. The Inside tab controls the bore sleeve and inside polish. This focused layout does not expose non-circular paths, design grooves, or edge controls, although those controller APIs remain available to a custom interface. At runtime, use `getAvailableLayouts()`, `getLayout()`, and `setLayout(id)`. An unknown ID is rejected with a validation warning rather than rendering an empty panel. ## Presets 11 built-in themes, applied with one line: ```javascript api.setTheme('luxury-gold'); ``` | Preset | Character | |---|---| | `default` | Clean, neutral. Works with any brand | | `luxury-gold` | Warm gold accents, serif typography | | `modern-minimal` | Monochrome, light, minimal chrome | | `dark` | Dark background, light text, jeweler showcase feel | | `rose-elegant` | Rose/blush tones, elegant serif fonts | | `coral-modern` | Clean white with a coral-red accent, rounded sans-serif | | `fresh-teal` | Light canvas with a calm teal accent, clean sans-serif | | `minimal-blue` | Pure white, airy spacing, blue accent, system sans-serif | | `warm-beige` | Warm beige tones with a muted blue selection accent | | `classic-gold` | Dark-gold accent on white, gold-gradient ring toggle | | `ijewel` | iJewel3D's own purple-accented brand styling | The builder interface under the Default, Luxury Gold, Fresh Teal and iJewel theme presets To cycle through presets interactively: ```javascript const nextTheme = api.cycleTheme(); console.log(`Now using: ${nextTheme}`); ``` ## Custom Themes Start from a preset and override specific properties: ```javascript api.setTheme({ preset: 'modern-minimal', colors: { primary: '#2E5B3C', background: '#F5F7F5', }, fonts: { body: "'Cormorant Garamond', serif", googleFonts: ['Cormorant+Garamond:wght@400;500;600'], }, panelWidth: 380, }); ``` Or build a theme from scratch without a preset base: ```javascript api.setTheme({ colors: { primary: '#8B6914', primaryHover: '#A07D1C', text: '#1a1a1a', textMuted: '#666666', background: '#FAFAF8', surface: '#FFFFFF', border: '#E0DDD8', }, fonts: { body: "'Inter', sans-serif", headline: "'Playfair Display', serif", googleFonts: ['Inter:wght@300;400;500', 'Playfair+Display:wght@400;700'], }, shapes: { borderRadius: 8, }, }); ``` ## Colors All color properties are optional. Unset values fall back to the preset (or `default` if no preset). ```typescript interface ThemeColors { primary?: string // Accent color (buttons, active states, sliders) primaryHover?: string // Primary hover state secondary?: string // Secondary accent text?: string // Main text color textMuted?: string // Secondary/hint text textPlaceholder?: string // Placeholder text background?: string // Page background surface?: string // Card/panel background surfaceHover?: string // Surface hover state border?: string // Border color borderLight?: string // Subtle borders borderHover?: string // Border hover state } ``` ## Fonts ```typescript interface ThemeFonts { body?: string // Body text (e.g., "'Inter', sans-serif") headline?: string // Section headings light?: string // Light weight variant googleFonts?: string[] // Google Fonts to load (e.g., ['Inter:wght@300;400;500']) } ``` Google Fonts listed in the `googleFonts` array are automatically loaded via the Google Fonts API. No manual `` tags needed. ## UI Controls | Property | Type | Default | Description | |---|---|---|---| | `panelWidth` | `number` | `340` | Width of the configuration panel in pixels | | `showPoses` | `boolean` | `true` | Show camera angle buttons | | `showARButton` | `boolean` | `true` | Show the AR try-on button | | `showExportButton` | `boolean` | `true` | Show export/import buttons | | `showRingToggle` | `boolean` | `true` | Show the His/Her band toggle | | `initialTab` | `string` | - | Which tab to open by default | ```javascript // Hide features you don't need api.setTheme({ preset: 'dark', showARButton: false, showExportButton: false, panelWidth: 360, initialTab: 'material', }); ``` ## Custom CSS For fine-grained control, inject raw CSS: ```javascript api.setTheme({ preset: 'modern-minimal', customCSS: ` .wbb-root .field-label { text-transform: uppercase; letter-spacing: 0.05em; } .wbb-root .pricing-total { font-size: 1.4em; } `, }); ``` All custom CSS is scoped under `.wbb-root`, so it won't affect the rest of your page. ## CSS Custom Properties The theme system injects CSS custom properties on the `.wbb-root` element. Use these in your own stylesheets to stay in sync with the active theme: | Property | Maps to | |---|---| | `--rb-color-primary` | `colors.primary` | | `--rb-color-primary-hover` | `colors.primaryHover` | | `--rb-color-secondary` | `colors.secondary` | | `--rb-color-text` | `colors.text` | | `--rb-color-text-muted` | `colors.textMuted` | | `--rb-color-background` | `colors.background` | | `--rb-color-surface` | `colors.surface` | | `--rb-color-border` | `colors.border` | | `--rb-font-body` | `fonts.body` | | `--rb-font-headline` | `fonts.headline` | | `--rb-radius-md` | `shapes.borderRadius` | ```css /* Example: style your own elements to match the configurator theme */ .my-price-display { background: var(--rb-color-surface); color: var(--rb-color-text); border: 1px solid var(--rb-color-border); font-family: var(--rb-font-body); border-radius: var(--rb-radius-md); } ``` ## Full Type Reference ```typescript interface UITheme { preset?: ThemePresetName colors?: ThemeColors fonts?: ThemeFonts shapes?: ThemeShapes components?: ThemeComponentOverrides customCSS?: string panelWidth?: number showPoses?: boolean showARButton?: boolean showExportButton?: boolean showRingToggle?: boolean initialTab?: string } type ThemePresetName = | 'default' | 'luxury-gold' | 'modern-minimal' | 'dark' | 'rose-elegant' | 'coral-modern' | 'fresh-teal' | 'minimal-blue' | 'warm-beige' | 'classic-gold' | 'ijewel' ``` For the complete API, see [`setTheme()`](./api-reference#settheme-theme) in the API Reference. --- # API Reference Complete reference for the Wedding Band Builder API. ## Accessing the API ### Direct Integration (Same Page) ```javascript window.addEventListener('ijewel-viewer-ready', (e) => { const viewer = e.detail.viewer; const api = viewer.getPluginByType('WeddingBandBuilder').controller; api.setWidthMm(4.4); }); ``` ### Same-Origin iframe The iframe page fires `ijewel-viewer-ready` on its own `window`. That event does not bubble to the parent page. Register a parent callback before the iframe loads, then forward the viewer from a listener inside the iframe page. Parent page: ```html ``` ```javascript window.handleWbbViewerReady = (viewer) => { const api = viewer.getPluginByType('WeddingBandBuilder').controller; api.setWidthMm(4.4); }; const iframe = document.getElementById('wbb-iframe'); iframe.src = './wbb-viewer.html'; ``` Inside `wbb-viewer.html`, register this listener before creating Mini Viewer: ```javascript window.addEventListener('ijewel-viewer-ready', ({ detail }) => { window.parent.handleWbbViewerReady?.(detail.viewer); }, { once: true }); ``` This direct callback requires both pages to use the same origin. You can also use the postMessage protocol below for a same-origin iframe. ### Cross-Origin (PostMessage) For iframes on a different domain: ```javascript // Parent page sends to iframe const viewerOrigin = 'https://ijewel3d.com'; iframe.contentWindow.postMessage({ id: 'req-1', method: 'setWidthMm', args: [4.4] }, viewerOrigin); // Listen for responses from iframe window.addEventListener('message', (event) => { if (event.source !== iframe.contentWindow) return; if (event.origin !== viewerOrigin) return; if (event.data.id === 'req-1') { if (event.data.error) { // Structured error: { message, source, details } console.log(event.data.error.message); } else { console.log('Result:', event.data.result); } } if (event.data.event) { console.log('Event:', event.data.event, event.data.data); } }); ``` Events (including `'log'` and `'error'`) are automatically forwarded from the iframe to the parent window. ## Read Methods ### `getSnapshot(bandName?)` Returns a customer-facing summary snapshot for one band. It includes the outside and inside features and each slot's base, variant and finish. Use `toJSON()` when exact state restoration is required. ```javascript const snapshot = api.getSnapshot('her'); ``` **Parameters:** | Name | Type | Default | Description | |------|------|---------|-------------| | `bandName` | `string` | active band | `'her'` or `'his'` | **Returns:** [`RingSnapshot`](#ringsnapshot) ### `exportConfig()` Exports one `RingSnapshot` summary for every band included in the project. This is the readable record for a cart, an order line, or a manufacturer handoff. ```javascript const config = api.exportConfig(); // { her: RingSnapshot, his: RingSnapshot } ``` **Returns:** `Record` The summary covers the profile, dimensions, materials — including each slot's base, variant and finish — outside and inside features, diamonds, edges, engraving, and price. [`importConfig()`](#importconfig-config) reads it back and reproduces the same rings. Pricing is the one thing it does not restore. The snapshot carries computed totals, not the [`PricingParams`](#pricingparams) that produced them, so remove `pricing` from each band before you import the record back. Use `api.toJSON()` when you need the exact internal state, including anything the readable summary does not model. ### `getBandNames()` Returns the IDs of all bands included in the loaded project. Do not assume that both `her` and `his` exist—a Drive project can be created with only one. ```javascript const bands = api.getBandNames(); // ['her', 'his'], ['her'], or ['his'] ``` **Returns:** `string[]` ### `getManifest()` Returns the loaded Wedding Band manifest, including project catalogs, icons, limits, engraving options, and theme configuration. Prefer the dedicated catalog getters for building UI; use this method when you need project metadata that has no dedicated getter. ```javascript const manifest = api.getManifest(); console.log(manifest?.icons?.logo); ``` **Returns:** `WeddingBandManifest | null` ### `getSpecSheetData(bandName?)` Returns one manufacturing/export payload containing the ring snapshot, price, diamond size information, and actual physical dimensions. ```javascript const { snapshot, price, diamondSizeInfo, actualDimsMm, } = api.getSpecSheetData('her'); ``` **Returns:** ```typescript { snapshot: RingSnapshot; price: PriceBreakdown | null; diamondSizeInfo: { diameterMm: number; carats: number } | null; actualDimsMm: { widthMm: number; heightMm: number }; } ``` See [Specification Sheet](./spec-sheet) for a printable implementation. ### `getRawState(bandName?)` Returns a read-only snapshot of the controller's internal `BandState`. This is primarily useful for debugging and advanced migration work; storefront order data should use `exportConfig()` or `getSnapshot()` for a readable summary, and `api.toJSON()` when an exact restore is needed. ```javascript const internalState = api.getRawState('her'); ``` **Returns:** `Readonly` ### `getActiveBand()` Returns the name of the currently active band. ```javascript const band = api.getActiveBand(); // 'her' or 'his' ``` **Returns:** `string` ### `getDimensions(bandName?)` Returns the current dimension state. For compatibility, `widthMm` and `heightMm` are legacy field names: their values are **profile scale multipliers**, not physical millimeters. `radiusMm` is a physical radius in millimeters. ```javascript const dims = api.getDimensions(); // { widthMm: 1.0, heightMm: 1.0, radiusMm: 8.5 } console.log(`Width scale: ×${dims.widthMm}`); ``` **Returns:** [`DimensionsSnapshot`](#dimensionssnapshot) ### `getRawProfileDimensions(bandName?)` Returns the source profile's width and height at a `1.0` scale, in millimeters. ```javascript const raw = api.getRawProfileDimensions(); // { widthMm: 4.0, heightMm: 1.8 } ``` **Returns:** `{ widthMm: number; heightMm: number }` ### `getActualDimensionsMm(bandName?)` Returns the physical profile width and height after applying the current scale multipliers. ```javascript const actual = api.getActualDimensionsMm(); // { widthMm: 4.4, heightMm: 1.8 } ``` **Returns:** `{ widthMm: number; heightMm: number }` ### `getDiamondBaseDiameterMm()` Returns the manifest's source diamond diameter at `stoneSize = 1`. ```javascript const baseDiameterMm = api.getDiamondBaseDiameterMm(); ``` **Returns:** `number` ### `getDiamondSizeInfo(stoneSize)` Converts a Wedding Band stone-size multiplier into its physical diameter and approximate round-brilliant carat weight. ```javascript const stone = api.getDiamondSizeInfo(1.5); // { diameterMm: number, carats: number } ``` **Returns:** `{ diameterMm: number; carats: number }` ### `getMaterials(bandName?)` Returns the current partition, material slots, and outside/inside material features. The historical `metal` field contains the base material ID. ```javascript const mats = api.getMaterials(); // { // partition: 2, // slots: [ // { slot: 1, metal: 'White', base: 'White', variant: '18k', finish: 'Polished' }, // { slot: 2, metal: 'Yellow', base: 'Yellow', variant: '14k', finish: 'Hammered' } // ], // insidePolished: true, // splitAtGroove: true, // inlays: [{ centerZ: 0, widthMm: 1, metal: 'wood', variant: 'koa' }], // overlays: [], // sleeve: { enabled: true, metal: 'yellow', variant: '18k', full: true } // } ``` Every slot names all three material axes. `base` is the base material and `metal` carries the same value under its original name, so code written before variants existed keeps working. `variant` is the quality or sub-category — `18k` versus `14k`, or a wood species — and is always filled in: a slot the customer never changed reports the material's own default rather than nothing. `finish` is empty for a material with no finish axis, such as wood. **Returns:** [`MaterialSnapshot`](#materialsnapshot) ### `getDiamonds(bandName?)` Returns the current diamond setting configuration, or `null` if no diamonds are set. ```javascript const diamonds = api.getDiamonds(); ``` **Returns:** [`DiamondSnapshot`](#diamondsnapshot) `| null` ### `getEdge(bandName?)` Returns the current edge configuration. ```javascript const edge = api.getEdge(); // { type: 'Beveled', side: 'Both' } ``` **Returns:** [`EdgeSnapshot`](#edgesnapshot) ### `getPrice(bandName?)` Returns the full price breakdown, or `null` if pricing is not configured. ```javascript const price = api.getPrice('her'); console.log(`$${price.totalUsd.toFixed(2)}`); ``` **Returns:** [`PriceBreakdown`](#pricebreakdown) `| null` See [Pricing API](./pricing) for detailed pricing documentation. ### `getWaveParams(bandName?)` Returns the clamped wave-path parameters plus the current amplitude ceiling, so a slider can bound itself. `frequency` stays within 2 to 6, and `amplitudeMax` is `0.7 / frequency` under the engine's slope rule. ```javascript const { frequency, amplitude, amplitudeMax } = api.getWaveParams(); ``` **Returns:** `{ frequency: number; amplitude: number; amplitudeMax: number }` ### `getEdges(bandName?)` Returns the independent configuration of both band edges. **Returns:** `{ left: { type, width, depth, finish }; right: { type, width, depth, finish } }` ### `getDivisionBoundary(bandName?)` Returns the wave that the color seam actually rides on the mesh, or `undefined` when the seam runs straight. Draw this in any 2D placement surface that must agree with the ring. An enabled Wavy Grooves feature owns the wave and splits the colors along it only when wavy split is on, so a wavy Division can still draw a straight seam. **Returns:** `{ frequency: number; amplitude: number } | undefined` ### `getRelationship(bandName?)` Returns the current segment-width ratio, normalized to the partition count. **Returns:** `number[]` ### `getRingSizeForBand(bandName?)` Returns the standard size the band currently reads as, in every system. The spec sheet resolves sizes the same way, so the two can never disagree. ```javascript const { entry, radiusMm, diameterMm, label } = api.getRingSizeForBand(); console.log(label('US')); ``` **Returns:** `{ entry: RingSizeEntry; radiusMm: number; diameterMm: number; label: (system: RingSizeSystem) => string }` ### `getAutoOptimalHeight(bandName?)` Returns `true` when the band tracks the manufacturer's optimal thickness. **Returns:** `boolean` ### `getThicknessRangeMm(bandName?)` Returns the manufacturable thickness range for the active profile at its current width, or `null` when that profile has no rule table. Use it to bound the height control dynamically. **Returns:** `{ minMm: number; maxMm: number } | null` ### `getMaxDiamondCount(bandName?)` Returns how many stones the current setting can physically fit across the band. This is the ceiling the engine clamps requests to, not the count last placed. **Returns:** `number` ### `isSettingTypeAvailable(settingType, bandName?)` Returns `true` when a stone-setting type suits the band's current profile and path. **Returns:** `boolean` ### `getUIOptions()` Returns the resolved UI option block from the manifest theme. **Returns:** `Partial` ### `getParallaxEnabled()` Returns whether relief parallax mapping is on. **Returns:** `boolean` ## Catalog Methods These methods return the available options defined in the project manifest. ### `getAvailableProfiles()` ```javascript const profiles = api.getAvailableProfiles(); // [{ index: 0, id: 'd-shape', name: 'D-Shape', thumbnail: '...' }, ...] ``` **Returns:** `{ index: number; id: string; name: string; thumbnail?: string; iconUrl?: string }[]` ### `getAvailableMetals()` Returns the base materials allowed for the main band body, as a flat metal-style list. Prefer `getAvailableMaterials('band')` when the UI also needs variants or usage roles. ```javascript const metals = api.getAvailableMetals(); // [{ id: 'yellow', name: 'Gold', iconUrl: '...' }, ...] ``` The catalog reports the material icon as `iconUrl`. An older manifest's `thumbnail` is carried into the same field, so always read `iconUrl`. **Returns:** `{ id: string; name: string; iconUrl?: string }[]` ### `getAvailableMaterials(usage?)` Returns the base-material catalog. Pass a usage role to build the correct picker for the band body, an inlay, an overlay, or the inside sleeve. ```javascript const bandMaterials = api.getAvailableMaterials('band'); const inlayMaterials = api.getAvailableMaterials('inlay'); ``` `usage` is optional and accepts `'band'`, `'inlay'`, `'overlay'`, or `'sleeve'`. A material with no `usage` list is returned for every role. **Returns:** `MaterialEntry[]` ### `getAvailableVariants(baseId)` Returns the qualities or subcategories for one base material. ```javascript const variants = api.getAvailableVariants('yellow'); // [{ id: '14k', name: '14k', files: { polished: '...' } }, ...] ``` **Returns:** `MaterialVariant[]` ### `getAvailableFinishesFor(baseId)` Returns only the finishes supported by a base material. It returns an empty array when that material has no finish axis. ```javascript const goldFinishes = api.getAvailableFinishesFor('yellow'); const woodFinishes = api.getAvailableFinishesFor('wood'); // [] ``` **Returns:** `{ id: string; name: string; iconUrl?: string }[]` ### `getAvailableFinishes()` Returns the complete top-level finish display catalog. Prefer `getAvailableFinishesFor(baseId)` for a material picker, because one material can support only part of this list. ```javascript const finishes = api.getAvailableFinishes(); // [{ id: 'polished', name: 'Polished', thumbnail: '...' }, ...] ``` **Returns:** `{ id: string; name: string; thumbnail?: string; iconUrl?: string }[]` ### `getAvailablePartitions()` ```javascript const partitions = api.getAvailablePartitions(); // ['1 Color', '2 Color', '3 Color'] ``` **Returns:** `string[]` ### `getAvailableSettingTypes()` ```javascript const settings = api.getAvailableSettingTypes(); // [{ id: 'none', name: 'None', iconKey: 'no-diamonds' }, ...] ``` **Returns:** `{ id: string; name: string; iconKey?: string }[]` Use `option.id` when calling a setter and `option.name` for the visible label: ```javascript settings.forEach((option) => { const button = document.createElement('button'); button.textContent = option.name; button.onclick = () => option.id === 'none' ? api.setDiamonds(null) : api.setDiamonds({ settingType: option.id }); }); ``` ### `getAvailableEdgeTypes()` ```javascript const edges = api.getAvailableEdgeTypes(); // [{ id: 'None', name: 'None' }, { id: 'Beveled', name: 'Beveled' }, ...] ``` **Returns:** `{ id: string; name: string }[]` ### `getAvailableEdgeSides()` ```javascript const sides = api.getAvailableEdgeSides(); // [{ id: 'Left', name: 'Left' }, { id: 'Both', name: 'Both' }, ...] ``` **Returns:** `{ id: string; name: string }[]` ### `getAvailableDiamondSpans()` ```javascript const spans = api.getAvailableDiamondSpans(); // [{ id: 'half', name: '1/2', fraction: 0.5 }, ...] ``` **Returns:** `{ id: string; name: string; fraction: number | string }[]` ### `getAvailableDiamondSpacings()` ```javascript const spacings = api.getAvailableDiamondSpacings(); // [{ id: 'half-stone', name: '1/2 Stone', value: 1.5 }, ...] ``` **Returns:** `{ id: string; name: string; value: number | string }[]` ### `getDiamondSpanFraction(span)` Returns the numeric or manifest-defined fraction for a diamond span ID. **Returns:** `number | string` ### `getDiamondSpacingValue(spacing)` Returns the numeric or manifest-defined value for a diamond spacing ID. **Returns:** `number | string` ### `getAvailablePositionSnaps()` **Returns:** `{ name: string; value: number }[]` ### `getEngravingFonts()` Returns the project-defined engraving fonts, or the built-in font catalog when the manifest does not override it. **Returns:** `string[]` ### `getEngravingSymbols()` Returns the symbols offered by the built-in engraving UI. ```javascript const symbols = api.getEngravingSymbols(); // [{ title: 'Heart', char: '♥' }, ...] ``` **Returns:** `{ title: string; char: string }[]` ### `getEngravingDefaults()` Returns the resolved project defaults used when a band has no explicit engraving font, size, or rotation. **Returns:** `{ font: string; fontSize: number; rotation: number }` ### `getEngravingVOffset(profileIndex, partition)` Returns a profile-specific vertical engraving offset from the manifest, or `undefined` when the engine should calculate the inner-surface center. ```javascript const offset = api.getEngravingVOffset(0, '1 Color'); ``` **Returns:** `number | undefined` ### `getLimits()` Returns the manifest-driven numeric ranges used by the controller. Use these values for sliders instead of hard-coding ranges. ```javascript const limits = api.getLimits(); widthSlider.min = limits.width.min; widthSlider.max = limits.width.max; widthSlider.step = limits.width.step || 0.05; ``` **Returns:** an object containing `{ min, max, step? }` ranges for width, height, radius, stone size, diamond count and position, engraving, and wavy groove controls. ### `getAvailableThemes()` ```javascript const themes = api.getAvailableThemes(); // ['default', 'luxury-gold', 'modern-minimal', 'dark', 'rose-elegant', // 'coral-modern', 'fresh-teal', 'minimal-blue', 'warm-beige', 'classic-gold', 'ijewel'] ``` **Returns:** [`ThemePresetName[]`](#themepresetname) ### `getAvailablePaths()` Returns the extrusion paths, which are the band centerline shapes. The list holds the built-in circular path plus every manifest entry, with icon URLs already resolved. ```javascript const paths = api.getAvailablePaths(); // [{ id: 'circular', name: 'Classic' }, { id: 'wave', name: 'Wave', iconUrl: '...' }] ``` **Returns:** `{ id: string; name: string; iconUrl?: string }[]` ### `getAvailableDivisionTypes(bandName?)` Returns the color-division orientations the band can use. An entry with `partitionCount` suits exactly one partition count. **Returns:** `{ id: string; name: string; iconUrl?: string; partitionCount?: number }[]` ### `getAvailableGrooveTypes()` Returns the groove cross sections. `type` names the engine groove, and `angle` carries the opening angle of a V groove. **Returns:** `{ id: string; name: string; iconUrl?: string; type?: 'square' | 'v' | 'u' | 'convex-u' | 'milgrain' | 'milgrain2'; angle?: number }[]` ### `getAvailableGrooveFinishes()` Returns the interior finishes a groove or joint can take. **Returns:** `{ id: string; name: string; iconUrl?: string }[]` ### `getAvailableGrooveDirections()` Returns the groove directions, which run around the ring or across the band. **Returns:** `{ id: string; name: string; iconUrl?: string }[]` ### `getAvailableSideEdgeTypes()` Returns the treatments an independent left or right edge can take. **Returns:** `{ id: string; name: string; iconUrl?: string }[]` ### `getAvailableEyeOrientations()` Returns the eye-setting orientations. Each entry carries the numeric `value` the engine applies. **Returns:** `{ id: string; name: string; iconUrl?: string; value: number }[]` ### `getAvailableRingTypes()` Returns the ring types a compilation accepts. **Returns:** `{ id: 'wedding' | 'memoire' | 'engagement'; name: string; iconUrl?: string }[]` ### `getAvailableSideSettingOptions(bandName?)` Returns the side-setting catalog from the manifest, already filtered by compatibility with the current profile. **Returns:** `{ id: string; name: string; iconKey?: string }[]` ### `getAvailableSettingTypeIds(bandName?)` / `getAvailableEdgeTypeIds()` Return plain id lists, for integrations that do not need the catalog metadata. **Returns:** `string[]` ### `getRelationshipPresets(partitionOrCount?)` Returns the named segment-width ratios offered for a partition, such as 2:1:1. **Returns:** `{ name: string; ratios: number[] }[]` ### `getFreeStonePresetOptions()` Returns the curated free-stone patterns, each with the stones it places. **Returns:** `{ id: string; name: string; stones: FreeStone[]; iconUrl?: string }[]` ### `getDiamondColors()` / `getDefaultDiamondColor()` `getDiamondColors()` returns the stone colors whose material loaded from the manifest. `getDefaultDiamondColor()` returns the color a stone takes when it names none, which is the first catalog entry. It returns an empty string when no color loaded, and stones then keep the material of the diamond model. **Returns:** `{ id: string; name: string; swatch?: string; iconUrl?: string }[]` / `string` ### `getRingSizes()` / `getRingSizeSystems()` `getRingSizes()` returns the standard size catalog that every size control and the spec sheet resolve against. A formula drifts from it by up to half a size, so a UI that offers sizes must offer these. `getRingSizeSystems()` returns the systems this build can label a ring in. **Returns:** `readonly RingSizeEntry[]` / `readonly RingSizeSystem[]` ## Write Methods All write methods accept an optional `bandName` parameter (`'her'` or `'his'`). If omitted, the currently active band is used. ### `setLogLevel(level)` Set the minimum log level. Messages below this level are suppressed. ```javascript api.setLogLevel('info'); // show everything api.setLogLevel('warn'); // errors + warnings (default) api.setLogLevel('error'); // errors only api.setLogLevel('silent'); // suppress all output and events ``` | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `level` | `LogLevel` | `'warn'` | Minimum severity to emit | **Returns:** `void` ### `setWidthMm(mm, bandName?)` Sets the band width in absolute millimeters, clamped to the product range (1.5–10 mm). The value is stored internally as a profile-relative multiplier (mm ÷ the profile's natural width). Changing the width reconciles the height against the manufacturer rules — the optimal thickness when auto-optimal height is enabled, otherwise a clamp to the manufacturable range. Out-of-range values are clamped and emit `validation:warning`. ```javascript api.setWidthMm(4.4); // band is now 4.4 mm wide ``` **Returns:** `void` ### `setHeightMm(mm, bandName?)` Sets the band thickness (height) in absolute millimeters, clamped to the manufacturable range — the manufacturer possibility rule for the active profile + width when one exists, else the profile's natural height × 0.5–1.5. ```javascript api.setHeightMm(1.8); ``` **Returns:** `void` ### `setWidthMultiplier(multiplier, bandName?)` / `setHeightMultiplier(multiplier, bandName?)` Set width or height as a profile-relative multiplier: `1.0` = the active profile's natural dimension. Width is bounded by the same 1.5–10 mm product range as `setWidthMm`; height by 0.5–1.5. Changing the width reconciles the height as above. ```javascript api.setWidthMultiplier(1.1); // 110% of the source profile width api.setHeightMultiplier(0.95); ``` **Returns:** `void` ### `setWidth(multiplier, bandName?)` / `setHeight(multiplier, bandName?)` Deprecated aliases of `setWidthMultiplier` / `setHeightMultiplier`. Despite the historical names, the argument is a **multiplier, not millimeters**. Calling them logs a deprecation warning; use `setWidthMultiplier()`/`setHeightMultiplier()` or `setWidthMm()`/`setHeightMm()` instead. Note there is no `setRingSizeMm()`: [`setRingSize()`](#setringsize-radiusmm-bandname) already takes the inner radius in millimeters. **Returns:** `void` ### `setRingSize(radiusMm, bandName?)` Sets the ring's inner radius in millimeters. If your UI works with inner diameter, divide the diameter by two before calling this method. ```javascript api.setRingSize(8.5); // 17 mm inner diameter api.setRingSize(10, 'his'); ``` The value is clamped to `getLimits().radius`. **Returns:** `void` ### `setProfile(indexOrName, bandName?)` Sets the ring profile by index or name. Returns a promise because the profile geometry needs to be loaded. ```javascript await api.setProfile(0); // by index await api.setProfile('Flat'); // by name ``` **Returns:** `Promise` ::: warning `setProfile()` is async. Always await it before reading dimensions or other state that depends on the new geometry: ```javascript await api.setProfile(0); const dims = api.getDimensions(); // safe, new geometry is loaded ``` Without the await, you may read stale dimensions from the previous profile. ::: ### `setMaterial(slot, metal, finish, bandName?)` Sets the base material and finish for a specific slot. It does not select a variant. Use `setMaterialRef()` for new interfaces. ```javascript await api.setMaterial(1, 'Yellow', 'Polished'); // Slot 1 await api.setMaterial(2, 'White', 'Hammered'); // Slot 2 await api.setMaterial(3, 'Rose', 'Brush'); // Slot 3 ``` | Parameter | Type | Description | |-----------|------|-------------| | `slot` | `number` | One-based material slot number | | `metal` | `string` | Base material ID or accepted display name | | `finish` | `string` | Finish ID or accepted display name | **Returns:** `Promise` ### `setMaterialRef(slot, ref, bandName?)` Sets a full base, variant, and finish reference for one material slot. ```javascript await api.setMaterialRef(1, { base: 'yellow', variant: '18k', finish: 'polished', }); ``` Omitted `variant` and `finish` values keep the current slot values. When the base changes, the controller clears a stale finish for a finishless material. It otherwise replaces an unsupported finish with `polished` or the first available finish. A variant the new base material does not offer is dropped — the slot falls back to that material's default and a `validation:warning` names the variants it could have had. **Returns:** `Promise` ### `setPartition(numColors, bandName?)` Sets the number of material color zones. ```javascript await api.setPartition(2); // 2-color band ``` | Parameter | Type | Description | |-----------|------|-------------| | `numColors` | `number` | Number of material zones supported by a manifest preset | **Returns:** `Promise` ### `setPartitionByName(presetName, bandName?)` Applies an exact partition preset from `getAvailablePartitions()`. Use this instead of `setPartition()` for named layouts such as `2 Color Vertical`. ```javascript const preset = api.getAvailablePartitions()[0]; await api.setPartitionByName(preset); ``` **Returns:** `Promise` ### `setDiamonds(config, bandName?)` Configures diamond settings. Accepts a partial [`DiamondSnapshot`](#diamondsnapshot) — only the fields you pass are changed. Pass `null` to remove diamonds. ```javascript api.setDiamonds({ settingType: 'Channel', span: 'half', spacing: 'half-stone', count: 12, stoneSize: 1.5, // 0.5–3.0 }); // A row of stones across the band at 45° api.setDiamonds({ settingType: 'Cross Bezel', count: 4, positionAngle: 45 }); // Tension setting with two stones and a custom bridge width api.setDiamonds({ settingType: 'Tension', count: 2, bridgeWidth: 2.4 }); // Remove diamonds api.setDiamonds(null); ``` Available `settingType` values: `Channel`, `Channel All Around`, `Bezel`, `Prong`, `Cross Bezel`, `Cross Channel`, `Cross Around`, `Tension`, `Tension Diagonal`, `Eye`, `Free` (use `getAvailableSettingTypes()` — some depend on the profile). Type-specific options: `positionAngle` (cross, tension, eye — degrees around the ring), `bridgeWidth` (tension), `eyeOrient` (eye — 0, 90, ±45), `freeStones` (free placement). Side-face settings have their own API — see [Side stone settings](#side-stone-settings). **Returns:** `void` #### Diamond size Stone size is the `stoneSize` field. Update it on its own by passing only that field: ```javascript api.setDiamonds({ stoneSize: 2.0 }); // 0.5–3.0 ``` #### Diamond position Position along the ring's width is the `position` field. It is automatically clamped based on band width, diamond size, and groove width to keep diamonds inside the ring: ```javascript api.setDiamonds({ position: -1 }); // Left api.setDiamonds({ position: 0 }); // Center (default) api.setDiamonds({ position: 1 }); // Right api.setDiamonds({ position: 0.5 }); // Between center and right ``` | Field | Type | Description | |-----------|------|-------------| | `position` | `number` | Position from `-1` (left) to `1` (right), `0` = center | ::: info Diamond position is automatically reset to center (`0`) when wavy grooves are enabled. ::: ### `setEdge(type, side?, bandName?)` Sets the edge treatment. ```javascript api.setEdge('Beveled', 'Both'); api.setEdge('None'); // Remove edge ``` | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `type` | `string` | | Edge type (see `getAvailableEdgeTypes()`) | | `side` | `string` | current | Side ID from `getAvailableEdgeSides()` (`'Left'`, `'Right'`, or `'Both'`) | **Returns:** `void` ### `setEngraving(text, font?, fontSize?, bandName?, rotation?)` Sets the interior engraving text. Pass `null` to remove. ```javascript api.setEngraving('Forever & Always', 'serif', 80); // Remove engraving api.setEngraving(null); ``` | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `text` | `string \| null` | | Engraving text, or `null` to remove | | `font` | `string` | current | Font family name | | `fontSize` | `number` | current | Font size in pixels | | `bandName` | `string` | active band | Registered band name | | `rotation` | `number` | current | Engraving rotation, clamped to the manifest limit | **Returns:** `void` ### `setInsidePolished(value, bandName?)` Toggles whether the ring interior is polished. ```javascript await api.setInsidePolished(true); ``` **Returns:** `Promise` ### `setPath(pathId, bandName?)` Sets the extrusion path, which is the band centerline shape. `circular` is the built-in default, and other ids come from the manifest path registry. A custom path drops the settings that need a circular band — the Tension, Eye and Side family — and drops engraving. Regular stone settings ride the path. ```javascript await api.setPath('wave'); ``` **Returns:** `Promise` ### `setPathStrength(strength, bandName?)` Sets the path displacement strength. `1` gives the full wave, and `0` matches the classic band. **Returns:** `void` ### `setWaveParams(params, bandName?)` Sets the frequency and amplitude of the built-in wave path. Frequency is an integer from 2 to 6. Amplitude is a fraction of the radius, and the engine clamps it by the slope rule `amplitude x frequency <= 0.7`. Both values apply only while the `wave` path is active. ```javascript await api.setWaveParams({ frequency: 4, amplitude: 0.12 }); ``` **Returns:** `Promise` ### `setRelationship(ratio, bandName?)` Sets the width ratio between color segments. The ratio length must equal the current partition count. Pass `null` to return to a uniform split. ```javascript await api.setRelationship([2, 1, 1]); ``` **Returns:** `Promise` ### `setRingSizeByStandard(system, size, bandName?)` Sets the ring size by its standard designation. The value resolves through the size table, so the band lands on an exact standard radius rather than on a formula's approximation. An unknown designation is refused with a `validation:warning` event. ```javascript api.setRingSizeByStandard('US', 7); api.setRingSizeByStandard('UK', 'N½'); ``` **Returns:** `void` ### `setAutoOptimalHeight(on, bandName?)` Turns on automatic thickness. The band then takes the manufacturer's optimal height for its width whenever the width changes. Turning it on applies the optimal height immediately. **Returns:** `void` ### `setEdgeSide(side, cfg, bandName?)` Configures one edge independently. Pass `'left'` or `'right'` and any of `type`, `width`, `depth` and `finish`. An edge that turns on takes a polished finish unless the call names another. ```javascript api.setEdgeSide('left', { type: 'Edge', width: 0.3, depth: 0.2, finish: 'matt' }); ``` **Returns:** `void` ### `setMilgrain(cfg, bandName?)` Sets the band-wide milgrain bead style: the bead type, its size, and its spacing. Milgrain turns on per host, through an edge of type `Milgrain` or a groove or joint of type `milgrain`, never through this call. Legacy `enabled`, `onEdges` and `onGrooves` inputs are accepted and ignored. ```javascript api.setMilgrain({ beadType: 'round', sizeMm: 0.18, spacingFactor: 1.1 }); ``` **Returns:** `void` ### `setEngravingStyle(color?, roughness?, bandName?, bumpOnly?, bumpScale?, mode?, bump?)` Sets the appearance of the engraved marks. `color` is a diffuse tint multiplied into the metal color, and `'#ffffff'` or `null` means no tint. `roughness` runs from `0`, which stays polished, to `1`, which is fully matte. `bumpOnly` gives pure relief with no roughness or tint. `bumpScale` is in engine units, and a negative value embosses. ```javascript await api.setEngravingStyle('#ffffff', 0.6, undefined, false, 0.4, 'engrave'); ``` **Returns:** `Promise` ### `setInnerStone(cfg, bandName?)` Sets the hidden stone, which is a single flush or bezel-set stone in the bore next to the engraving. Its position is an explicit angle in degrees around the ring, independent of where the engraving text sits. Pass `enabled: false` to remove it. ```javascript await api.setInnerStone({ enabled: true, angleDeg: 180, stoneSize: 1.2 }); ``` **Returns:** `Promise` ### `setDiamondColor(colorId, bandName?)` Sets the stone color for one band. His and her rings keep independent colors even though they share the diamond model. Pass `null` to restore the material of the model. **Returns:** `void` ### `setParallaxEnabled(enabled)` Turns relief parallax mapping on or off. The extension applies to every material with a bump map, which covers engraving and bump finishes such as brush, so the setting is viewer-wide rather than per band. **Returns:** `void` ## Outside and Inside Material Features Inlays and overlays paint regions on the outer surface. A sleeve paints the inside bore. These features change material assignment only; they do not add solid geometry or change weight. They render only on a circular path with a plain vertical-style material division. Axial, diagonal, and wavy divisions do not support them. Use `areOutsideFeaturesAvailable()` before showing custom controls. ### `setOutsideFeatures(features, bandName?)` Replaces all inlays and overlays in one rebuild. Use this method when several features change together to avoid rendering intermediate states. ```javascript await api.setOutsideFeatures({ inlays: [ { centerZ: 0, widthMm: 1.2, metal: 'wood', variant: 'koa' }, ], overlays: [ { side: 'left', widthMm: 0.8, metal: 'rose', variant: '18k', finish: 'polished', rimCoverage: 0.5, }, ], sleeve: { enabled: true, metal: 'yellow', variant: '18k', finish: 'polished', full: true, }, }); ``` The `inlays` and `overlays` arrays replace their current arrays. Omitted arrays therefore clear those feature types. Omit `sleeve` to preserve the current sleeve, or pass `sleeve: null` to remove it. The controller accepts up to three inlays and one overlay on each rim. It clamps feature widths and positions to prevent overlap and edge overflow. **Returns:** `Promise` ### `setInlay(index, inlay, bandName?)` Adds an inlay at the next index or updates an existing inlay. `centerZ` is the stripe center in millimeters from the band's center width. `widthMm` is the stripe width. ```javascript await api.setInlay(0, { centerZ: 0, widthMm: 1, metal: 'marble', variant: '1', }); ``` The controller keeps inlays sorted by `centerZ`. An index is not a stable identifier after a move. Read `getInlays()` again after each update. **Returns:** `Promise` ### `removeInlay(index, bandName?)` / `getInlays(bandName?)` Removes one inlay or returns copies of all current inlay configurations. ```javascript await api.removeInlay(0); const inlays = api.getInlays(); ``` **Returns:** `Promise` / `InlayConfig[]` ### `getInlayBounds(index, bandName?)` Returns the legal center range and maximum width for an inlay. Re-read these bounds after any band-width, inlay, or overlay change. ```javascript const { centerMin, centerMax, widthMax } = api.getInlayBounds(0); ``` **Returns:** `{ centerMin: number; centerMax: number; widthMax: number }` ### `setOverlay(side, overlay, bandName?)` Adds or updates the overlay anchored to the left or right rim. Only one overlay can exist on each side. ```javascript await api.setOverlay('right', { widthMm: 1, metal: 'white', variant: '18k', finish: 'brush', rimCoverage: 1, }); ``` `rimCoverage` controls how far the material reaches down the flat rim face. Use `0` for none, `1` for the complete face, or an intermediate fraction. `rimCoverage` takes precedence over the older `coversRim` boolean. **Returns:** `Promise` ### `removeOverlay(side, bandName?)` / `getOverlays(bandName?)` Removes one rim overlay or returns copies of all overlay configurations. **Returns:** `Promise` / `OverlayConfig[]` ### `getOverlayWidthMax(side, bandName?)` Returns the largest permitted overlay width for one side after accounting for the band width, other overlays, and inlays. **Returns:** `number` ### `setSleeve(sleeve, bandName?)` / `getSleeve(bandName?)` Sets the material on the inside bore. Pass a boolean to change only the enabled state. A full sleeve covers the complete bore. A partial sleeve is centered and uses `widthMm`. ```javascript await api.setSleeve({ enabled: true, metal: 'yellow', variant: '18k', finish: 'polished', full: false, widthMm: 3, }); const sleeve = api.getSleeve(); ``` Changing the sleeve reapplies interior engraving against the new bore material. **Returns:** `Promise` / `SleeveConfig | undefined` ### `areOutsideFeaturesAvailable(bandName?)` Returns `true` when the current path and division can render inlays, overlays, and a sleeve. **Returns:** `boolean` ### `outsideFeaturesFit(bandName?)` Returns `false` when the current inlay and overlay set overlaps or exceeds the band width. Public setters clamp invalid dimensions, but this method is useful when validating imported state. **Returns:** `boolean` ### `setSplitAtGroove(value, bandName?)` Toggles whether material splits align to grooves. ```javascript await api.setSplitAtGroove(true); ``` **Returns:** `Promise` ### `setWavyGrooves(enabled, frequency?, amplitude?, wavySplit?, bandName?)` Enables or disables wavy groove patterns. ```javascript api.setWavyGrooves(true, 8, 0.3); // Enable with frequency 8, amplitude 0.3 api.setWavyGrooves(true, 8, 0.3, true); // Also split/separate the wave api.setWavyGrooves(false); // Disable ``` | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `enabled` | `boolean` | | Enable or disable wavy grooves | | `frequency` | `number` | current | Wave frequency | | `amplitude` | `number` | current | Wave amplitude | | `wavySplit` | `boolean` | current | Enable separation along the wavy groove | | `bandName` | `string` | active band | Registered band name | **Returns:** `void` ::: info Enabling wavy grooves automatically resets the diamond position to center (`0`), since offset diamond positions are not supported with wavy grooves. ::: ### Division methods - `setDivision(division, bandName?)` - `setDivisionParams(frequency?, amplitude?, bandName?)` - `setDivisionParams(params, bandName?)` - `getDivision(bandName?)` Sets how the color zones separate: `'vertical'`, `'axial'`, `'diagonal'`, or `'wavy'`. `setDivisionParams` adjusts the wavy/diagonal boundary. `frequency` is the number of wave periods around the band and applies to `'wavy'` only; `amplitude` (0–1) is the boundary excursion and applies to both `'wavy'` and `'diagonal'`. ```javascript await api.setDivision('wavy'); await api.setDivisionParams(4, 0.4); // frequency, amplitude // Object form, supported by Mini Viewer 0.6.18 and later. await api.setDivisionParams({ frequency: 4, amplitude: 0.4 }); ``` ::: tip Mini Viewer `0.6.18` and later accept both call shapes. On an older viewer, use the positional form. ::: ### `setSegmentWidthsMm(widths, bandName?)` / `getSegmentWidthsMm(bandName?)` Per-zone widths in millimeters for multi-color partitions (e.g. a 2:1:1 split). ### `setSeparationGroove(cfg, bandName?)` / `getSeparationGroove(bandName?)` Configures the joint groove on color boundaries: `{ enabled?, type?, width?, depth?, angle?, finish?, boundaries? }`. `boundaries` is a per-boundary enable array (disc 1–2, 2–3, ...). Works on straight, diagonal, and wavy divisions alike. ```javascript api.setSeparationGroove({ type: 'v', angle: 60, depth: 0.15 }); api.setSeparationGroove({ enabled: false }); // clean grooveless seam ``` ### Design grooves Freely placed decorative grooves: `getDesignGrooves()`, `addDesignGroove(groove?)`, `updateDesignGroove(index, changes)`, `removeDesignGroove(index?)`, `clearDesignGrooves()`. Each groove: `{ type, width, depth, position, angle?, finish?, orientation?, positionAngle? }` — `orientation: 'horizontal'` runs the groove across the band at `positionAngle` degrees. ### Side stone settings Stones on the band's flat side faces, independent of the top setting: - `setSideSetting(type, bandName?)` / `getSideSetting(bandName?)` — `'none'`, `'Side Bezel'`, `'Side Channel'`, `'Side Prong'` - `getAvailableSideSettingTypes(bandName?)` — filtered by profile compatibility (side settings need a flat side face) - `setSideBezelSides(sides, sourceSide?, bandName?)` — `'left'`, `'right'`, or `'both'`; newly enabled sides clone from `sourceSide` - `setSideBezelSide(side, config, bandName?)` — per-side span / count / spacing / stone size - `copySideBezelSide(from, bandName?)` — copy one side's settings to the other - `getSideBezel(bandName?)` — full per-side state including computed stone counts ### Free stone placement The `'Free'` setting type places individual bezel stones anywhere on the band: - `getFreeStones()` / `setFreeStones(stones)` — each stone: `{ angleDeg, offset, size }` (`offset` −1..1 across the band) - `addFreeStone(size?)`, `updateFreeStone(index, changes)`, `removeFreeStone(index)`, `clearFreeStones()` - `applyFreeStonePreset(name)` / `getFreeStonePresets()` — Scatter, Orbit, Cascade, Constellation, Wave ### `setSmoothSeats(on, bandName?)` / `getSmoothSeats(bandName?)` Switches bezel-style settings (Bezel, Cross Bezel, Free, Side Bezel) between classic sharp-rim pockets and smooth scooped seats that blend tangentially into the surface. ## History The builder records every configuration change, so a UI can offer undo and redo without tracking state itself. ### `undo()` / `redo()` Step back or forward by exactly one change. Calls queue, so rapid presses walk the history instead of collapsing into one step. `redo()` returns `false` when nothing was undone. ```javascript if (api.canUndo()) await api.undo(); ``` **Returns:** `Promise` ### `canUndo()` / `canRedo()` Report whether a step exists in each direction. The `history:changed` event fires whenever either answer changes. **Returns:** `boolean` ## Saved Configurations A saved configuration is a complete ring design under a short readable id, such as `WB-BA5A-DZ58`, with a viewer snapshot as its thumbnail. Storage is `localStorage` until you supply somewhere else to put it. That is the right default for a shopper, whose designs never need to leave their browser. To make one project's designs appear in every embed of it, on any device, give the viewer a project catalogue host — see [The project design catalogue](#the-project-design-catalogue) below. To hand a shopper a link that carries their design with no storage at all, see [Design Links](#design-links). ### `saveConfiguration(name?)` Saves the current configuration and returns its id and name, or `null` when the save fails. ```javascript const saved = await api.saveConfiguration('Emma and Tom'); ``` **Returns:** `Promise<{ id: string; name: string } | null>` ### `loadConfiguration(id)` Loads a saved configuration. Returns `false` when the id is unknown. **Returns:** `Promise` ### `listConfigurations()` Returns the saved configurations, newest first, with id, name, date and thumbnail. **Returns:** `Promise` ### `deleteConfiguration(id)` Deletes one saved configuration. **Returns:** `Promise` ### `setConfigStorageAdapter(adapter)` Replaces the persistence backend, so saved designs can live in your own REST service or in host-supplied storage instead of `localStorage`. ```javascript api.setConfigStorageAdapter({ async list() { /* … */ }, async save(record) { /* … */ }, async load(id) { /* … */ }, async remove(id) { /* … */ }, }); ``` **Returns:** `void` ### The project design catalogue Saved designs can live in the project instead of the browser. A design saved once then appears in every embed of that project, on any device. This is a viewer option, not an API call. Set `wbbDesignHost` when you create the viewer. Mini Viewer installs it on the builder for you. ```javascript new ijewelViewer.Viewer(container, project, { wbbDesignHost: { // Write the whole catalogue and return its public URL. async save(designs) { return myBackend.putProjectFile('saved-designs.json', designs); }, // Optional, but recommended. See the note below. async list() { return myBackend.getProjectFile('saved-designs.json'); }, }, }); ``` Omit the option to keep saving to `localStorage`. `save` receives the complete catalogue and rewrites it whole, so the URL it returns must serve exactly what it was given. The file has to be publicly readable: a shopper reads it without signing in. Implement `list` if two people can save to the same project. Every save writes a new file at a new URL, so a viewer that loaded before someone else's save holds a stale catalogue. `list` re-reads the current one first, and without it that save would drop the other person's designs. When the host is unavailable, saving falls back to `localStorage` rather than failing. A catalogue that cannot be read is never replaced with an empty one. ::: warning Same-page integrations only `wbbDesignHost` holds functions, so it cannot cross the postMessage bridge. A cross-origin iframe host must set it inside the iframe page. The same limit applies to [`setConfigStorageAdapter()`](#setconfigstorageadapter-adapter). ::: See [ViewerOptions](../viewer/viewer-class#vieweroptions) for the full option list. ## Design Links A design link carries the whole design in the URL. Nothing is written to a server, so there is no record to keep and nothing to clean up. Use it for a share button, or to put a design in a product field on your own storefront. Only the restorable part travels — the bands, their pricing, and the ring compilation. The manifest and the thumbnail do not, so a typical design compresses to roughly 500 characters. ### `getDesignCode()` The current design as a compact code, with no link around it. Use it when you want to keep the design in your own field, such as a line on an order. ```javascript const code = await api.getDesignCode(); // Store it on the order, then restore it later with applyDesignLink(code). ``` Returns `null` when there is no band state to share. **Returns:** `Promise` ### `getShareUrl()` A ready link to the current design, with the code in the URL fragment. ```javascript const url = await api.getShareUrl(); await navigator.clipboard.writeText(url); ``` The code goes in the fragment on purpose. A fragment never reaches a server log, which matters because a design can carry engraving text, and it avoids proxy limits on query-string length. Any route or query already in the address is kept, so a storefront path such as `https://shop.example/#/product/42` survives being shared. Returns `null` when there is no design to share, or no address to build on. **Returns:** `Promise` ### `setShareBaseUrl(url)` Sets the address `getShareUrl()` builds on. ```javascript api.setShareBaseUrl('https://shop.example/#/product/42'); ``` Needed inside a cross-origin iframe, where the builder cannot read the storefront's address and would otherwise build a link to the iframe itself. **Returns:** `void` ### `applyDesignLink(text)` Restores a design. Accepts a bare code, a `?design=` URL, or a `#?design=` URL, so you can pass whatever the shopper pasted. ```javascript const restored = await api.applyDesignLink(window.location.href); if (!restored) { // The text carried no readable design, or none of its rings exist here. } ``` Returns `false`, and emits a `validation:warning`, when the text holds no readable design or when none of its bands exist in this project. A design made against a different manifest is still applied, with a warning, since the same catalogue served from another URL is normal between staging and production. This is also the only way a cross-origin host can restore an exact design. The postMessage bridge can call `toJSON()` but not the plugin's `fromJSON()`. **Returns:** `Promise` ## Manufacturing Export ### `exportManufacturing(config?)` Returns manufacturing data in the metrix and confmetrix format: per-zone volumes and weights, grooves, the stone layout, and hallmark engraving. Pass a partial config to override the client vocabulary, such as alloy names or profile ids. Use this for a production handoff. Use `getSpecSheetData()` for the readable summary, and `api.toJSON()` for restorable state. ```javascript const rows = api.exportManufacturing(); ``` **Returns:** `any[]` ## Band Linking ### `setBandsLinked(linked)` / `isBandsLinked()` Link or unlink the wedding bands, overriding `ui.linkBands` in the manifest. Linking records the state of every band and changes none of them, so only later edits mirror across. Ring size and engraving stay personal. **Returns:** `void` / `boolean` ## Bead Library The milgrain bead designer stores custom beads in `localStorage` alongside the built-in presets. ### `getBeadTypes()` Returns the built-in bead presets plus the saved beads of this user. A saved entry carries `custom: true`. **Returns:** `{ id: string; name: string; params: MilgrainBeadParams; custom?: boolean }[]` ### `saveBeadType(name, params)` / `deleteBeadType(id)` Save a bead into the library and return its id, or delete one by id. **Returns:** `string` / `void` ### `createBeadPreview(canvas)` Attaches a live 3D bead preview to a canvas. The preview uses polished white metal under the same HDR environment as the builder viewer. Call `dispose()` when the modal closes. The renderer holds GPU resources until you do. ```javascript const preview = api.createBeadPreview(canvasEl); preview.update(params); preview.render(); // later preview.dispose(); ``` **Returns:** `BeadPreviewRenderer` — `{ update(params), render(), dispose() }` ## Plugin Serialization (Advanced) The controller's `toJSON()` delegates to the `WeddingBandBuilderPlugin` and returns complete project/plugin state. Full restoration uses the plugin's `fromJSON()` method. This format preserves raw band states, including material variants and outside/inside features. ### `toJSON()` Exports the complete plugin state as a JSON-serializable object. Includes the manifest URL, all band states, and pricing configuration. ```javascript const plugin = viewer.getPluginByType('WeddingBandBuilder'); const data = api.toJSON(); // equivalent to plugin.toJSON() // Save or transmit the configuration localStorage.setItem('wbb-state', JSON.stringify(data)); ``` **Returns:** `{ type, manifestUrl? or inline manifest fields, bands?, pricing?, rings? }` ### `fromJSON(data)` Restores plugin state from a previously exported JSON object. If bands are already loaded, it applies states in-place without recreating geometry. If the plugin hasn't been initialized yet, it performs a full cold load. ```javascript const plugin = viewer.getPluginByType('WeddingBandBuilder'); const saved = JSON.parse(localStorage.getItem('wbb-state')); await plugin.fromJSON(saved); ``` **Returns:** the plugin instance (or a promise resolving after cold loading) ::: info Cross-origin restoration The postMessage bridge can call controller `toJSON()`, but it cannot call the plugin-only `fromJSON()` method. A cross-origin iframe must load full saved state inside its viewer page or expose an application-specific restore command. ::: ## Batch Operations ### `batch(config, bandName?)` Apply multiple changes in a single operation. This is more efficient than calling individual setters because it triggers only one geometry rebuild. ```javascript await api.batch({ profile: { name: 'D-Shape' }, dimensions: { widthMm: 1.1, heightMm: 0.95 }, materials: { partition: 2, slots: [ { slot: 1, metal: 'White', finish: 'Polished' }, { slot: 2, metal: 'Yellow', finish: 'Hammered' }, ], insidePolished: true, splitAtGroove: true, }, diamonds: { settingType: 'Channel', span: 'half', spacing: 'half-stone', count: 12, stoneSize: 1.5, }, edge: { type: 'Beveled', side: 'Both' }, engraving: { text: 'Forever', font: 'serif' }, pricing: { metalPricePerGram: 52.0, markupMultiplier: 2.5, }, }); ``` All fields in `BatchConfig` are optional. Include only the sections you want to change. `batch().materials` applies the partition, the slots — base, variant and finish alike — inside polish, split state, inlays, overlays, and the sleeve. It touches only the keys the config names: an absent `inlays` or `overlays` list leaves the current one in place, and `sleeve: null` removes the sleeve while an absent `sleeve` key leaves it alone. **Returns:** `Promise` ### `importConfig(config)` Applies one [`BatchConfig`](#batchconfig) to each named band. A `RingSnapshot` is a valid `BatchConfig` after you remove its computed `pricing` value, as shown below. Bands the config does not name are left alone, and so is a name that is not registered in the project. ```javascript await api.importConfig({ her: { profile: { name: 'Comfort' }, dimensions: { widthMm: 0.9 }, materials: { partition: 1, slots: [{ slot: 1, metal: 'Rose', finish: 'Polished' }], }, }, his: { profile: { name: 'Flat' }, dimensions: { widthMm: 1.2 }, materials: { partition: 1, slots: [{ slot: 1, metal: 'White', finish: 'Brush' }], }, }, }); ``` ```javascript // Round-trip an order record. Drop the computed price first — see below. const order = api.exportConfig(); for (const band of Object.values(order)) delete band.pricing; await api.importConfig(order); ``` `importConfig()` restores the profile, dimensions, material slots with their variants, inlays, overlays, the sleeve, diamonds, edges, and engraving. ::: warning Remove `pricing` before you re-import `exportConfig()` writes a computed price breakdown into `pricing`. On the way in, that same key means the [`PricingParams`](#pricingparams) that produce a price. `importConfig()` merges what it finds there into the stored pricing parameters, so a raw round trip pollutes them. Delete `pricing` from each band first, as above. Then set the real values with `setPricingParams()`. ::: Use `plugin.fromJSON(savedPluginState)` when you need the exact internal state. **Returns:** `Promise` ### `applyBandState(bandName, state)` Applies a complete `BandState` to one band and resolves after the profile and material rebuilds finish. Use it to restore a state object you stored yourself. Mirroring is suspended for the duration, so a linked pair does not flatten one band's state onto the other. ```javascript await api.applyBandState('her', savedState); ``` **Returns:** `Promise` ## Navigation ### `switchBand(bandName)` Switches the active band between "her" and "his". ```javascript api.switchBand('his'); ``` **Returns:** `void` **Fires:** [`band:switched`](#event-reference) ::: warning Switching bands does not update your custom UI automatically. In headless mode, listen to `band:switched` and refresh all controls from the new band's snapshot: ```javascript api.events.on('band:switched', (data) => { const snapshot = api.getSnapshot(data.to); updateAllControls(snapshot); }); ``` ::: ## Ring Compilation Manage the set of rings in the scene: parametric wedding bands plus pre-modelled engagement and memoire rings from the [catalog](./assets-setup#ring-catalog). All changes fire [`rings:changed`](#event-reference). ### `getRings()` Returns the compilation in scene order. ```javascript api.getRings(); // [{ id: 'her', type: 'wedding', name: 'Her Ring' }, // { id: 'ring-3', type: 'engagement', name: 'Engagement 1', // catalogId: 'ring-1', metalId: 'white', visible: true }] ``` **Returns:** `{ id, type, name, catalogId?, metalId?, visible? }[]` ### `getRingCatalog(type)` Catalog entries available for a type, with resolved thumbnail URLs. ```javascript const models = api.getRingCatalog('engagement'); // [{ id: 'ring-1', name: 'Solitaire I', thumbnail: 'https://...' }, ...] ``` **Parameters:** `type` — `'engagement'` or `'memoire'` ### `addRing(type, catalogId?)` Adds a ring and returns its id. Wedding rings are new parametric bands; engagement/memoire load the given catalog model (first entry when omitted) with white gold applied. Async — resolves when the model is in the scene. ```javascript const id = await api.addRing('engagement', 'ring-2'); ``` ### `removeRing(id)` Removes a ring. The last remaining wedding band cannot be removed. ### `moveRing(id, direction)` Moves a ring one slot `'left'` or `'right'`; the 3D layout follows. ### `renameRing(id, name)` Sets the display name shown on the ring's tab and in the manager dialog. ### `swapRingModel(id, catalogId)` Swaps a loaded ring's model in place — same id, tab, name, slot, and metal. The current model stays visible until the replacement has loaded. Async. ### `setRingMetal(id, metalId)` / `getRingMetal(id)` Applies a metal variant (`'white'`, `'yellow'`, `'rose'`) to a loaded ring. Uses the same polished `.pmat` materials as the wedding bands, so colors match across the compilation. ### `setRingVisible(id, visible)` Shows or hides a ring without removing it (it keeps its slot). The camera re-frames the visible scene and shadows rebake. ### `focusRing(id)` Smoothly centers the camera on one ring, any type — the same fit `switchBand` performs for bands. ## Layout ### `getAvailableLayouts()` Returns the layout IDs registered by the active UI build. ```javascript console.log(api.getAvailableLayouts()); // ['panel', 'boutique', 'modern-metals'] ``` **Returns:** `string[]` ### `getLayout()` Returns the selected layout ID, or `null` when the UI should use its default. **Returns:** `string | null` ### `setLayout(id)` Switches to a registered layout and emits `layout:changed`. Unknown IDs are ignored and produce a `validation:warning` event. ```javascript api.setLayout('boutique'); ``` Changing layout affects presentation only. It does not add or remove rings. Drive-created Modern Metals projects are single-ring because Drive scaffolds their project state that way. **Returns:** `void` ### `registerLayouts(ids)` Declares the layout ids this UI build provides, so `getAvailableLayouts()` and `setLayout()` can validate against them. The bundled React UI calls this for you. A custom front end calls it only when it registers layouts of its own. ```javascript api.registerLayouts(['panel', 'boutique', 'modern-metals']); ``` **Returns:** `void` ## Theme ### `setTheme(theme)` Apply a preset theme or custom theme configuration. ```javascript // Preset api.setTheme('dark'); // Custom with preset base api.setTheme({ preset: 'luxury-gold', colors: { primary: '#8B7355' }, fonts: { body: "'Cormorant Garamond', serif", googleFonts: ['Cormorant+Garamond:wght@400;500;600'], }, panelWidth: 380, showPoses: true, showARButton: true, }); // Fully custom api.setTheme({ colors: { primary: '#2E5B3C', text: '#1a1a1a', background: '#F5F7F5', surface: '#ffffff', border: '#D4DDD4', }, }); ``` See [Theming](./integration-direct#theming) for full details. **Returns:** `void` ### `cycleTheme()` Cycles to the next preset theme. Useful for previewing themes. ```javascript const nextTheme = api.cycleTheme(); console.log(`Now using: ${nextTheme}`); ``` **Returns:** `ThemePresetName` (the name of the newly applied theme) ### `getThemeCSSVariables()` Returns the core CSS custom properties resolved from the active theme. This is useful when styling a specification sheet or host-page controls to match the built-in Wedding Band UI. ```javascript const variables = api.getThemeCSSVariables(); Object.entries(variables).forEach(([name, value]) => { document.documentElement.style.setProperty(name, value); }); ``` **Returns:** `Record` ## Pricing ### `setPricingParams(params, bandName?)` Override pricing parameters at runtime. ```javascript api.setPricingParams({ metalDensityGcm3: 15.5, metalPricePerGram: 52.0, diamondPricePerCarat: 1500, markupMultiplier: 2.5, weightUnit: 'gram', // 'gram' | 'ounce' | 'troy_ounce' }); ``` **Returns:** `void` See [Pricing API](./pricing) for detailed documentation. ## Events Subscribe to events using the `events` property: ```javascript const unsubscribe = api.events.on('price:updated', (data) => { console.log(data); }); // Unsubscribe unsubscribe(); // or api.events.off('price:updated', handler); ``` For direct integrations, wait for the window-level `ijewel-viewer-ready` event before reading the controller. For cross-origin iframes, wait for the forwarded `{ event: 'ready' }` message. The controller's own `ready` event is emitted during initialization and may occur before a same-page host obtains the controller. ### Event Reference | Event | Payload | Fired When | |-------|---------|------------| | `profile:changed` | `{ bandName, profileIndex, profileName }` | Profile shape changes | | `path:changed` | `{ bandName, pathId, strength? }` | Extrusion path changes | | `dimensions:changed` | `{ bandName, width, height, radius }` | Width, height, or radius changes | | `material:changed` | `{ bandName, slot, metal, finish }` | Material on any slot changes | | `partition:changed` | `{ bandName, numColors }` | Number of color zones changes | | `diamonds:changed` | `{ bandName, settingType, numStones }` | Diamond configuration changes | | `edge:changed` | `{ bandName, type, side }` | Edge treatment changes | | `engraving:changed` | `{ bandName, text, font }` | Engraving text or font changes | | `milgrain:changed` | `{ bandName, enabled }` | Milgrain state changes | | `finish:changed` | `{ bandName, insidePolished, splitGroove }` | Inside polish or groove split toggles | | `inlays:changed` | `{ bandName, inlays }` | The inlay list changes | | `overlays:changed` | `{ bandName, overlays }` | The rim-overlay list changes | | `sleeve:changed` | `{ bandName, sleeve }` | The bore sleeve changes or clears | | `build:started` | `{ bandName }` | Ring geometry rebuild begins | | `build:complete` | `{ bandName, durationMs }` | Ring geometry rebuild finishes | | `price:updated` | `{ bandName, pricing }` | Price recalculated (see [PriceBreakdown](#pricebreakdown)) | | `history:changed` | `{ canUndo, canRedo }` | Undo or redo availability changes | | `config:saved` | `{ id, name }` | A saved configuration is created or replaced | | `config:loaded` | `{ id, name? }` | A saved configuration is loaded | | `config:deleted` | `{ id }` | A saved configuration is deleted | | `band:switched` | `{ from, to }` | Active band changes | | `link:changed` | `{ linked }` | Wedding-band linking changes | | `rings:changed` | `{ rings }` | Ring compilation changes (add / remove / reorder / rename / metal / visibility) | | `compatibility:resolved` | `{ bandName, feature, value, action, reason, message }` | A configuration change made a feature incompatible and it was auto-removed, or an incompatible request was rejected | | `pose:changed` | `{ poseIndex }` | Camera pose changes | | `ar:started` | `{}` | AR try-on session begins | | `ar:stopped` | `{}` | AR try-on session ends | | `theme:changed` | `{ theme, ui? }` | Theme or UI options are applied | | `layout:changed` | `{ from, to }` | Built-in layout changes | | `ready` | `{}` | Plugin fully initialized | | `disposed` | `{}` | Plugin disposed and cleaned up | | `validation:warning` | `{ field, message, provided, corrected }` | A value was clamped or rejected (out of range input) | | `error` | `{ source, message, details? }` | An error occurred (also emitted as a `log` event with level `'error'`) | | `log` | `{ level, source, message, details?, timestamp }` | Any log entry emitted (all levels) | The cross-origin bridge forwards every event in this table except `pose:changed`, `ar:started`, and `ar:stopped`. Those three events are available only through direct `api.events` subscriptions. ## Lifecycle ### `dispose()` Removes controller event listeners and marks the controller unavailable. The Mini Viewer calls this automatically when a Wedding Band project is cleared, reloaded, or the viewer is destroyed. Application code normally should not call it directly. ```javascript api.dispose(); // advanced/manual teardown only ``` After disposal, get the new controller from the next viewer/project initialization instead of reusing the old instance. ## Types ### `RingSnapshot` ```typescript interface RingSnapshot { bandName: string profile: ProfileSnapshot dimensions: DimensionsSnapshot materials: MaterialSnapshot diamonds: DiamondSnapshot | null edge: EdgeSnapshot engraving: EngravingSnapshot | null pricing: PriceBreakdown | null } ``` ### `ProfileSnapshot` ```typescript interface ProfileSnapshot { index: number name: string fileName: string } ``` ### `DimensionsSnapshot` ```typescript interface DimensionsSnapshot { widthMm: number // Legacy name: profile width scale multiplier heightMm: number // Legacy name: profile height scale multiplier radiusMm: number // Physical radius in millimeters } ``` ### `MaterialSnapshot` ```typescript interface MaterialSnapshot { partition: number // Number of active material zones slots: MaterialSlot[] insidePolished: boolean splitAtGroove: boolean inlays?: InlayConfig[] overlays?: OverlayConfig[] sleeve?: SleeveConfig } interface MaterialSlot { slot: number // One-based active material slot metal: string // Base material id — same value as `base` finish: string // Finish id; '' for a material with no finish axis base?: string // Base material id variant?: string // Quality or sub-category: '18k', '14k', 'koa' } // The same slot on the way in, through batch() / importConfig(): only `slot` // is required, and an omitted field keeps that slot's current value. interface MaterialSlotInput extends Partial { slot: number } ``` ### `MaterialEntry`, `MaterialVariant`, and `MaterialRef` ```typescript type MaterialUsage = 'band' | 'inlay' | 'overlay' | 'sleeve' interface MaterialEntry { id: string name: string kind?: 'metal' | 'ceramic' | 'organic' | 'composite' iconUrl?: string swatch?: string usage?: MaterialUsage[] variants: MaterialVariant[] defaultVariant?: string finishes?: string[] defaultFinish?: string | null } interface MaterialVariant { id: string name: string iconUrl?: string swatch?: string files?: Record file?: string density?: number pricePerGram?: number } interface MaterialRef { base: string variant?: string finish?: string } ``` `density` and `pricePerGram` are reserved fields. The current runtime pricing engine does not read per-variant values from them. ### `InlayConfig` ```typescript interface InlayConfig { centerZ: number widthMm: number metal: string variant?: string finish?: string } ``` ### `OverlayConfig` ```typescript interface OverlayConfig { side: 'left' | 'right' widthMm: number metal: string variant?: string finish?: string coversRim?: boolean rimCoverage?: number } ``` ### `SleeveConfig` ```typescript interface SleeveConfig { enabled: boolean metal: string variant?: string finish?: string full?: boolean widthMm?: number } ``` ### `DiamondSnapshot` ```typescript interface DiamondSnapshot { settingType: string span: string spacing: string count: number placement: number stoneSize: number position: number // -1 (left) to 1 (right), 0 = center } ``` ### `EdgeSnapshot` ```typescript interface EdgeSnapshot { type: string side: string } ``` ### `EngravingSnapshot` ```typescript interface EngravingSnapshot { text: string font: string fontSize: number } ``` ### `PriceBreakdown` ```typescript interface PriceBreakdown { volumeMm3: number weightGrams: number metalPrice: { name: string // e.g. "White Gold" - reflects active metal densityGcm3: number pricePerGram: number totalUsd: number } makingCharge: { mode: 'none' | 'percent' | 'per-gram' percent: number perGram: number totalUsd: number } diamonds: { count: number totalCarats: number pricePerCarat: number totalUsd: number } | null settingCost: { costPerStone: number count: number totalUsd: number } | null finishSurcharge: { name: string // e.g. "Hammered" totalUsd: number } | null subtotalUsd: number markupMultiplier: number totalBeforeRounding: number totalUsd: number } ``` ### `PricingParams` ```typescript interface PricingParams { metalDensityGcm3?: number metalPricePerGram?: number metalPrices?: Record finishSurcharges?: Record diamondPricePerCarat?: number markupMultiplier?: number weightUnit?: WeightUnit makingChargeMode?: MakingChargeMode makingChargePercent?: number makingChargePerGram?: number settingCostPerStone?: number roundingEnabled?: boolean roundingStep?: number } interface MetalPriceEntry { density: number pricePerGram: number } type WeightUnit = 'gram' | 'ounce' | 'troy_ounce' type MakingChargeMode = 'none' | 'percent' | 'per-gram' ``` See [Pricing Engine](./pricing) for detailed documentation on pricing models, per-metal pricing, making charges, and rounding. ### `BatchConfig` ```typescript interface BatchConfig { profile?: { index: number } | { name: string } dimensions?: Partial // Slots are MaterialSlotInput, so a `materials` block read straight out of // exportConfig() can be handed back unchanged. `sleeve: null` removes the // sleeve; omitting the key leaves the current one alone. materials?: Omit, 'slots' | 'sleeve'> & { slots?: MaterialSlotInput[] sleeve?: SleeveConfig | null } diamonds?: Partial | null edge?: Partial engraving?: Partial | null pricing?: PricingParams } ``` ### `UITheme` ```typescript interface UITheme { preset?: ThemePresetName colors?: ThemeColors fonts?: ThemeFonts shapes?: ThemeShapes components?: ThemeComponentOverrides customCSS?: string panelWidth?: number showPoses?: boolean showARButton?: boolean showExportButton?: boolean showRingToggle?: boolean initialTab?: string } ``` ### `ThemeColors` ```typescript interface ThemeColors { primary?: string primaryHover?: string secondary?: string text?: string textMuted?: string textPlaceholder?: string background?: string surface?: string surfaceHover?: string border?: string borderLight?: string borderHover?: string } ``` ### `ThemeFonts` ```typescript interface ThemeFonts { body?: string headline?: string light?: string googleFonts?: string[] // e.g., ['Inter:wght@300;400;500'] } ``` ### `ThemePresetName` ```typescript type ThemePresetName = | 'default' | 'luxury-gold' | 'modern-minimal' | 'dark' | 'rose-elegant' | 'coral-modern' | 'fresh-teal' | 'minimal-blue' | 'warm-beige' | 'classic-gold' | 'ijewel' ``` ### `LogLevel` ```typescript type LogLevel = 'error' | 'warn' | 'info' | 'silent' ``` ### `LogSource` ```typescript type LogSource = 'api' | 'material' | 'geometry' | 'ar' | 'config' | 'engraving' | 'pricing' ``` ### `LogEntry` ```typescript interface LogEntry { level: Exclude source: LogSource message: string details?: any timestamp: number } ``` ## CSS Custom Properties The theme system injects CSS custom properties that you can use in your own stylesheets: | Property | Description | |----------|-------------| | `--rb-color-primary` | Primary accent color | | `--rb-color-primary-hover` | Primary hover state | | `--rb-color-secondary` | Secondary accent color | | `--rb-color-text` | Main text color | | `--rb-color-text-muted` | Secondary text color | | `--rb-color-background` | Page background | | `--rb-color-surface` | Card/panel background | | `--rb-color-border` | Border color | | `--rb-font-body` | Body font family | | `--rb-font-headline` | Headline font family | | `--rb-radius-md` | Border radius | ```css /* Use theme variables in your custom styles */ .my-custom-panel { background: var(--rb-color-surface); color: var(--rb-color-text); border: 1px solid var(--rb-color-border); font-family: var(--rb-font-body); } ``` --- # FAQ ## For Businesses Questions for jewelry brand owners, managers, and decision-makers evaluating the Wedding Band Builder.
What does the Wedding Band Builder cost? The Wedding Band Builder is part of the iJewel3D platform. The pricing model is one-time onboarding plus an annual subscription. No per-change fees, no opaque project quotes. Contact [contact@ijewel3d.com](mailto:contact@ijewel3d.com) for a quote. See [License and Pricing](../introduction/license) for general iJewel3D pricing information.
Which plan do I need? Every plan includes the Wedding Band Builder, from Free upward. On any plan you can create a Wedding Band project and use the built-in profile library. **Custom profile upload** — your own `.3dm` cross sections — needs the **Silver** plan or above. On a lower plan, the upload option shows an upgrade prompt. A **whitelabel embed**, with the iJewel branding removed, needs the **Gold** plan or above. See [Whitelabeling and Branding](../integrations/whitelabeling).
Do I need a developer to set it up? **For the basic setup, no.** The project itself is created and configured on the iJewel3D platform, no code required ([Create a Project](./drive-setup)). You can then embed the Wedding Band Builder with a single ` ``` Without `camera` permission, the Try-On button can appear but the camera cannot start inside the iframe.
What browsers are supported? The Wedding Band Builder uses WebGL 2.0 through the iJewel3D engine and works in current desktop and mobile versions of Chrome, Edge, Firefox, and Safari. Camera Try-On does not use WebXR. It requires WebGL 2, camera access through `navigator.mediaDevices.getUserMedia`, and HTTPS. Device performance also matters. For custom controls, use `ij_vto.canRunVTO()` before showing the Try-On button: ```javascript const support = ij_vto.canRunVTO(); if (!support.ok) { console.warn("Try-On unavailable", support.reason, support.details); } ``` Test the exact devices and in-app browsers used by your customers instead of depending on a browser version number alone.
### Performance
How large is the viewer bundle? The mini-viewer IIFE bundle (including the WebGI engine) is approximately 2-3 MB gzipped. Assets (profiles, PMAT materials, environment maps) are separate and load on demand after the viewer initializes. First-load time depends on your CDN and the number of assets in your manifest, but the viewer shell typically renders within 1-2 seconds.
Is the ring geometry generated in real time or pre made? Real time. The Wedding Band Builder uses a **parametric approach**: 2D profile curves are extruded along a circular path, materials are applied procedurally, and diamonds/edges/grooves are computed on the fly. Every combination produces a unique ring. There's no fixed catalog of 3D models.
### Offline & Caching
Does the configurator work offline? No. The Wedding Band Builder requires an internet connection. The viewer bundle, 3D engine, profile curves, material files, and environment maps are all loaded from the CDN or your asset server. Without connectivity, the viewer cannot initialize. However, assets are cached by the browser after the first load. Subsequent visits on the same device load significantly faster because profiles, materials, and environment maps are served from the browser cache. The viewer bundle itself is also cached. If a customer loses connectivity mid-session, the ring they've already configured remains visible and interactive (rotation, zoom). Changes that require loading new assets (switching profiles or materials) will fail until connectivity is restored.
### Troubleshooting
The viewer is blank / not loading. What do I check? 1. **Script loaded?** Check the browser console for 404 errors on the mini-viewer bundle. 2. **Container has dimensions?** The viewer fills its container. If the container has `0` height, nothing renders. Give it explicit dimensions (e.g., `height: 600px`). 3. **Manifest accessible?** The `manifestUrl` must be reachable from the browser. Check the Network tab for failed fetches. 4. **CORS?** If your assets are on a different domain, make sure the server sends `Access-Control-Allow-Origin` headers. 5. **Console errors?** Check for JavaScript errors. The `error` event also fires if something goes wrong after initialization: ```javascript api.events.on('error', (err) => console.error(err)); ```
How do I track what customers are configuring? Listen to change events and send them to your analytics platform: ```javascript // Track profile changes api.events.on('profile:changed', (data) => { analytics.track('ring_profile_changed', { band: data.bandName, profile: data.profileName, }); }); // Track material changes api.events.on('material:changed', (data) => { analytics.track('ring_material_changed', { band: data.bandName, metal: data.metal, finish: data.finish, }); }); // Track price views api.events.on('price:updated', (data) => { analytics.track('ring_price_viewed', { band: data.bandName, total: data.pricing.totalUsd, }); }); ``` This works with any analytics provider (Google Analytics, Segment, Mixpanel, etc.).
How do I handle version updates? The viewer bundle is versioned. Pin to a specific version in your script tag or iframe URL to avoid unexpected changes: ```html ``` The Wedding Band SDK guides pin the release pair that was verified end to end. Check the [Changelog](../viewer/viewer-changelog) before upgrading. The Wedding Band iframe lifecycle fixes require Mini Viewer `0.6.11` or newer. Material variants, the outside and inside material features, and the Modern Metals layout require `0.6.17` or newer. Ring Configurator and Wedding Band Builder Try-On require `0.6.18` or newer.
--- # Create an iJewel viewer embed An embed lets you place an interactive iJewel3D viewer on a website without building a JavaScript integration. Configure the viewer in iJewel Platform or iJewel Design, then copy either the complete `
{%- endif -%} ``` The conditional prevents an empty iframe from appearing on products that do not have an iJewel URL. ::: info Theme differences Dawn-based themes are often customized. If `sections/main-product.liquid` does not exist, search the theme for the section that renders the main product media or product information. Place the block where it best fits that layout. ::: ## Alternative: Build the URL from a product tag Use this option when many Shopify products map to public iJewel3D files. Each product stores a short tag instead of a complete URL. The tag must identify one public file within the selected folder tree. ### Prepare the iJewel3D files 1. Open the folder that contains the models in iJewel3D. 2. Make sure that each model file is public. 3. Right-click a model and select **Edit Tags**. 4. Add a unique product tag, such as `diamond-ring-001`. 5. Repeat this process for each product model. 6. Copy the folder ID from the address bar. The folder URL has the format `https://ijewel3d.com/drive/folders/FOLDER_ID`. Copy the value after `/folders/`. ### Create a tag metafield Follow [Step 2](#step-2-create-a-product-metafield) with these values: - **Name:** `iJewel model tag` - **Namespace and key:** `custom.model_tag` - **Description:** `Tag assigned to the public model in iJewel3D` - **Type:** `Single line text` - **Values:** `One value` Open each Shopify product and enter its iJewel3D tag in this metafield. ### Add the tag-based iframe Add this block to the product template. Replace `YOUR_FOLDER_ID` with the copied folder ID. ```liquid {%- assign ijewel_model_tag = product.metafields.custom.model_tag.value -%} {%- if ijewel_model_tag != blank -%}
{%- endif -%} ``` This template uses one URL pattern for all products. A file replacement does not require a Shopify URL change when its tag stays unchanged. ## Step 5: Preview and test Preview the duplicate theme and check: 1. A product with an iJewel URL displays the correct model. 2. A product without an iJewel URL does not show an empty space. 3. The viewer has enough height on desktop and mobile. 4. Fullscreen and viewer controls work as expected. 5. The storefront console has no blocked-frame or URL errors. 6. For a tag-based embed, each product displays the file with its assigned tag. ## Troubleshooting - **The viewer is blank:** open the metafield URL in a private browser window and confirm that the model is publicly accessible. - **The editor appears instead of the viewer:** regenerate the embed and copy the iframe `src`, not the browser's editor URL. - **Shopify rejects the metafield value:** confirm that you copied the complete `https://` URL without quotation marks. - **The viewer is too short or too tall:** adjust `min-height` and `aspect-ratio` in the iframe style. - **You need Shopify variants to change materials or models:** use the [Mini Viewer SDK integration](./shopify-dawn-viewer.md). ## Next steps - [Remove iJewel branding or use your own logo](./whitelabeling.md) - [Customize initial material selections](../viewer/tutorial-embed-drive.md#applying-materials-via-url) - [Move to the Mini Viewer SDK](./shopify-dawn-viewer.md) for direct page-to-viewer interaction ::: details Contact For Shopify integration or licensing assistance, email [contact@ijewel3d.com](mailto:contact@ijewel3d.com). ::: --- # Shopify integration with the Mini Viewer SDK ![Shopify Viewer Integration](../assets/images/shopify_sdk_banner.webp) Use the iJewel Mini Viewer SDK to add an interactive 3D viewer to a Shopify product page. This is the recommended custom integration for [Dawn](https://themes.shopify.com/themes/dawn/styles/default) and related themes. The Mini Viewer SDK is built on WebGI, but it manages the common viewer setup, model loading, UI, configurators, and lifecycle for you. You can still access the underlying WebGI viewer when you need targeted scene, camera, or plugin customization. ::: tip Looking for the simplest option? If you already have an embed URL from iJewel Drive or iJewel Design and do not need the page to control the viewer directly, use [Add an Embedded iJewel Viewer to Shopify](./shopify-embedding.md). ::: ## Why use the Mini Viewer SDK? - It is the recommended integration for new Shopify viewer projects. - It provides a stable API instead of requiring your theme to manage WebGI directly. - It can load a public iJewel Drive model by ID or load a standalone project configuration. - It includes iJewel viewer UI and support for configured materials, configurators, and Try-On features. - It reduces theme code and makes future viewer upgrades easier. - It provides the underlying WebGI `ViewerApp` through the `ijewel-viewer-ready` event when advanced customization is required. Use the [direct WebGI integration](./shopify-dawn.md) only if your team needs full engine-level control and will maintain the viewer initialization, plugins, UI, and lifecycle itself. ## Prerequisites - Access to the Shopify admin and theme code - A duplicate of the theme for development and testing - Basic familiarity with Liquid, HTML, CSS, and JavaScript - A public iJewel Drive model ID, or a public URL to a GLB/GLTF model - An iJewel3D SDK website license; see [Licensing](../introduction/license.md) ::: tip If you prefer to have a development team handle the integration, see our [Development Partners](../partners/info.md). ::: ## Step 1: Back up the theme In Shopify admin, open **Online Store → Themes**, open the theme actions menu, and select **Duplicate**. Make the integration changes in the duplicate theme and preview it before publishing. ## Step 2: Create a product metafield Create a product metafield that maps each Shopify product to its iJewel Drive model: 1. Open **Settings → Custom data → Products**. 2. Select **Add definition**. 3. Set the name to `iJewel Model ID`. 4. Set the namespace and key to `custom.ijewel_model_id`. 5. Select **Single line text** as the type and save it. 6. Open each product and enter its public iJewel Drive file ID in this metafield. ::: warning The file must be public Only files shared publicly in iJewel Drive can load on a storefront. A private file returns *Not found* and the viewer stays empty, so make the file public in Drive before testing. ::: If you host GLB/GLTF files yourself instead of using iJewel Drive, create a **URL** metafield here instead; see [Load a GLB file by URL](#load-a-glb-file-by-url). ## Step 3: Add a viewer asset In **Online Store → Themes → Edit code**, create `assets/ijewel-mini-viewer.js` with the following code: ::: info Tested script versions The examples in this guide use WebGI `0.22.0` with Mini Viewer `0.6.8`. Load WebGI first and keep both versions fixed until you have tested an upgrade in your duplicated theme. ::: ```js // Initialize every iJewel viewer container that has not been initialized yet. function initIjewelViewers(root = document) { if (typeof ijewelViewer === 'undefined') return; // SDK bundle not loaded yet root.querySelectorAll('[data-ijewel-model-id], [data-ijewel-model-url]').forEach((container) => { if (container.dataset.ijewelInitialized === 'true') return; container.dataset.ijewelInitialized = 'true'; // Defaults, merged with any options set from the Shopify admin (see Step 5). const viewerOptions = Object.assign( { showCard: false, brandingSettings: { enable: true, }, showConfigurator: true, transparentBg: true, }, window.iJewelViewerOptions || {}, ); if (container.dataset.ijewelModelId) { // Load a model from iJewel Drive by its file ID. ijewelViewer.loadModelById( container.dataset.ijewelModelId, container.dataset.ijewelBasename || 'drive', container, viewerOptions, ); } else { // Load a GLB/GLTF file directly from a URL. new ijewelViewer.Viewer( container, { modelUrl: container.dataset.ijewelModelUrl }, viewerOptions, ); } }); } // Initialize on the first page load. initIjewelViewers(); // The Shopify theme editor re-renders sections; initialize any new containers. document.addEventListener('shopify:section:load', (event) => { initIjewelViewers(event.target); }); // Optional: access the underlying WebGI ViewerApp for targeted customization. // Keep model loading and viewer lifecycle in the Mini Viewer SDK. window.addEventListener('ijewel-viewer-ready', (event) => { const webgiViewer = event.detail.viewer; console.log('iJewel viewer ready', webgiViewer); }); ``` The options shown above are examples. See [Viewer Options](../viewer/viewer-class.md#vieweroptions) for all available controls. Each container loads either an iJewel Drive model (`data-ijewel-model-id`) or a GLB/GLTF file from a URL (`data-ijewel-model-url`); see [Load a GLB file by URL](#load-a-glb-file-by-url). The `data-ijewel-initialized` guard prevents a container from loading twice, and the `shopify:section:load` listener re-initializes the viewer when Shopify's theme editor re-renders the product section. ## Step 4: Add the viewer to the product page Open `sections/main-product.liquid` and add the following block where the 3D viewer should appear: ```liquid {%- if product.metafields.custom.ijewel_model_id.value != blank -%}
{%- endif -%} ``` Deferred scripts execute in document order, so WebGI loads before the Mini Viewer SDK and your theme asset runs last. ::: info Enterprise Drive instances Keep `data-ijewel-basename="drive"` for the standard iJewel Drive. Enterprise customers with a custom Drive instance should replace `drive` with the basename supplied by iJewel3D. ::: ### Load a GLB file by URL If your models are GLB/GLTF files hosted outside iJewel Drive, the same asset script can load them with the `Viewer` class instead of `loadModelById`: 1. In Step 2, create the metafield with the **URL** type — for example `custom.ijewel_model_url` — and enter each product's model URL. 2. Use `data-ijewel-model-url` on the container instead of `data-ijewel-model-id`: ```liquid {%- if product.metafields.custom.ijewel_model_url.value != blank -%}
{%- endif -%} ``` The asset script detects the attribute and creates the viewer with `new ijewelViewer.Viewer(container, { modelUrl }, viewerOptions)`. The second argument is a project configuration and also accepts scene settings such as a custom environment map; see the [Viewer Class](../viewer/viewer-class.md) reference. A directly loaded GLB file has no iJewel Drive configuration, so materials, environments, and configurators must be part of the file itself. The file's host must also allow cross-origin requests from your storefront domain. ## Step 5: Change viewer options from the admin (optional) The asset script applies `window.iJewelViewerOptions` on top of its defaults, so you can adjust the viewer from the Shopify admin later without editing code again. 1. Open **Settings → Custom data → Shop** and add a definition named `iJewel viewer options` with the namespace and key `custom.ijewel_viewer_options` and the **JSON** type. 2. Enter the options you want to override as JSON, for example: ```json { "showConfigurator": false, "runRotateCamera": true } ``` 3. In `sections/main-product.liquid`, print the metafield before the asset script from Step 4: ```liquid {%- if shop.metafields.custom.ijewel_viewer_options.value -%} {%- endif -%} ``` Skip this step if the defaults in the asset script are all you need. ## Step 6: Match the theme layout Adjust the viewer container height for your product-page layout. You can place the standalone container beside the media gallery or in the product-information area, but keep it outside Shopify's native `` and `` elements. Dawn-based themes are frequently customized, so confirm the exact section and snippet names in your theme. The standalone container intentionally leaves Shopify's built-in `` and AR/XR behavior unchanged. If you want Mini Viewer to replace 3D files uploaded to Shopify product media instead, use [Replace Dawn's built-in 3D viewer](#replace-dawn-s-built-in-3d-viewer). Do not combine both approaches on the same product page. ## Step 7: Test the integration Preview the duplicated theme and verify that: 1. Products with an iJewel model ID show the viewer. 2. Products without the metafield continue to use the normal product layout. 3. The viewer works in the product media area on desktop and mobile. 4. Product variants, quick-view drawers, and dynamically loaded sections do not create duplicate viewers. 5. The browser console has no script, CORS, or licensing errors. If a model cannot be loaded from iJewel Drive, confirm that it is public and that the storefront domain is allowed. See [Connect to iJewel Drive](../viewer/connect-to-drive.md) for model-loading details. ::: info License An **iJewel3D Evaluation Version** watermark and a console warning appear when the SDK is not licensed for the storefront domain. To remove them, purchase a license; see [Licensing](../introduction/license.md). ::: ## Replace Dawn's built-in 3D viewer Use this alternative when product 3D models should open in Mini Viewer inside Dawn's existing product gallery and media modal. The override reads each ``'s `src` attribute and supports the same two sources as the standalone container: a GLB file uploaded to Shopify's **Media** section, or a public iJewel Drive link in the form `https://ijewel3d.com//files/` — for example when a customized theme fills `src` from a URL metafield. Drive links are loaded by instance and file ID, so the model keeps its Drive configuration. Dawn renders separate `` elements for the gallery and modal. A Mini Viewer cannot be reused by calling `render()` on a second container because its React root remains attached to the container where it was created. The override below creates one persistent host and physically moves that host between the visible gallery or modal element. This follows the same shared-viewer lifecycle used by the tested Shopify implementation. ::: warning Theme-specific integration This override targets current Dawn-style `product-model`, `product-modal`, and `DeferredMedia` elements. Test it against your exact theme version and customizations. The override replaces Shopify's native model viewer and native Shopify XR controls; configure iJewel Try-On separately if required. ::: ### Step 1: Create the override asset In **Online Store → Themes → Edit code**, create `assets/ijewel-model-viewer-override.js`: ```js (() => { if (window.iJewelShopifyOverrideInitialized) return; window.iJewelShopifyOverrideInitialized = true; if (customElements.get('model-viewer')) { console.error( 'iJewel override must load before Shopify defines .', ); return; } const viewerOptions = Object.assign( { showCard: false, brandingSettings: { enable: true, }, showConfigurator: true, transparentBg: true, }, window.iJewelViewerOptions || {}, ); // The model src supports the same two sources as the standalone container: // a public iJewel Drive link — https://ijewel3d.com//files/ — // loaded by instance and file ID so the model keeps its Drive configuration, // or a direct GLB/GLTF URL. function getDriveFileRef(src) { const match = src.match(/ijewel3d\.com\/([^/]+)\/files\/([^/?#]+)/); return match ? { basename: match[1], fileId: match[2] } : null; } // Mini Viewer creates its React root in this element. Move this same host // between Dawn's gallery and modal instead of creating a second viewer. const sharedHost = document.createElement('div'); Object.assign(sharedHost.style, { width: '100%', height: '100%', minHeight: '420px', }); let sharedViewer = null; let currentOwner = null; let currentSrc = null; let sceneReady = false; function finishSceneLoad() { sceneReady = true; currentOwner?.markLoaded(); } class IJewelModelViewer extends HTMLElement { constructor() { super(); this.modelLoaded = false; this.visibilityObserver = null; } connectedCallback() { // Prevent Shopify's Google Model Viewer feature loader from handling // this element. delete this.dataset.shopifyFeature; // Modal media is activated when product-modal opens. Gallery media is // initialized only when it becomes visible. if (this.closest('product-modal')) return; this.visibilityObserver = new IntersectionObserver((entries) => { if (!entries.some((entry) => entry.isIntersecting)) return; this.activate(); this.visibilityObserver?.disconnect(); this.visibilityObserver = null; }, { threshold: 0.01 }); this.visibilityObserver.observe(this); } disconnectedCallback() { this.visibilityObserver?.disconnect(); this.visibilityObserver = null; } doOnLoad(callback) { this.onLoad = callback; if (this.modelLoaded) callback(); } activate() { const src = this.getAttribute('src'); if (!src || typeof ijewelViewer === 'undefined') return; if (sharedHost.parentElement !== this) { this.appendChild(sharedHost); } currentOwner = this; if (!sharedViewer) { currentSrc = src; sceneReady = false; window.addEventListener('ijewel-scene-ready', finishSceneLoad, { once: true, }); const driveFile = getDriveFileRef(src); if (driveFile) { // Store the promise immediately so a second activate() cannot // create another viewer while this model is still loading. sharedViewer = ijewelViewer .loadModelById(driveFile.fileId, driveFile.basename, sharedHost, viewerOptions) .then((viewer) => (sharedViewer = viewer)); } else { sharedViewer = new ijewelViewer.Viewer( sharedHost, { modelUrl: src }, viewerOptions, ); } } else if (currentSrc !== src && typeof sharedViewer.render === 'function') { currentSrc = src; sceneReady = false; this.modelLoaded = false; window.addEventListener('ijewel-scene-ready', finishSceneLoad, { once: true, }); const driveFile = getDriveFileRef(src); if (driveFile) { // Passing the existing viewer makes loadModelById render into it // instead of creating a second one. ijewelViewer.loadModelById(driveFile.fileId, driveFile.basename, sharedHost, { ...viewerOptions, viewer: sharedViewer, }); } else { sharedViewer.render({ modelUrl: src }); } } else if (sceneReady) { this.markLoaded(); } requestAnimationFrame(() => { sharedViewer?.viewerApp?.resize?.(); }); } markLoaded() { if (currentOwner !== this) return; this.modelLoaded = true; this.onLoad?.(); requestAnimationFrame(() => { sharedViewer?.viewerApp?.resize?.(); }); } pause() { // Dawn calls pause() when another media item becomes active. } } customElements.define('model-viewer', IJewelModelViewer); // Replace Dawn's product-model wrapper so it clones the template without // loading Shopify's ModelViewerUI. if (!customElements.get('product-model')) { customElements.define( 'product-model', class extends DeferredMedia { constructor() { super(); const modelViewer = this.querySelector('template')?.content.querySelector('model-viewer'); if (modelViewer) delete modelViewer.dataset.shopifyFeature; } loadContent(focus = true) { super.loadContent(focus); const modelViewer = this.querySelector('model-viewer'); if (!modelViewer) return; modelViewer.doOnLoad(() => { const poster = this.querySelector('.deferred-media__poster'); if (poster) poster.style.display = 'none'; }); modelViewer.activate(); } setupModelViewerUI() {} }, ); } function findModalViewer(modal) { return ( modal.querySelector('[data-media-id].active model-viewer') || modal.querySelector('.active model-viewer') ); } function findGalleryViewer(src) { return Array.from( document.querySelectorAll('product-model model-viewer'), ).find( (modelViewer) => !modelViewer.closest('product-modal') && modelViewer.getAttribute('src') === src, ); } function syncModal(modal) { if (modal.hasAttribute('open')) { requestAnimationFrame(() => { findModalViewer(modal)?.activate(); }); return; } if (!currentSrc) return; findGalleryViewer(currentSrc)?.activate(); } function observeProductModals(root = document) { root.querySelectorAll('product-modal').forEach((modal) => { if (modal.dataset.ijewelObserved === 'true') return; modal.dataset.ijewelObserved = 'true'; new MutationObserver(() => syncModal(modal)).observe(modal, { attributes: true, attributeFilter: ['open'], }); }); } observeProductModals(); document.addEventListener('shopify:section:load', () => { // Dawn can move product-modal under , outside the reloaded section. observeProductModals(document); }); // Native Shopify XR is disabled by this replacement. Hide Dawn's native XR // button, including buttons added by a later section render. const xrStyle = document.createElement('style'); xrStyle.textContent = '[data-shopify-xr] { display: none !important; }'; document.head.appendChild(xrStyle); window.ProductModel = { loadShopifyXR() {}, setupShopifyXR() {}, }; })(); ``` The important detail is `sharedHost`: Mini Viewer is created in that element once, and the exact same element is moved into whichever `model-viewer` is visible. When another model is selected, the project is swapped on the same viewer — `render()` for GLB URLs, or `loadModelById` with the `viewer` option for Drive links — without changing the React root. ### Step 2: Replace Dawn's product-model script In `sections/main-product.liquid`, find the block that loads `product-model.js`. Some Dawn versions include the same block in `sections/featured-product.liquid`. ```liquid {%- if first_3d_model -%} {%- endif -%} ``` Keep `ProductJSON`, but replace the `product-model.js` script with the tested WebGI and Mini Viewer bundles followed by the override: ```liquid {%- if first_3d_model -%} {%- endif -%} ``` Deferred scripts execute in document order. The override must run after both viewer bundles and before any other script defines ``. ::: warning Do not replace `product-modal.js`; it controls Dawn's media modal and is used by the shared-host lifecycle. ::: ### Step 3: Upload and test a Shopify model 1. Edit a product and upload a GLB file in its **Media** section. 2. Preview the duplicated theme and select the 3D media item in the product gallery. 3. Open the media modal and confirm that the same loaded viewer moves into it. 4. Close the modal and confirm that the viewer returns to the gallery. 5. Repeat the test with more than one Shopify 3D model, on mobile, and in the theme editor. 6. Confirm that the browser console contains no custom-element, WebGL-context, or script-order errors. If your theme fills the model-viewer `src` from an iJewel Drive URL metafield instead of uploaded media, also verify that the Drive model loads with its configured materials and configurator. For iJewel Try-On or store-specific variant-to-material behavior, extend this lifecycle rather than creating another Mini Viewer. The working Shopify implementation uses the same persistent viewer for those features. ## Next steps - Review the [Viewer API](../viewer/viewer-class.md) to customize the viewer UI. - Follow [Connect to iJewel Drive](../viewer/connect-to-drive.md) for other model lookup methods. - Use [direct WebGI](./shopify-dawn.md) only for a fully custom, engine-level integration. ::: details Contact For integration or licensing assistance, email [contact@ijewel3d.com](mailto:contact@ijewel3d.com). ::: --- # Direct WebGI integration for Shopify ![Shopify Viewer Integration](../assets/images/shopify_sdk_banner.webp) This guide outlines the process of integrating WebGI directly into [Shopify](https://www.shopify.com/) using [Dawn](https://themes.shopify.com/themes/dawn/styles/default) or related themes. WebGI replaces the default Google/Shopify Model Viewer on the product detail page (PDP) and provides high-quality rendering for jewelry and fashion products. ::: warning Advanced integration For most Shopify stores, use the [Mini Viewer SDK integration](./shopify-dawn-viewer.md). It is the recommended integration and provides a stable, higher-level API for loading iJewel models, configurators, viewer UI, and Try-On features. Continue with direct WebGI only when your team needs engine-level control and is prepared to own the viewer implementation and its maintenance. ::: ## Why use direct WebGI, and who is it for? The Mini Viewer SDK is built on WebGI and covers the standard Shopify viewer workflow. It also exposes the underlying WebGI viewer through the `ijewel-viewer-ready` event, so needing occasional scene or camera customization is not, by itself, a reason to integrate WebGI directly. Choose **Mini Viewer SDK** when you want: - The recommended and supported path for a standard Shopify product page - Built-in model loading from iJewel Drive or a project configuration - Ready-made viewer UI, configurators, branding options, and Try-On integration - A smaller integration surface and easier SDK upgrades - Access to the underlying WebGI viewer only for selected customizations Choose **direct WebGI** only when you have an experienced 3D/WebGL development team and need: - Full ownership of viewer initialization, plugin setup, loading states, and lifecycle - A completely custom interface or rendering pipeline that does not fit the Mini Viewer SDK - Direct access to low-level WebGI APIs throughout the integration - Support for an existing direct-WebGI implementation that you are maintaining or migrating | Requirement | Recommended approach | | --- | --- | | Add an iJewel viewer to a Shopify PDP | [Mini Viewer SDK](./shopify-dawn-viewer.md) | | Load and configure models from iJewel Drive | [Mini Viewer SDK](./shopify-dawn-viewer.md) | | Customize a few camera, scene, or plugin settings | Mini Viewer SDK, then use `ijewel-viewer-ready` | | Build and maintain a fully custom rendering architecture | Direct WebGI (this guide) | | Maintain a legacy direct-WebGI Shopify theme | Direct WebGI (this guide) | ## Prerequisites - Access to your Shopify admin portal - Basic understanding of Shopify theme structure - Basic Familiarity with HTML, CSS, and JavaScript - iJewel3D SDK Website License. Check out the [license page](../introduction/license) for more details. ::: tip If you are looking for a development team for the integration, check our [Development Partners](../partners/info) ::: ## Step 1: Backup Your Theme 1. Log in to your Shopify admin portal at https://admin.shopify.com/ 2. Select your store 3. Navigate to `Online Store` -> `Themes` in the left menu 4. Locate your current theme and click on `Actions` (three dots) -> `Duplicate` 5. This creates a backup of your theme in case you need to revert changes ## Step 2: Access Theme Code 1. Find your duplicated theme 2. Click on `Actions` -> `Edit code`. This would open the Code Editor with the theme. ## Step 3: Verify Existing Product Model Code Themes include a file `product-model.js` that loads the default Google Model Viewer. We need to check that it exists and replace this code with the iJewel 3D Viewer. 1. In the `Assets` folder, locate `product-model.js` 2. Verify that it contains the following code. 3. If you can't find this file, search for similar code in other JavaScript files ::: details product-model.js ```js if (!customElements.get('product-model')) { customElements.define( 'product-model', class ProductModel extends DeferredMedia { constructor() { super(); } loadContent() { super.loadContent(); Shopify.loadFeatures([ { name: 'model-viewer-ui', version: '1.0', onLoad: this.setupModelViewerUI.bind(this), }, ]); } setupModelViewerUI(errors) { if (errors) return; this.modelViewerUI = new Shopify.ModelViewerUI(this.querySelector('model-viewer')); } } ); } window.ProductModel = { loadShopifyXR() { Shopify.loadFeatures([ { name: 'shopify-xr', version: '1.0', onLoad: this.setupShopifyXR.bind(this), }, ]); }, setupShopifyXR(errors) { if (errors) return; if (!window.ShopifyXR) { document.addEventListener('shopify_xr_initialized', () => this.setupShopifyXR()); return; } document.querySelectorAll('[id^="ProductJSON-"]').forEach((modelJSON) => { window.ShopifyXR.addModels(JSON.parse(modelJSON.textContent)); modelJSON.remove(); }); window.ShopifyXR.setupXRElements(); }, }; window.addEventListener('DOMContentLoaded', () => { if (window.ProductModel) window.ProductModel.loadShopifyXR(); }); ``` ::: ## Step 4: Add iJewel Viewer Code 1. Create a new file in the `Assets` folder named `product-model-ijewel.js` 2. Copy the following code into this new file. 3. Save the file ::: details product-model-ijewel.js ```js /** * This file is an alternative of `product-model.js` on Shopify. * It overloads the default model-viewer with the `webgi-viewer` from the iJewel3D SDK(https://ijewel3d.com). * This file must be included in the theme manually, and referenced in the pages where product-model.js was used. * Check the docs for more information and updates. - https://developer.ijewel3d.com/integrations/shopify * * File version - 26-07-2025 */ // Settings for the iJewel3D SDK, this includes the webgi package version, environment maps etc. // This can be set externally in the metafields or in the page where the product model is used, if not, the default settings will be used. window.iJewelSDKSettings = { webgi_version: "0.15.0", scene_settings: "", environment_map: "", loading: { loadingTextHeader: "Loading iJewel 3D Experience", showFileNames: false, backgroundOpacity: 0.5, background: "#ffffff", textColor: "#222222", logoImage: "https://playground.ijewel3d.com/logo_black.png", }, ...(window.iJewelSDKSettings||{}), } // Create a custom model-viewer element that extends the HTMLElement, this will be used to load the iJewel3D SDK viewer. // Note that it has to be made sure that this should be run before loading the google model viewer, since we cannot redefine an html element. if(!customElements.get('model-viewer')){ const viewerScript = document.createElement('script'); viewerScript.setAttribute('src', window.iJewelSDKSettings.webgi_version.includes('/') ? window.iJewelSDKSettings.webgi_version : // assume URL 'https://releases.ijewel3d.com/webgi/runtime/viewer-'+(window.iJewelSDKSettings.webgi_version||'0.9.19')+'.js' ); document.head.appendChild(viewerScript); //todo: fix for proper multiple viewer support. let globalViewer = null; // to make sure we use only 1 viewer and canvas on a page, customElements.define('model-viewer', class ModelViewerWebGi extends HTMLElement{ constructor() { super(); const container = document.createElement('div') this.container = container this.container.style.width = "100%" this.container.style.height = "100%" this.appendChild(container) this.modelLoaded = false; this.initialize() } doOnLoad(fn){ if(this.modelLoaded) fn() this.onLoad = fn; } async initialize(){ if(globalViewer) { if(globalViewer === 1) return this.viewer = globalViewer this.viewer.scene.removeSceneModels() }else { globalViewer = 1; this.viewer = new CoreViewerApp({container: this.container}) await this.viewer.initialize({caching: true, ground: true, bloom: true, enableDrop: false, importPopup: true, debug: false}) // ENCRYPTED_MODELS // Uncomment this and set your password to load encrypted models. // viewer.getManager().importer.registerFile("temp.glb").preparsers[0].key = (encryption, json)=> { // // console.log(encryption, json); // return "password"; // }; globalViewer = this.viewer; this.viewer.canvas.style.width = "100%" this.viewer.canvas.style.height = "100%" } const src = this.getAttribute('src') let envMapPromise = null this.refreshLoadingScreen() if(window.iJewelSDKSettings.environment_map && window.iJewelSDKSettings.environment_map.length){ envMapPromise = this.viewer.getManager().importer.importSinglePath(window.iJewelSDKSettings.environment_map) } const modelPromise = this.viewer.load(src) const [model, envMap] = await Promise.all([modelPromise, envMapPromise]) this.refreshLoadingScreen() if(window.iJewelSDKSettings.scene_settings && window.iJewelSDKSettings.scene_settings.length){ await this.viewer.load(window.iJewelSDKSettings.scene_settings) } this.view = this.viewer.plugins.CameraViews.getCurrentCameraView() this.refreshLoadingScreen() if(envMap) this.viewer.scene.setEnvironment(envMap) this.modelLoaded = true // await timeout(200) setTimeout(()=>{ if(this.onLoad) this.onLoad() window.dispatchEvent(new CustomEvent('ijewel-viewer-loaded', {detail: this})) }, 200) } refreshLoadingScreen(){ const loadingSettings = window.iJewelSDKSettings.loading ?? {} const loadingPlugin = this.viewer.getPluginByType('LoadingScreenPlugin') Object.entries(loadingSettings).forEach(([key, value])=>{ loadingPlugin[key] = value }) } resetView(){ if(!this.view || !this.viewer) return this.viewer.plugins.CameraViews.animateToView(this.view, 500) } pause(){} }) } // Create a custom ProductModel element that extends the DeferredMedia element, this disables loading of google-model-viewer if (!customElements.get('product-model')) { customElements.define('product-model', class ProductModel extends DeferredMedia { constructor() { super(); const template = this.querySelector('template') const viewer = template.content.querySelector('model-viewer') delete viewer.dataset.shopifyFeature // disables loading of google model viewer script by shopify const closeButton = document.createElement('div') closeButton.className = 'deferred-media__close-button' closeButton.innerHTML = '×' Object.assign(closeButton.style, { padding: '5px', position: 'absolute', top: '0', right: '0', margin: '10px', zIndex: 101, cursor: 'pointer', borderRadius: '50%', lineHeight: '20px', fontSize: '16px', display: 'flex', justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgb(var(--color-background))', border: '.1rem solid rgba(var(--color-foreground), .1)', color: 'rgb(var(--color-foreground))', height: '28px', width: '28px', transform: 'scale(1)', transition: 'transform var(--duration-short) ease, color var(--duration-short) ease', }); closeButton.addEventListener('click', async () => { if(this.modelViewer){ await this.modelViewer.resetView() } const poster = this.querySelector('.deferred-media__poster') const posterButton = this.querySelector('.deferred-media__poster-button') // const poster = document.querySelectorAll('.deferred-media__poster')[0] // const posterButton = document.querySelectorAll('.deferred-media__poster-button')[0] posterButton.style.display = 'flex' poster.style.display = 'flex' closeButton.style.display = 'none' }) this.closeButton = closeButton; } loadContent() { super.loadContent(); this.closeButton.style.display = 'flex' const poster = this.querySelector('.deferred-media__poster') poster.style.display = 'block' poster.style.zIndex = 100; const posterButton = this.querySelector('.deferred-media__poster-button') posterButton.style.display = 'none' const modelViewer = this.querySelector('model-viewer') this.modelViewer = modelViewer; // used by the close button to reset the view modelViewer.doOnLoad(()=>{ modelViewer.viewer.container.appendChild(this.closeButton) poster.style.display = 'none' }) } setupModelViewerUI(errors) { if (errors) return; } }); } // Set a dummy ProductModel in the window, just in case window.ProductModel = { loadShopifyXR() { }, setupShopifyXR(errors) { if (errors) return; }, }; ``` ::: ::: details Loading Encrypted Models Encryption can be used from the [iJewel3D Playground](https://playground.ijewel3d.com) to encrypt models, this protects your models from being downloaded and directly viewed in editors/viewers without a password. To load encrypted models, uncomment the code block `ENCRYPTED_MODELS` in the `initialize` function and set the password in the `key` function. This will be used to decrypt the model before loading. The password can be based on the model/meta-field or a fixed global password. Note that the password is added to the frontend javascript file. While this prevents non-technical users to easily extract the 3d file, experienced engineers can still extract it by reading the front-end code, and use it to decrypt and view the file. More strategies like obfuscation(and other techniques) can be used to further protect the password. This is very useful when using dynamic passwords for different models, since any bad actors would need to individually extract the password for each model. ::: ## Step 5: Update Theme Files Next, we need to replace the reference of `product-model.js` with `product-model-ijewel.js` in the pages where the product model is used. 1. Locate the files that reference the file, in the default theme(Dawn) this would be: - `sections/main-product.liquid` - `sections/featured-product.liquid` - Any other relevant section files 2. In each file, find the code block that loads the code. It should look similar to this: ```liquid {%- if first_3d_model -%} {%- endif -%} ``` 3. Replace the filename in the above code with `product-model-ijewel.js` and optionally get the settings from metafields and set as `iJewelSDKSettings` global variable: ```liquid {%- if first_3d_model -%} {%- if shop.metafields.ijewel3d_settings -%} {%- endif -%} {%- endif -%} ``` ::: info Note that this is enclosed in `if first_3d_model` block, this should already be present in the theme, and is done so that the script is only loaded once and when there is a 3d model in the product. ::: ::: warning There is also a reference to `product-modal.js` which is different, dont change that. ::: 4. Save all modified files ## Step 6: Configure iJewel Settings (Optional) To customize the iJewel viewer, the settings can be changed directly in the code for the file `product-model-ijewel.js`. If you would prefer to change them from the admin panel without editing the code, Shopify metafields can be added to store the settings, which are accessed in liquid as in Step 5.3 above. 1. Go to `Settings` -> `Metafields` in your Shopify admin 2. Create a new metafield for your shop with the namespace `ijewel3d_settings`. (or pick your own) 3. Add your desired settings as a JSON object. (or individual) 4. Save the metafield 5. Update the code in the theme to read the meta-field and set the `iJewelSDKSettings` global variable. (see Step 5.3) Example settings: ```json { "webgi_version": "0.9.19", "scene_settings": "", "environment_map": "", "loading": { "loadingTextHeader": "Loading iJewel 3D Experience", "showFileNames": false, "backgroundOpacity": 0.5, "background": "#ffffff", "textColor": "#222222", "logoImage": "https://playground.ijewel3d.com/logo_black.png" } } ``` ## Step 7: Add 3D Models to Products 1. Edit a product in your Shopify admin 2. In the **Media** section, select **Upload new** 3. Upload a GLB file - Test model: [Download Test Model](https://demo-assets.pixotronics.com/pixo/gltf/weddingrings1.glb) 4. Save the changes ::: tip Cover Image Once the model is uploaded, Shopify automatically generates a preview image for it. You can replace the preview by opening the model and editing its cover image. Other model settings in Shopify are not used by this integration. ::: ::: info Note - Shopify can store multiple 3D models on a product, but this sample integration supports one active 3D model per product. - If a configurator appears over the model, the GLB probably contains configurator data. To remove it, use the [iJewel3D Playground](https://playground.ijewel3d.com/v2/index.html). ::: ::: info License * An iJewel3D Evaluation Version logo will be shown along with a console warning if the iJewel3D SDK is not licensed. * To remove this, you need to purchase a license from [iJewel3D](https://ijewel3d.com/). ::: ## Step 8: Test the Integration 1. Preview the product page with the 3D model and the theme. 2. Verify that the iJewel viewer loads correctly and functions as expected 3. Test on various devices and browsers to ensure compatibility ## Troubleshooting - If the viewer doesn't appear, check the browser console for JavaScript errors - Ensure all file paths are correct in your theme files - Verify that the uploaded 3D model is a GLB file ## Next Steps - Explore additional iJewel SDK features and integrate them as needed - Check out other products at [iJewel3D](https://ijewel3d.com/) Remember to thoroughly test your changes before pushing the updated theme live. Regularly check for updates to both the Shopify theme and the iJewel SDK to ensure compatibility and access to new features. ::: details Contact For any questions or assistance with the integration, or questions about the license, email us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com), ::: --- # WordPress (WooCommerce) + 3D Viewer ![Wordpress Viewer Integration](../assets/images/wordpress_woocommerce_banner.webp) This guide outlines the process of integrating the iJewel 3D Viewer into [WordPress](https://wordpress.com/) using [Twenty Twenty-Four](https://wordpress.org/themes/twentytwentyfour/) or related themes with [WooCommerce](https://woocommerce.com/). The iJewel 3D Viewer added Model Viewer on the Product Display Page(PDP), offering high-quality rendering for jewelry and fashion items, and additional features like custom configurators, post-processing effects, AR TryOn etc ## Prerequisites - Access to your Wordpress admin portal - Understanding of Wordpress & Woocommerce theme structure - Basic Familiarity with HTML, CSS, and JavaScript - iJewel3D SDK Website License. Check out the [license page](../introduction/license) for more details. ::: tip If you are looking for a development team for the integration, check our [Development Partners](../partners/info) ::: ## Step 1: Install and Activate `ACF Plugin` 1. Go to Plugins > Add New in the WordPress dashboard. 2. Search for **Advanced Custom Fields** 3. Install and activate the plugin. ::: tip This Plugin is required to create custom field for product. ::: ## Step 2: Create Custom Fields for the 3D Model The viewer can load a model in two ways, so create two custom fields and fill only one of them per product: - **iJewel Drive model ID** — loads a public model from iJewel Drive with its configured materials and configurators. - **.glb file upload** — loads a GLB/GLTF file uploaded to WordPress directly. 1. Go to `Custom Fields > Add New`. 2. Add a field group title `3D Model`. 3. Click Add Field to create the model-ID field. - Field Label: `iJewel Model ID` - Field Name: `ijewel_model_id` - Field Type: Select `Text` from the dropdown menu. 4. Click Add Field again to create the file-upload field. - Field Label: `3D Model (.glb)` - Field Name: `3d_model` - Field Type: Select `File` from the dropdown menu. - Return Format: Choose `File URL` (you'll need the URL to load the model later). 5. Under Location, set Show this field group if to: - Post Type is equal to Product. 6. Click Publish. ::: warning Drive files must be public Only files shared publicly in iJewel Drive can load on your store. A private file returns *Not found* and the viewer stays empty, so make the file public in Drive before testing. ::: ## Step 3: Display the .glb File on the Product Page To display the 3D model on the front-end WooCommerce product page, you need to modify your `WooCommerce` product template. Modify Product Image Gallery Template (Optional) If you want more control over how and where the custom image appears, you can override the WooCommerce product gallery template. 1. Copy the WooCommerce Template: - Copy the template from `wp-content/plugins/woocommerce/templates/single-product/product-image.php` to your theme folder under `your-theme/woocommerce/single-product/product-image.php`. 2. Modify the Template: - In the copied template file, you can add your custom image logic. For example, add the custom image right before or after the existing gallery: ::: details product-image.php ```php // 3D model viewer if( get_field('ijewel_model_id') || get_field('3d_model') ) { echo ''; } ``` ::: This will display the custom image either before or after the main product images in the gallery. ::: info Some theme may have custom products image gallery slider. This may require some developer attention. ::: ## Step 4: Add code into theme `function.php` 1. Go to `project_folder/wp-content/themes/` 2. Add the following code in the bottom of `function.php` file. 3. Save the file ::: details function.php ```php // 3D model viewer function ij_custom_javascript() { ?> Customize > Additional CSS` ```CSS #mini-viewer #webgi-wrapper+.absolute button { display: none !important; } #webgi-wrapper button.z-0 { padding-left: 10px; padding-right: 10px; margin: 0; } .row-small>.flickity-viewport>.flickity-slider>.col.ij-item a::before { content: ""; position: absolute; right: 5px; top: 5px; z-index: 1; width: 25px; height: 25px; background: url('image/3d-rotate-icon-1.svg'); background-repeat: repeat; background-repeat: no-repeat; opacity: 0.6; } .ij-model-product { min-height: 640px; } @media (max-width:1350px){ .ij-model-product { min-height: calc(50vw - 30px); max-height: 640px; } } button.group { color: #000; } @media(max-width:849px) { .ij-model-product { min-height: calc(58vw - 30px); } } @media(max-width:549px) { .ij-model-product { min-height: calc(100vw - 30px); } } ``` ::: info Note that you need to adjust css properties as per design needs. ::: Save all modified changes ## Step 6: Add 3D Models to Products Once you've done above process Add new or Edit product. 1. Navigate to `WooCommerce > Products`. 2. Choose a product, or create a new product. 3. Fill exactly one of the two fields: - **iJewel Model ID** — paste the public iJewel Drive file ID. The model loads with its Drive-configured materials and configurators. - **3D Model (.glb)** — upload a GLB or GLTF file. Test model: [Download Test Model](https://demo-assets.pixotronics.com/pixo/gltf/weddingrings1.glb) 4. Save the changes ## Step 7: Test the Integration 1. Preview the product page with the 3D model and the theme. 2. Verify that the iJewel viewer loads correctly and functions as expected 3. Test on various devices and browsers to ensure compatibility ## Troubleshooting - If the viewer doesn't appear, check the browser console for JavaScript errors - Ensure all file paths are correct in your theme files - Verify that the 3D model file is in a supported format (GLB or GLTF) - If a Drive model does not load, confirm the file is shared publicly in iJewel Drive ## Next Steps - Explore additional iJewel SDK features and integrate them as needed - Check out other products at [iJewel3D](https://ijewel3d.com/) Remember to thoroughly test your changes before pushing the updated theme live. Regularly check for updates to the Theme, WooCommerce Plugin and the iJewel SDK to ensure compatibility and access to new features. ::: details Contact For any questions or assistance with the integration, or questions about the license, email us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com), ::: --- # Embedding in Wordpress(using woocommerce) ![Wordpress Viewer Integration](../assets/images/wordpress_woocommerce_banner.webp) This guide outlines the process of embedding the iJewel 3D Viewer into [WordPress](https://wordpress.com/) using [Twenty Twenty-Four](https://wordpress.org/themes/twentytwentyfour/) or related themes with [WooCommerce](https://woocommerce.com/). The iJewel 3D Viewer added Model Viewer on the Product Display Page(PDP), offering high-quality rendering for jewelry and fashion items, and additional features like custom configurators, post-processing effects, AR TryOn etc ## Prerequisites - Access to your Wordpress admin portal - Understanding of Wordpress & Woocommerce theme structure - Basic Familiarity with HTML, CSS, and JavaScript - iJewel3D SDK Website License. Check out the [license page](../introduction/license) for more details. ::: tip If you are looking for a development team for the integration, check our [Development Partners](../partners/info) ::: ## Step 1: Install and Activate `ACF Plugin` 1. Go to Plugins > Add New in the WordPress dashboard. 2. Search for **Advanced Custom Fields** 3. Install and activate the plugin. ::: tip This Plugin is required to create custom field for product. ::: ## Step 2: Create a Custom Field for Embedding URL 1. Go to `Custom Fields > Add New`. 2. Add a field group title `iJewel Embedding`. 3. Click Add Field to create a new custom field. - Field Label: `Embedding url` - Field Name: `ijewel_url` - Field Type: Select `URL` from the dropdown menu. 4. Under Location, set Show this field group if to: - Post Type is equal to Product. 5. Click Publish. ## Step 3: Displaying Embedded viewer on the Product Page To display the 3D model on the front-end WooCommerce product page, you need to modify your `WooCommerce` product template. Modify Product Image Gallery Template (Optional) If you want more control over how and where the custom image appears, you can override the WooCommerce product gallery template. 1. Copy the WooCommerce Template: - Copy the template from `wp-content/plugins/woocommerce/templates/single-product/product-image.php` to your theme folder under `your-theme/woocommerce/single-product/product-image.php`. 2. Modify the Template: - In the copied template file, you can add your custom image logic. For example, add the custom image right before or after the existing gallery: ::: details product-image.php ```php
``` ::: Adjust the iframe `width` and `height` to match your layout. This will display the viewer either before or after the main product images in the gallery. ::: info Some theme may have custom products image gallery slider. This may require some developer attention. ::: Save all modified changes ## Step 4: Add Embedding URL from [iJewel3D](https://ijewel3d.com) or [iJewel Design](https://ijewel.design) to Products Once you've done above process Add new or Edit product. 1. Navigate to `WooCommerce > Products`. 2. Choose a product, or create a new product. 3. You should see an option to add/edit `Embedding url`. 4. Save the changes ::: info Tip To get the embedding URL, follow this guide: [Create an iJewel Viewer Embed](./embedding.md) ::: ![custom field](../assets/images/wordpress-custom-field.webp) ## Step 5: Test the Integration 1. Preview the product page with the 3D model and the theme. 2. Verify that the iJewel viewer loads correctly and functions as expected 3. Test on various devices and browsers to ensure compatibility ## Troubleshooting - If the viewer doesn't appear, check the browser console for JavaScript errors - Ensure all file paths are correct in your theme files - Verify that the 3D model file is in a supported format (GLB or GLTF) ## Next Steps - Explore additional iJewel SDK features and integrate them as needed - Check out other products at [iJewel3D](https://ijewel3d.com/) Remember to thoroughly test your changes before pushing the updated theme live. Regularly check for updates to the Theme, WooCommerce Plugin and the iJewel SDK to ensure compatibility and access to new features. ::: details Contact For any questions or assistance with the integration, or questions about the license, email us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com), ::: --- # iJewel3D Rhino Plugin Using the iJewel Rhino Plugin, models can be previewed with the iJewel Viewer directly inside [McNeel Rhino 8](https://www.rhino3d.com/). The models can then be rendered to images, videos or shared online. [Download Now for free](https://www.food4rhino.com/en/app/ijewelviewer) It is designed specifically for 3D jewelry designers. It enhances the workflow for designers to interact and share their intricate jewelry models with their clients and fellow designers. ### Key Features 1. Experience seamless viewing of your 3D jewelry models directly within Rhino. 2. Export your Rhino models directly to the iJewel Viewer. 3. Provides different options within the viewer to rotate, zoom, and pan around your imported 3D model. 4. Create and customize your own configurator using a predefined set of metal and gem libraries, applying selected materials to your models according to your preferences. 5. Enhance your models further by applying different metal and gem environment maps available from the library. 6. Adjust advanced settings like environment rotation and intensity to achieve the perfect look for your designs. 7. Share your creations with clients, allowing them to view and interact with your designs in real-time, thereby providing an engaging experience. The plugin can be downloaded from the Package Manager in Rhino or from food4rhino - [iJewel3D Viewer](https://www.food4rhino.com/en/app/ijewelviewer). ## Usage After installing the plugin, load any 3d file, and use the command `iJewelViewer` to launch the 3D viewer with realtime realistic rendering. ## Layers and Materials The plugin automatically assigns materials to layers based on the layer names. In the following video, we guide you through on how to ensure if all your layers are correctly defined and materials are accurately assigned. Here’s how it works: 1. Standard Layer Naming Conventions: -Gold/Metal Materials: Layers named Metal, Metal 01, Metal 02, Metal 03, Metal 04, Head, or Heads will automatically get assigned gold/metal materials. -Diamond Materials: Layers named Gem, Gem 01, Gem 02, Gem 03, or Gem 04 will be assigned diamond materials. 2. Editing Layer Names: You can rename layers in the configurator to set it as per your preferences. This allows for better organization and customization of materials. 3. Handling Unwanted Elements: If you find extra elements that don’t fit your design, simply select the layer in Rhino and disable it. This will hide the layer, and it won’t appear in the plugin. 4. Correcting Material Assignments: If the same material is applied to multiple diamonds (grouped in the same layer), you can easily separate them in Rhino. Just ungroup the diamonds and assign different layer names to each for accurate material application. Follow along with the above video to ensure your designs are perfectly prepared for presentation with iJewel Viewer. ## Sharing After creating and customizing your jewelry models, you can share them with your clients or other designers. Click the share button at the top of the viewer to generate a link that can be shared with anyone. The link remains active for 7 days and can be used to view the model in the viewer. The shared model can be viewed on any device, including mobile phones, tablets, and desktops. The viewer is optimized for all screen sizes and provides a smooth and interactive experience for the user. To share the model permanently and build your personal portfolio, check out [ijewel.design](https://ijewel.design) - a platform for designers and jewelers to showcase their 3D models and connect with clients and collaborators. ### Encryption Models can be also be encrypted(password protected) before sharing. Before sharing the model, click the `Encrypt` button, and you will be prompted for a password to encrypt the model. The encrypted model can only be viewed by entering the correct password. All the encryption happens locally on your machine, and the password is not stored or transmitted to the server. The encryption is based on AES-256 encryption, which is a widely used and secure encryption algorithm. --- # Integrating iJewel3D Rhino Plugin in custom workflows This section outlines the technical details of iJewel Viewer plugin for [McNeel Rhino 8](https://www.rhino3d.com/). The plugin allows users to launch iJewel Viewer directly from Rhino via a custom command. This guide can be followed to integrate iJewel viewer into any rhino plugin or workflow. `Rhino.Commands.Command` is the abstract base class for custom commands within Rhino from [RhinoCommon](https://developer.rhino3d.com/api/rhinocommon/)(the .NET SDK for Rhino). By overriding its `RunCommand` method, we enable Rhino to export model data, synchronize changes, and stream assets directly into iJewel Viewer. The plugin is open-source and available on GitHub - https://github.com/ijewel3d/ijewel-rhino ### Core Command Workflow The central logic resides in the RunCommand method: ```csharp protected override Result RunCommand(RhinoDoc doc, RunMode mode) { try { RhinoApp.WriteLine("Checking internet connectivity..."); if (!CheckInternetConnectivity()) { RhinoApp.WriteLine("Error: No internet connection detected."); ShowNoInternetDialog(); return Result.Failure; } RhinoApp.WriteLine("Internet connection verified."); RhinoApp.WriteLine("Starting IJewelViewer..."); // Only start server if one isn't already running StartFileServer(); RhinoApp.WriteLine("Exporting model..."); ExportModel(doc); string uri = "https://ijewel.design/rhinoceros"; if (Rhino.Runtime.HostUtils.RunningOnOSX) { if (!BrowserLauncher.LaunchBrowserInMac(uri)) { //launch webview if none of the supported browsers are available on mac var webViewForm = new WebViewForm(uri); webViewForm.Show(); } } else { //use webview directly on windows var webViewForm = new WebViewForm(uri); webViewForm.Show(); } return Result.Success; } catch (Exception ex) { RhinoApp.WriteLine($"Error in RunCommand: {ex.Message}"); RhinoApp.WriteLine($"Stack Trace: {ex.StackTrace}"); return Result.Failure; } } ``` This workflow is divided into three major steps: 1. ##### Checking Intenet Connectivity
Validates an active internet connection. This is critical because iJewel Viewer pulls a rich library of assets from the cloud, including:
* Photorealistic material definitions (metals, diamonds, gemstones)
* HDR lighting environments
* 3D asset templates
* Texture maps and surface details
This ensures that every designer has access to the most updated visual assets.
2. ##### Local File Server Initialization and Model Observervation
The plugin starts a lightweight local file server to serves 3D model data to web clients.This enables Rhino’s 3D model data to be seamlessly streamed into the iJewel Viewer without manual exporting. ```csharp protected void StartFileServer() { if (IsPortInUse(Port)) return; _listener = new HttpListener(); _listener.Prefixes.Add($"http://localhost:{Port}/"); _listener.Start(); _serverThread = new Thread(() => ServerUtility.ServerThreadStart(_listener, _cancellationTokenSource.Token)); _serverThread.Start(); } ``` Alongside this, the `RhinoModelObserver` class continuously monitors model changes:
* Model creation, deletion, or modification
* Layer hiding or reassignment
* Material and object property changes
* Transformation changes
Every update is instantly reflected in the iJewel Viewer, ensuring what the designer sees is always accurate and up to date. The `RhinoModelObserver` class tracks the above model changes. This ensures that any changes to the 3D model are automatically detected and can trigger re-exports or notifications to connected iJewel Viewer. ```csharp public sealed class RhinoModelObserver { private RhinoModelObserver() { RhinoDoc.AddRhinoObject += (s, e) => MarkChanged(); RhinoDoc.DeleteRhinoObject += (s, e) => MarkChanged(); RhinoDoc.ReplaceRhinoObject += (s, e) => MarkChanged(); // Additional event handlers... } } ``` 3. ##### Launching iJewelViewer in Browser or Embedded Window Finally, the plugin launches the iJewel Viewer, either in:
* The user’s default web browser, or
* An embedded in-app web view
```csharp string uri = "https://ijewel.design/rhinoceros"; if (Rhino.Runtime.HostUtils.RunningOnOSX) { if (!BrowserLauncher.LaunchBrowserInMac(uri)) { //launch webview if none of the supported browsers are available on mac var webViewForm = new WebViewForm(uri); webViewForm.Show(); } } else { //use webview directly on windows var webViewForm = new WebViewForm(uri); webViewForm.Show(); } ``` * On macOS, it attempts to launch specific browsers (Chrome, Firefox, Opera) before falling back to an embedded WebView. * On Windows, the embedded WebView is the default. ::: tip * You can replace the uri "https://ijewel.design/rhinoceros", with "https://ijewel.design/rhinoceros?rhino" to ensure that the iJewel Viewer will listen to any model changes made in your CAD software. * To Launch [iJewel Playground](https://playground.ijewel3d.com/v2/index.html), change the uri to "https://playground.ijewel3d.com/v2/index.html" ::: ### Source Code Access You can fork the github repo to get access to the complete source code - [Here](https://github.com/ijewel3d/ijewel-rhino). --- # Changelog for iJewel Rhino Plugin ## [0.2.5] - 2025-12-11 ### Added - `iJewelPlatform` command to launch the viewer in ijewel3d.com. - `iJewelEnterprise` command to launch the viewer in any ijewel3d organization. ### Changed - Reverted `iJewelPlayground` command to launch Playground V2. --- # iJewel Partner Program ![iJewel Partner program](../assets/images/partner_program_hero.webp) iJewel3D partners with developers, designers, and agencies to create custom AR applications, configurators, and viewers. We provide tools, support, and resources to help partners build and deploy high-quality experiences for their clients. We also partner with resellers and local distributors to provide iJewel3D products in different regions. This includes training, support, and marketing resources to help partners grow. ::: tip Interested in becoming a partner? Learn about our partner program and get in touch — [Become a Partner](./become-a-partner) ::: ## Technical Partners

Thinkspace

📍 Portland, USA
Software development company focused on 3D jewelry experiences. The team develops 3D viewers and configurators based on the iJewel3D API. Hundreds of retailers and vendors trust Thinkspace to increase customer engagement and drive jewelry sales through branded and custom experiences.
3D model creation & optimization Viewers & configurators (iJewel SDK) E-commerce platform integration
Coming soon

Virtual Diamond Boutique (VDB)

📍 New York, USA | Tel Aviv, Israel | Mumbai, India
Jewelry technology platform enabling businesses to sell online and offline through specialized B2B and B2C applications. VDB provides wholesale tools, retail solutions, marketplace integrations, and 3D jewelry customization — connecting retailers, suppliers, and consumers across the diamond, lab-grown diamond, and gemstone markets. Trusted by over 30,000 jewelry trade professionals.
B2B wholesale tools & marketplace B2C retail apps & websites Shopify & WooCommerce integrations 3D jewelry configurators (Ring Creator) In-store Sales Genie app API & webhook integrations CRM/ERP integrations

Visionaries 777 Ltd.

📍 Tokyo | Hong Kong | Singapore | Berlin
Bespoke XR and real-time 3D company leveraging spatial computing to merge the physical and digital worlds. Founded in 2012 with roots in LEGO R&D and early AR innovation, VZ777 creates high-fidelity interactive solutions for enterprise clients across automotive, luxury, industrial, and real estate sectors.
Real-time 3D visualizers Configurators Bespoke XR applications R&D and innovation consulting
Coming soon

The CAD Co.

📍 Mumbai, India
Trendsetting B2B provider of advanced 3D CAD and product configurator solutions for the jewelry industry. As a strategic iJewel3D partner, the team leverages iJewel APIs and SDKs to deliver precision engineered services for jewelry manufacturing and customization.
3D jewelry configurators (iJewel SDK) CAD visual engineering Photorealistic 3D visuals Product catalogue creation Website development
Coming soon

Alloyum

📍 Innsbruck, Austria
Led by luxury jewelry expert Anja Hermanns with 25+ years in high-end jewelry, retail strategy, and brand development. As an official iJewel partner, Alloyum creates customized configurator solutions reflecting each brand's philosophy and emotional identity, with integration guidance, consulting, and team training.
Custom configurator solutions Integration consulting Team training & adoption Premium visual storytelling
Coming soon

Ole Solutions

📍 Mumbai, India
Technology and digital execution partner specializing in eCommerce, 3D visualization (using iJewel API), automation, and AI led operational workflows. Ole helps brands build scalable digital platforms, product experiences, and backend systems that improve customer engagement, operational efficiency, and online sales. Strong experience in jewelry, product visualization, Shopify, and automation led business transformation.
3D viewers & configurators Shopify / Shopify Plus E-commerce development Supply chain activation Catalog management AI & workflow automation

AMG Dynamics

📍 Mumbai, India | London, UK
Global technology company specializing in digital transformation solutions for the jewelry industry. Serving clients across the US, Europe, UK, Australia, Africa, and India, AMG Dynamics combines deep jewelry expertise with cutting edge technology to help businesses scale, automate, and innovate. Also the creator of The Goldsmith AI, the world's first AI platform built specifically for the jewelry industry.
E-commerce website development Jewelry configurators & 3D viewers API integrations & enterprise systems AI & machine learning solutions Factory & workflow automation Custom software development Digital catalog & inventory management
Coming soon
## 3D Modelling Partners

Jewelry CAD on Demand

📍 Mumbai, India
Internationally trusted, award winning custom jewelry CAD studio. Since 2013, the team has completed over 20,000 bespoke jewelry projects for jewelers, designers, and manufacturers worldwide. Expertise includes intricate, technically refined, and organic CAD models that combine artistry with manufacturability. Models integrate seamlessly into the iJewel workflow.
Custom CAD design Rendering & animation GLB file preparation for iJewel

Ole Solutions

📍 Mumbai, India
Technology and digital execution partner specializing in eCommerce, 3D visualization (using iJewel API), automation, and AI led operational workflows. Ole helps brands build scalable digital platforms, product experiences, and backend systems that improve customer engagement, operational efficiency, and online sales. Strong experience in jewelry, product visualization, Shopify, and automation led business transformation.
3D model creation & rendering Product image enhancement Photorealistic rendering 3D viewers & configurators

iGold 3D

📍 São Paulo, Brazil 🏆 iJewel3D 2025 Competition Winner
Brazilian studio specialized in technical jewelry development and CAD engineering. Focuses on manufacturing oriented CAD modeling combining structural precision, stone setting reliability, and production efficiency. The workflow combines engineering logic with aesthetic refinement, supporting jewelry brands and manufacturers in transforming concepts into production ready pieces.
Jewelry CAD (Rhino & ZBrush) Manufacturing ready files Structural optimization Stone setting analysis GLB preparation for iJewel
Coming soon

Thinkspace

📍 Portland, USA
Software development company focused on 3D jewelry experiences. The team develops 3D viewers and configurators based on the iJewel3D API. Hundreds of retailers and vendors trust Thinkspace to increase customer engagement and drive jewelry sales through branded and custom experiences.
3D model creation & optimization Viewers & configurators (iJewel SDK) E-commerce platform integration
Coming soon

AMG Dynamics

📍 Mumbai, India | London, UK
Global technology company specializing in digital transformation solutions for the jewelry industry. Serving clients across the US, Europe, UK, Australia, Africa, and India, AMG Dynamics combines deep jewelry expertise with cutting edge technology to help businesses scale, automate, and innovate. Also the creator of The Goldsmith AI, the world's first AI platform built specifically for the jewelry industry.
Rendering & product visualization Jewelry photography solutions Jewelry configurators & 3D viewers Digital catalog & inventory management
Coming soon
--- ## Become a Partner Want to join the iJewel3D partner ecosystem? We're looking for developers, 3D studios, agencies, and resellers worldwide. Learn More & Apply --- # Become an iJewel3D Partner ![iJewel Development Partners](../assets/images/development_partners_banner.webp) iJewel3D's partner program connects developers, agencies, 3D studios, and resellers with the tools, support, and resources to build and deliver exceptional jewelry visualization experiences. ## Partner Types ### Technical Partners Build custom viewers, configurators, AR experiences, and integrations using the iJewel3D SDK and APIs. We provide dedicated technical support, early access to new features, and co-marketing opportunities. **Good fit if you:** - Develop e-commerce integrations - Build product configurators - Build XR/AR applications for retail or luxury brands - Offer web development services to jewelry companies ### 3D Modelling Partners Create production ready 3D jewelry models optimized for the iJewel3D platform. We provide workflow guidance, quality standards documentation, and visibility through our partner directory and designer community. **Good fit if you:** - Specialize in jewelry CAD design (Rhino, ZBrush, Matrix, MatrixGold) - Offer rendering, animation, or product visualization services - Prepare manufacturing ready CAD files for jewelry brands ### Reseller & Distribution Partners Bring iJewel3D to your region or market. We provide training, sales support, marketing materials, and competitive reseller pricing. **Good fit if you:** - Serve jewelry retailers, manufacturers, or brands in your region - Offer consulting or digital transformation services to the jewelry industry - Have an existing network in jewelry trade or e-commerce ## What You Get | Benefit | Technical | 3D Modelling | Reseller | |---|:---:|:---:|:---:| | Partner directory listing | ✓ | ✓ | ✓ | | Dedicated partner support | ✓ | ✓ | ✓ | | Co-marketing opportunities | ✓ | ✓ | ✓ | | SDK & API early access | ✓ | | | | Technical onboarding | ✓ | | | | Workflow & quality guidelines | | ✓ | | | Community showcase visibility | | ✓ | | | Reseller pricing & training | | | ✓ | | Sales & marketing materials | | | ✓ | ## Get in Touch Interested in partnering with iJewel3D? Reach out and tell us about your company and how you'd like to work together.
You can also join our [Discord community](https://discord.com/invite/apzU8rUWxY) to connect with the team and other partners. --- # Frequently Asked Questions (FAQs) This page contains answers to common questions about iJewel3D products and features. ::: details How do I preserve user data strings when importing 3DM files? By default, when importing 3DM files, iJewel3D ignores user data strings that may have been defined by some people or plugins, this helps reduce the file size and improve the loading performance. However, you can choose to keep them if needed. If you're using iJewel3D.com, follow these steps when uploading a file: 1. Upload your 3DM file to iJewel3D 2. In the upload options popup, navigate to **Advanced Settings** 3. Under **3DM Options**, you'll find a checkbox labeled **Load User Data Strings** 4. Switch it **ON** to preserve the user data strings from your 3DM file This option allows you to retain any custom metadata or information stored in the user data strings of your 3DM files. Alternatively, if you're using the Playground, on the right side menu, under **Plugins** >> **Rhino 3dm Loader**, you'll find an option called **LoadUserDataString**. Switch it on before dropping your 3DM file to load the file with user data strings preserved. ::: --- Privacy Policy ============== Last updated: June 27, 2024 This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You. We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. Interpretation and Definitions ------------------------------ ### Interpretation The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural. ### Definitions For the purposes of this Privacy Policy: * **Account** means a unique account created for You to access our Service or parts of our Service. * **Affiliate** means an entity that controls, is controlled by or is under common control with a party, where "control" means ownership of 50% or more of the shares, equity interest or other securities entitled to vote for election of directors or other managing authority. * **Company** (referred to as either "the Company", "We", "Us" or "Our" in this Agreement) refers to iJewel 3d, 160 Robinson Road, #14-04 Singapore Business Federation Center, Singapore (068914). * **Cookies** are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses. * **Country** refers to: Singapore * **Device** means any device that can access the Service such as a computer, a cellphone or a digital tablet. * **Personal Data** is any information that relates to an identified or identifiable individual. * **Service** refers to the Website. * **Service Provider** means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used. * **Usage Data** refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit). * **Website** refers to iJewel3D including all subdomains, accessible from [https://ijewel3d.com/](https://ijewel3d.com/) * **You** means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable. Collecting and Using Your Personal Data --------------------------------------- ### Types of Data Collected #### Personal Data While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to: * Email address * First name and last name * Usage Data #### Usage Data Usage Data is collected automatically when using the Service. Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data. When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data. We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device. #### Tracking Technologies and Cookies We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include: * **Cookies or Browser Cookies.** A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies. * **Web Beacons.** Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity). Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. You can learn more about cookies on [TermsFeed website](https://www.termsfeed.com/blog/cookies/#What_Are_Cookies) article. We use both Session and Persistent Cookies for the purposes set out below: * **Necessary / Essential Cookies** Type: Session Cookies Administered by: Us Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services. * **Cookies Policy / Notice Acceptance Cookies** Type: Persistent Cookies Administered by: Us Purpose: These Cookies identify if users have accepted the use of cookies on the Website. * **Functionality Cookies** Type: Persistent Cookies Administered by: Us Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website. For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy. ### Use of Your Personal Data The Company may use Personal Data for the following purposes: * **To provide and maintain our Service**, including to monitor the usage of our Service. * **To manage Your Account:** to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user. * **For the performance of a contract:** the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service. * **To contact You:** To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation. * **To provide You** with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information. * **To manage Your requests:** To attend and manage Your requests to Us. * **For business transfers:** We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred. * **For other purposes**: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience. We may share Your personal information in the following situations: * **With Service Providers:** We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You. * **For business transfers:** We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company. * **With Affiliates:** We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us. * **With business partners:** We may share Your information with Our business partners to offer You certain products, services or promotions. * **With other users:** when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside. * **With Your consent**: We may disclose Your personal information for any other purpose with Your consent. ### Retention of Your Personal Data The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies. The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods. ### Transfer of Your Personal Data Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction. Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer. The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information. ### Delete Your Personal Data You have the right to delete or request that We assist in deleting the Personal Data that We have collected about You. Our Service may give You the ability to delete certain information about You from within the Service. You may update, amend, or delete Your information at any time by signing in to Your Account, if you have one, and visiting the account settings section that allows you to manage Your personal information. You may also contact Us to request access to, correct, or delete any personal information that You have provided to Us. Please note, however, that We may need to retain certain information when we have a legal obligation or lawful basis to do so. ### Disclosure of Your Personal Data #### Business Transactions If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy. #### Law enforcement Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency). #### Other legal requirements The Company may disclose Your Personal Data in the good faith belief that such action is necessary to: * Comply with a legal obligation * Protect and defend the rights or property of the Company * Prevent or investigate possible wrongdoing in connection with the Service * Protect the personal safety of Users of the Service or the public * Protect against legal liability ### Security of Your Personal Data The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security. If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information. Links to Other Websites ----------------------- Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit. We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services. Changes to this Privacy Policy ------------------------------ We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page. We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the "Last updated" date at the top of this Privacy Policy. You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page. Contact Us ---------- If you have any questions about this Privacy Policy, You can contact us: * By email: [contact@ijewel3d.com](mailto:contact@ijewel3d.com) * By visiting this page on our website: [https://www.ijewel3d.com/contact](https://www.ijewel3d.com/contact) --- # iJewel3D Developer Terms of Use Last updated: June 21, 2024 Check out the details in the [License](./introduction/license) section. --- Join our [discord](https://discord.com/invite/apzU8rUWxY), and share your feedback, ask questions, showcase your work and more. You can also email us at [contact@ijewel3d.com](mailto:contact@ijewel3d.com) or [Book a demo/meeting](https://ijewel3d.zohobookings.in/#/209816000000031082) with our sales team. ---