API Reference
Complete reference for the Wedding Band Builder API.
Accessing the API
Direct Integration (Same Page)
window.addEventListener('ijewel-viewer-ready', (e) => {
const viewer = e.detail.viewer;
const api = viewer.getPluginByType('WeddingBandBuilder').controller;
api.setWidthMm(4.4);
});Same-Origin iframe
// Access the controller through the iframe's viewer
const iframe = document.getElementById('wbb-iframe');
const viewer = iframe.contentWindow.ijewelViewer; // or however the viewer is exposed
const api = viewer.getPluginByType('WeddingBandBuilder').controller;
api.setWidthMm(4.4);Cross-Origin (PostMessage)
For iframes on a different domain:
// 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 the complete configuration snapshot for a band.
const snapshot = api.getSnapshot('her');Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
bandName | string | active band | 'her' or 'his' |
Returns: RingSnapshot
exportConfig()
Exports the full configuration for every band included in the project.
const config = api.exportConfig();
// { her: RingSnapshot, his: RingSnapshot }Returns: Record<string, RingSnapshot>
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.
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.
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.
const {
snapshot,
price,
diamondSizeInfo,
actualDimsMm,
} = api.getSpecSheetData('her');Returns:
{
snapshot: RingSnapshot;
price: PriceBreakdown | null;
diamondSizeInfo: { diameterMm: number; carats: number } | null;
actualDimsMm: { widthMm: number; heightMm: number };
}See Specification 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 getSnapshot() or exportConfig() instead.
const internalState = api.getRawState('her');Returns: Readonly<BandState>
getActiveBand()
Returns the name of the currently active band.
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.
const dims = api.getDimensions();
// { widthMm: 1.0, heightMm: 1.0, radiusMm: 8.5 }
console.log(`Width scale: ×${dims.widthMm}`);Returns: DimensionsSnapshot
getRawProfileDimensions(bandName?)
Returns the source profile's width and height at a 1.0 scale, in millimeters.
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.
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.
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.
const stone = api.getDiamondSizeInfo(1.5);
// { diameterMm: number, carats: number }Returns: { diameterMm: number; carats: number }
getMaterials(bandName?)
Returns the current material configuration including partition, slots, and finish options.
const mats = api.getMaterials();
// {
// partition: 2,
// slots: [
// { slot: 1, metal: 'White', finish: 'Polished' },
// { slot: 2, metal: 'Yellow', finish: 'Hammered' }
// ],
// insidePolished: true,
// splitAtGroove: true
// }Returns: MaterialSnapshot
getDiamonds(bandName?)
Returns the current diamond setting configuration, or null if no diamonds are set.
const diamonds = api.getDiamonds();Returns: DiamondSnapshot | null
getEdge(bandName?)
Returns the current edge configuration.
const edge = api.getEdge();
// { type: 'Beveled', side: 'Both' }Returns: EdgeSnapshot
getPrice(bandName?)
Returns the full price breakdown, or null if pricing is not configured.
const price = api.getPrice('her');
console.log(`$${price.totalUsd.toFixed(2)}`);Returns: PriceBreakdown | null
See Pricing API for detailed pricing documentation.
Catalog Methods
These methods return the available options defined in the project manifest.
getAvailableProfiles()
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()
const metals = api.getAvailableMetals();
// [{ id: 'yellow', name: 'Gold', thumbnail: '...' }, ...]Returns: { id: string; name: string; thumbnail?: string; iconUrl?: string }[]
getAvailableFinishes()
const finishes = api.getAvailableFinishes();
// [{ id: 'polished', name: 'Polished', thumbnail: '...' }, ...]Returns: { id: string; name: string; thumbnail?: string; iconUrl?: string }[]
getAvailablePartitions()
const partitions = api.getAvailablePartitions();
// ['1 Color', '2 Color', '3 Color']Returns: string[]
getAvailableSettingTypes()
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:
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()
const edges = api.getAvailableEdgeTypes();
// [{ id: 'None', name: 'None' }, { id: 'Beveled', name: 'Beveled' }, ...]Returns: { id: string; name: string }[]
getAvailableEdgeSides()
const sides = api.getAvailableEdgeSides();
// [{ id: 'Left', name: 'Left' }, { id: 'Both', name: 'Both' }, ...]Returns: { id: string; name: string }[]
getAvailableDiamondSpans()
const spans = api.getAvailableDiamondSpans();
// [{ id: 'half', name: '1/2', fraction: 0.5 }, ...]Returns: { id: string; name: string; fraction: number | string }[]
getAvailableDiamondSpacings()
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.
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.
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.
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()
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[]
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.
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.
api.setWidthMm(4.4); // band is now 4.4 mm wideReturns: 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.
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.
api.setWidthMultiplier(1.1); // 110% of the source profile width
api.setHeightMultiplier(0.95);Returns: void
setWidth(multiplier, bandName?) / setHeight(multiplier, bandName?) deprecated
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() 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.
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.
await api.setProfile(0); // by index
await api.setProfile('Flat'); // by nameReturns: Promise<void>
WARNING
setProfile() is async. Always await it before reading dimensions or other state that depends on the new geometry:
await api.setProfile(0);
const dims = api.getDimensions(); // safe, new geometry is loadedWithout the await, you may read stale dimensions from the previous profile.
setMaterial(slot, metal, finish, bandName?)
Sets the material for a specific slot.
api.setMaterial(1, 'Yellow', 'Polished'); // Slot 1
api.setMaterial(2, 'White', 'Hammered'); // Slot 2
api.setMaterial(3, 'Rose', 'Brush'); // Slot 3| Parameter | Type | Description |
|---|---|---|
slot | number | Slot number: 1, 2, or 3 |
metal | string | Metal ID (e.g., 'Yellow', 'White', 'Rose') |
finish | string | Finish ID (e.g., 'Polished', 'Hammered', 'Brush') |
Returns: void
setPartition(numColors, bandName?)
Sets the number of material color zones.
api.setPartition(2); // 2-color band| Parameter | Type | Description |
|---|---|---|
numColors | 1 | 2 | 3 | Number of material zones |
Returns: void
setPartitionByName(presetName, bandName?)
Applies an exact partition preset from getAvailablePartitions(). Use this instead of setPartition() for named layouts such as 2 Color Vertical.
const preset = api.getAvailablePartitions()[0];
api.setPartitionByName(preset);Returns: void
setDiamonds(config, bandName?)
Configures diamond settings. Accepts a partial DiamondSnapshot — only the fields you pass are changed. Pass null to remove diamonds.
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.
Returns: void
Diamond size
Stone size is the stoneSize field. Update it on its own by passing only that field:
api.setDiamonds({ stoneSize: 2.0 }); // 0.5–3.0Diamond 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:
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.
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.
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.
api.setInsidePolished(true);Returns: void
setSplitAtGroove(value, bandName?)
Toggles whether material splits align to grooves.
api.setSplitAtGroove(true);Returns: void
setWavyGrooves(enabled, frequency?, amplitude?, wavySplit?, bandName?)
Enables or disables wavy groove patterns.
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.
setDivision(division, bandName?) / setDivisionParams(params, bandName?) / getDivision(bandName?)
Sets how the color zones separate: 'vertical', 'axial', 'diagonal', or 'wavy'. setDivisionParams adjusts the wavy/diagonal boundary (frequency, amplitude).
api.setDivision('wavy');
api.setDivisionParams({ frequency: 4, amplitude: 0.4 });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.
api.setSeparationGroove({ type: 'v', angle: 60, depth: 0.15 });
api.setSeparationGroove({ enabled: false }); // clean grooveless seamDesign 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 fromsourceSidesetSideBezelSide(side, config, bandName?)— per-side span / count / spacing / stone sizecopySideBezelSide(from, bandName?)— copy one side's settings to the othergetSideBezel(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.
Plugin Serialization (Advanced)
toJSON() and fromJSON() belong to the WeddingBandBuilderPlugin, not the controller. They serialize the complete project/plugin state and are unavailable as controller calls over the cross-origin postMessage bridge. For customer selections, prefer api.exportConfig() and api.importConfig().
toJSON()
Exports the complete plugin state as a JSON-serializable object. Includes the manifest URL, all band states, and pricing configuration.
const plugin = viewer.getPluginByType('WeddingBandBuilder');
const data = plugin.toJSON();
// Save or transmit the configuration
localStorage.setItem('wbb-state', JSON.stringify(data));Returns: { manifestUrl, bands: { her: BandState, his: BandState }, pricing: {...} }
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.
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)
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.
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.
Returns: Promise<void>
importConfig(config)
Import complete configurations for both bands at once.
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' }],
},
},
});Returns: Promise<void>
Navigation
switchBand(bandName)
Switches the active band between "her" and "his".
api.switchBand('his');Returns: void
Fires: band:switched
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:
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. All changes fire rings:changed.
getRings()
Returns the compilation in scene order.
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.
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.
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.
Theme
setTheme(theme)
Apply a preset theme or custom theme configuration.
// 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 for full details.
Returns: void
cycleTheme()
Cycles to the next preset theme. Useful for previewing themes.
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.
const variables = api.getThemeCSSVariables();
Object.entries(variables).forEach(([name, value]) => {
document.documentElement.style.setProperty(name, value);
});Returns: Record<string, string>
Pricing
setPricingParams(params, bandName?)
Override pricing parameters at runtime.
api.setPricingParams({
metalDensityGcm3: 15.5,
metalPricePerGram: 52.0,
diamondPricePerCarat: 1500,
markupMultiplier: 2.5,
weightUnit: 'gram', // 'gram' | 'ounce' | 'troy_ounce'
});Returns: void
See Pricing API for detailed documentation.
Events
Subscribe to events using the events property:
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 |
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 |
finish:changed | { bandName, insidePolished, splitGroove } | Inside polish or groove split toggles |
build:started | { bandName } | Ring geometry rebuild begins |
build:complete | { bandName, durationMs } | Ring geometry rebuild finishes |
price:updated | { bandName, pricing } | Price recalculated (see PriceBreakdown) |
band:switched | { from, to } | Active band 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 } | Theme is applied |
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 the change, build, price, band, theme, ready, disposed, log, and error events. Subscribe directly on api.events when you also need validation:warning.
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.
api.dispose(); // advanced/manual teardown onlyAfter disposal, get the new controller from the next viewer/project initialization instead of reusing the old instance.
Types
RingSnapshot
interface RingSnapshot {
bandName: string
profile: ProfileSnapshot
dimensions: DimensionsSnapshot
materials: MaterialSnapshot
diamonds: DiamondSnapshot | null
edge: EdgeSnapshot
engraving: EngravingSnapshot | null
pricing: PriceBreakdown | null
}ProfileSnapshot
interface ProfileSnapshot {
index: number
name: string
fileName: string
}DimensionsSnapshot
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
interface MaterialSnapshot {
partition: number // 1, 2, or 3
slots: MaterialSlot[]
insidePolished: boolean
splitAtGroove: boolean
}
interface MaterialSlot {
slot: number // 1, 2, or 3
metal: string
finish: string
}DiamondSnapshot
interface DiamondSnapshot {
settingType: string
span: string
spacing: string
count: number
placement: number
stoneSize: number
position: number // -1 (left) to 1 (right), 0 = center
}EdgeSnapshot
interface EdgeSnapshot {
type: string
side: string
}EngravingSnapshot
interface EngravingSnapshot {
text: string
font: string
fontSize: number
}PriceBreakdown
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
interface PricingParams {
metalDensityGcm3?: number
metalPricePerGram?: number
metalPrices?: Record<string, MetalPriceEntry>
finishSurcharges?: Record<string, number>
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 for detailed documentation on pricing models, per-metal pricing, making charges, and rounding.
BatchConfig
interface BatchConfig {
profile?: { index: number } | { name: string }
dimensions?: Partial<DimensionsSnapshot>
materials?: Partial<MaterialSnapshot>
diamonds?: Partial<DiamondSnapshot> | null
edge?: Partial<EdgeSnapshot>
engraving?: Partial<EngravingSnapshot> | null
pricing?: PricingParams
}UITheme
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
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
interface ThemeFonts {
body?: string
headline?: string
light?: string
googleFonts?: string[] // e.g., ['Inter:wght@300;400;500']
}ThemePresetName
type ThemePresetName =
| 'default'
| 'luxury-gold'
| 'modern-minimal'
| 'dark'
| 'rose-elegant'
| 'coral-modern'
| 'fresh-teal'
| 'minimal-blue'
| 'warm-beige'
| 'classic-gold'
| 'ijewel'LogLevel
type LogLevel = 'error' | 'warn' | 'info' | 'silent'LogSource
type LogSource = 'api' | 'material' | 'geometry' | 'ar' | 'config' | 'engraving' | 'pricing'LogEntry
interface LogEntry {
level: Exclude<LogLevel, 'silent'>
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 |
/* 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);
}