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.setWidth(4.5);
});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.setWidth(4.5);Cross-Origin (PostMessage)
For iframes on a different domain:
// 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.
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 both bands.
const config = api.exportConfig();
// { her: RingSnapshot, his: RingSnapshot }Returns: { her: RingSnapshot; his: RingSnapshot }
getActiveBand()
Returns the name of the currently active band.
const band = api.getActiveBand(); // 'her' or 'his'Returns: string
getDimensions(bandName?)
Returns the current ring dimensions.
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.
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 }[]
getAvailableMetals()
const metals = api.getAvailableMetals();
// [{ id: 'Yellow', name: 'Yellow Gold', thumbnail: '...' }, ...]Returns: { id: string; name: string; thumbnail?: string }[]
getAvailableFinishes()
const finishes = api.getAvailableFinishes();
// [{ id: 'Polished', name: 'Polished', thumbnail: '...' }, ...]Returns: { id: string; name: string; thumbnail?: string }[]
getAvailablePartitions()
const partitions = api.getAvailablePartitions();
// ['1 Color', '2 Color', '3 Color']Returns: string[]
getAvailableSettingTypes()
const settings = api.getAvailableSettingTypes();
// ['none', 'Channel', 'Channel All Around', 'Bezel', 'Prong']Returns: string[]
getAvailableEdgeTypes()
const edges = api.getAvailableEdgeTypes();
// ['None', 'Beveled', 'Rounded', 'Sharp']Returns: string[]
getAvailableThemes()
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.
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
setWidth(mm, bandName?)
Sets the ring width in millimeters. The value is clamped to valid ranges.
api.setWidth(5.0);Returns: void
setHeight(mm, bandName?)
Sets the ring height (thickness) in millimeters.
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.
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', 'Brushed'); // 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', 'Brushed') |
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
setDiamonds(config, bandName?)
Configures diamond settings. Pass null to remove diamonds.
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.
api.setDiamondPosition(-1); // Left
api.setDiamondPosition(0); // Center (default)
api.setDiamondPosition(1); // Right
api.setDiamondPosition(0.5); // Between center and right| Parameter | Type | Description |
|---|---|---|
position | number | Position 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.
api.setDiamondSize(2.0);| Parameter | Type | Description |
|---|---|---|
size | number | Stone size value |
Returns: void
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 | 'both' | 'left', 'right', or 'both' |
Returns: void
setEngraving(text, font?, fontSize?, bandName?)
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 |
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?, bandName?)
Enables or disables wavy groove patterns.
api.setWavyGrooves(true, 8, 0.3); // Enable with frequency 8, amplitude 0.3
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 |
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.
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 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.
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.
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>
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);
});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)
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);
});
// One-time listener
api.events.once('ready', () => { /* ... */ });
// Unsubscribe
unsubscribe();
// or
api.events.off('price:updated', handler);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 |
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
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
heightMm: number
radiusMm: number
}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'
| 'bauhaus'
| 'euro-modern'
| 'soft-modern'
| 'swiss-precision'
| '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);
}