Skip to content

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.setWidth(4.5);
});

Same-Origin iframe

javascript
// 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.setWidth(4.5);

Cross-Origin (PostMessage)

For iframes on a different domain:

javascript
// Parent page sends to iframe
iframe.contentWindow.postMessage({
  id: 'req-1',
  method: 'setWidth',
  args: [4.5]
}, '*');

// Listen for responses from iframe
window.addEventListener('message', (event) => {
  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.

javascript
const snapshot = api.getSnapshot('her');

Parameters:

NameTypeDefaultDescription
bandNamestringactive band'her' or 'his'

Returns: RingSnapshot

exportConfig()

Exports the full configuration for both bands.

javascript
const config = api.exportConfig();
// { her: RingSnapshot, his: RingSnapshot }

Returns: { her: RingSnapshot; his: RingSnapshot }

getActiveBand()

Returns the name of the currently active band.

javascript
const band = api.getActiveBand(); // 'her' or 'his'

Returns: string

getDimensions(bandName?)

Returns the current ring dimensions.

javascript
const dims = api.getDimensions();
// { widthMm: 4.0, heightMm: 1.8, radiusMm: 8.5 }

Returns: DimensionsSnapshot

getMaterials(bandName?)

Returns the current material configuration including partition, slots, and finish options.

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

javascript
const diamonds = api.getDiamonds();

Returns: DiamondSnapshot | null

getEdge(bandName?)

Returns the current edge configuration.

javascript
const edge = api.getEdge();
// { type: 'Beveled', side: 'both' }

Returns: 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 | null

See Pricing API for detailed pricing documentation.

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 }[]

getAvailableMetals()

javascript
const metals = api.getAvailableMetals();
// [{ id: 'Yellow', name: 'Yellow Gold', thumbnail: '...' }, ...]

Returns: { id: string; name: string; thumbnail?: string }[]

getAvailableFinishes()

javascript
const finishes = api.getAvailableFinishes();
// [{ id: 'Polished', name: 'Polished', thumbnail: '...' }, ...]

Returns: { id: string; name: string; thumbnail?: string }[]

getAvailablePartitions()

javascript
const partitions = api.getAvailablePartitions();
// ['1 Color', '2 Color', '3 Color']

Returns: string[]

getAvailableSettingTypes()

javascript
const settings = api.getAvailableSettingTypes();
// ['none', 'Channel', 'Channel All Around', 'Bezel', 'Prong']

Returns: string[]

getAvailableEdgeTypes()

javascript
const edges = api.getAvailableEdgeTypes();
// ['None', 'Beveled', 'Rounded', 'Sharp']

Returns: string[]

getAvailableThemes()

javascript
const themes = api.getAvailableThemes();
// ['default', 'luxury-gold', 'modern-minimal', 'dark', 'rose-elegant',
//  'bauhaus', 'euro-modern', 'soft-modern', 'swiss-precision', '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.

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
ParameterTypeDefaultDescription
levelLogLevel'warn'Minimum severity to emit

Returns: void

setWidth(mm, bandName?)

Sets the ring width in millimeters. The value is clamped to valid ranges.

javascript
api.setWidth(5.0);

Returns: void

setHeight(mm, bandName?)

Sets the ring height (thickness) in millimeters.

javascript
api.setHeight(2.0);

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<void>

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 material for a specific slot.

javascript
api.setMaterial(1, 'Yellow', 'Polished');    // Slot 1
api.setMaterial(2, 'White', 'Hammered');     // Slot 2
api.setMaterial(3, 'Rose', 'Brushed');       // Slot 3
ParameterTypeDescription
slotnumberSlot number: 1, 2, or 3
metalstringMetal ID (e.g., 'Yellow', 'White', 'Rose')
finishstringFinish ID (e.g., 'Polished', 'Hammered', 'Brushed')

Returns: void

setPartition(numColors, bandName?)

Sets the number of material color zones.

javascript
api.setPartition(2); // 2-color band
ParameterTypeDescription
numColors1 | 2 | 3Number of material zones

Returns: void

setDiamonds(config, bandName?)

Configures diamond settings. Pass null to remove diamonds.

javascript
api.setDiamonds({
  settingType: 'Channel',
  span: 'half',
  spacing: 'normal',
  count: 12,
  stoneSize: 0.02,
});

// Remove diamonds
api.setDiamonds(null);

Returns: void

setDiamondPosition(position, bandName?)

Sets the diamond position along the ring's width. The value is automatically clamped based on band width, diamond size, and groove width to prevent diamonds from going outside the ring.

javascript
api.setDiamondPosition(-1);   // Left
api.setDiamondPosition(0);    // Center (default)
api.setDiamondPosition(1);    // Right
api.setDiamondPosition(0.5);  // Between center and right
ParameterTypeDescription
positionnumberPosition from -1 (left) to 1 (right), 0 = center

Returns: void

INFO

Diamond position is automatically reset to center (0) when wavy grooves are enabled.

setDiamondSize(size, bandName?)

Sets the diamond stone size.

javascript
api.setDiamondSize(2.0);
ParameterTypeDescription
sizenumberStone size value

Returns: void

setEdge(type, side?, bandName?)

Sets the edge treatment.

javascript
api.setEdge('Beveled', 'both');
api.setEdge('None'); // Remove edge
ParameterTypeDefaultDescription
typestringEdge type (see getAvailableEdgeTypes())
sidestring'both''left', 'right', or 'both'

Returns: void

setEngraving(text, font?, fontSize?, bandName?)

Sets the interior engraving text. Pass null to remove.

javascript
api.setEngraving('Forever & Always', 'serif', 80);

// Remove engraving
api.setEngraving(null);
ParameterTypeDefaultDescription
textstring | nullEngraving text, or null to remove
fontstringcurrentFont family name
fontSizenumbercurrentFont size in pixels

Returns: void

setInsidePolished(value, bandName?)

Toggles whether the ring interior is polished.

javascript
api.setInsidePolished(true);

Returns: void

setSplitAtGroove(value, bandName?)

Toggles whether material splits align to grooves.

javascript
api.setSplitAtGroove(true);

Returns: void

setWavyGrooves(enabled, frequency?, amplitude?, bandName?)

Enables or disables wavy groove patterns.

javascript
api.setWavyGrooves(true, 8, 0.3);  // Enable with frequency 8, amplitude 0.3
api.setWavyGrooves(false);          // Disable
ParameterTypeDefaultDescription
enabledbooleanEnable or disable wavy grooves
frequencynumbercurrentWave frequency
amplitudenumbercurrentWave amplitude

Returns: void

INFO

Enabling wavy grooves automatically resets the diamond position to center (0), since offset diamond positions are not supported with wavy grooves.

Serialization

toJSON()

Exports the complete plugin state as a JSON-serializable object. Includes the manifest URL, all band states, and pricing configuration.

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

javascript
const saved = JSON.parse(localStorage.getItem('wbb-state'));
await plugin.fromJSON(saved);

Returns: Promise<void>

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: 5.0, heightMm: 2.0 },
  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: 'normal',
    count: 12,
    stoneSize: 0.02,
  },
  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.

