live.js
<script src="https://devlive.thinkbeyondcorporate.com/sdk/v1/live.js"></script>
Defines window.VelvetLive, named like Lovense Cam Kit's model.js. It runs on the model's page only (it holds her model token). It never sees your secret key.
live.js keeps its own connection to Velvet Live for tips and status, separate from the toy panel. So receiveTip and the events work whether the panel is mounted on this page or open in the model's own tab.
VelvetLive.initCamApi(modelToken)
Start with the token your server minted. Calling it again with a new token (after a rotation) switches everything, including a mounted panel, without the model re-pairing her toy.
VelvetLive.mount(element, options?)
Puts the toy panel into element (an element or a CSS selector) as an iframe with allow="bluetooth". Returns the iframe.
| Option | |
|---|---|
height | CSS height, default 640px |
virtualToy | test models only: start with the virtual toy (ignored for live tokens) |
The token travels in the iframe URL's fragment (/panel/#mt=…), which browsers never send to any server.
VelvetLive.receiveTip(cname, amount, note?)
Lovense Cam Kit's argument order: tipper name, tokens, optional note. Returns a promise:
const r = await VelvetLive.receiveTip('raj_k', 25, '#wave');
// { ok: true, tipId, duplicate: false, action: { kind, strength, durationMs, rule, preset? } } (strength 0–100, ms)
// { ok: false, error: 'toy_offline' } no panel open: nothing recorded
Arguments that don't fit (a number as the name, a fraction, 0) are refused with invalid_tip_args, never guessed. (Lovense's Cam Extension uses (amount, name): check your call when you switch.)
Browser tips are unverified: they only move this model's own toy, and they don't count toward reporting. Prefer the server API when your server sees the tip.
VelvetLive.getSettings()
Promise of the menu: { version, levels, specials, perks } (shape).
VelvetLive.getToys()
Promise of [{ id, name, type, status: 'on' | 'off', battery }]: the toy the model's panel has paired (empty when no panel is open).
VelvetLive.addMessageListener(callback)
Every event is { type, detail }. Returns a function that removes the listener (removeMessageListener(callback) works too).
type | detail |
|---|---|
message | { code, text }: errors and notices (toy_offline, rate_limited, token_revoked, …) |
settings | the menu, on load and whenever the model edits it |
toy | { panelConnected, toys } |
tipQueueStatus | { paused, held, queueLength, queuedMs } |
tipRunning | { running: true, tipper, tokens, strength, remainingMs } or { running: false } |
tipLog | Velvet only: each tip's timing (received, queued, command, ack) |
VelvetLive.destroyCamApi()
Closes the connection and removes the panel (which stops the toy).