Skip to content

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 or inspect its source. 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:

FilePurpose
wedding-band-project.jsonCatalog, default rings, asset locations, and a reference to the scene file
wedding-band.vjsonEnvironment, lighting, ground, post-processing, and optionally the camera exported from Playground

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": "",
  "plugins": {
    "WeddingBandBuilder": {
      "type": "WeddingBandBuilder",
      "version": 1,
      "assetBaseUrl": "https://cdn.example.com/wedding-band/assets/",
      "profiles": [],
      "metals": [],
      "finishes": [],
      "diamonds": {},
      "separationPresets": {},
      "defaults": {
        "rootScale": 0.1,
        "autoFit": false,
        "bands": []
      }
    }
  }
}

This is a structure to fill in, not yet a loadable project. The required catalogs and opening band are added in the next steps.

Keep UI visibility out of the project JSON. The same project can power either the built-in Wedding Band controls or a Custom UI. Choose the UI mode with Mini Viewer's hideWbbUi option when you create the viewer in step 6.

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.

Metals and finishes

Metals define the color choices. Finishes map every metal ID to its material file:

json
"metals": [
  {
    "id": "yellow",
    "name": "Yellow Gold",
    "iconUrl": "icons/metal-yellow.png"
  },
  {
    "id": "white",
    "name": "White Gold",
    "iconUrl": "icons/metal-white.png"
  }
],
"finishes": [
  {
    "id": "polished",
    "name": "Polished",
    "iconUrl": "icons/finish-polished.png",
    "files": {
      "yellow": "materials/yellow-polished.pmat",
      "white": "materials/white-polished.pmat"
    }
  },
  {
    "id": "brush",
    "name": "Brush",
    "iconUrl": "icons/finish-brush.png",
    "files": {
      "yellow": "materials/yellow-brush.pmat",
      "white": "materials/white-brush.pmat"
    }
  }
]

Every key in files must match an ID in metals. When you add a metal, add a material for that metal to every finish you intend to offer.

For consistently named files, filePattern can replace files. Its default is "{metal}-{id}.pmat":

json
{
  "id": "polished",
  "name": "Polished",
  "filePattern": "materials/{metal}-{id}.pmat"
}

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"],
        "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 fieldMust refer to
profileIndexPosition of an entry in profiles
partitionA key in separationPresets
metalsIDs from metals
surfacesIDs from finishes

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.

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:

  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.
  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 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
  }
}

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
<div id="viewer" style="width: 100%; height: 600px"></div>

<script src="https://releases.ijewel3d.com/libs/webgi-v0/bundle-0.22.0.js"></script>
<script src="https://releases.ijewel3d.com/libs/mini-viewer/0.6.11/bundle.nowebgi.iife.js"></script>
<script src="./app.js"></script>

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,
      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.

ExperienceuseBuiltInWbbUiResult
Built-in controlstrueMini Viewer renders the standard Wedding Band panel
Custom/headless controlsfalseOnly 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. 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.

Continue with Script Tag (Direct Integration) for same-page API usage or Custom UI (Headless) to build your own controls.