javascript
await api.importConfig({
  her: {
    profile: { name: 'Comfort' },
    dimensions: { widthMm: 3.5 },
    materials: {
      partition: 1,
      slots: [{ slot: 1, metal: 'Rose', finish: 'Polished' }],
    },
  },
  his: {
    profile: { name: 'Flat' },
    dimensions: { widthMm: 6.0 },
    materials: {
      partition: 1,
      slots: [{ slot: 1, metal: 'White', finish: 'Brushed' }],
    },
  },
});

Returns: Promise<void>

switchBand(bandName)

Switches the active band between "her" and "his".

javascript
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:

javascript
api.events.on('band:switched', (data) => {
  const snapshot = api.getSnapshot(data.to);
  updateAllControls(snapshot);
});

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 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)

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 for detailed documentation.

Events

Subscribe to events using the events property:

javascript
const unsubscribe = api.events.on('price:updated', (data) => {
  console.log(data);
});

// One-time listener
api.events.once('ready', () => { /* ... */ });

// Unsubscribe
unsubscribe();
// or
api.events.off('price:updated', handler);

Event Reference

EventPayloadFired 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
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)

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
  heightMm: number
  radiusMm: number
}

MaterialSnapshot

typescript
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

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

typescript
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

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'
  | 'bauhaus'
  | 'euro-modern'
  | 'soft-modern'
  | 'swiss-precision'
  | '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<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:

PropertyDescription
--rb-color-primaryPrimary accent color
--rb-color-primary-hoverPrimary hover state
--rb-color-secondarySecondary accent color
--rb-color-textMain text color
--rb-color-text-mutedSecondary text color
--rb-color-backgroundPage background
--rb-color-surfaceCard/panel background
--rb-color-borderBorder color
--rb-font-bodyBody font family
--rb-font-headlineHeadline font family
--rb-radius-mdBorder 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);
}