TokElementsDOCS
ウィジェットSDK / V1
01

はじめに

1
マークアップとスタイルを書く

HTMLとCSSのタブでウィジェットを描きます。枠は透明で映像の上に浮かぶので、不透明な全面背景は絶対に塗らないでください。

2
イベントに反応する

JSタブでTE.on('gift', fn)を使って購読します。window.TEは読み込み済みなので、importも準備も不要です。

3
テストして追加

Simulate(シミュレート)やFire(発火)ボタンでオフラインでプレビューし、オーバーレイに追加します。MCP経由でClaudeに作ってもらうこともできます。

最初のウィジェット:ギフトのシャウトアウト· JSを編集すると、プレビューがリアルタイムで反応します
var box = document.getElementById('box');
TE.on('gift', function (ev) {
  box.textContent = ev.user.name + ' sent ' + ev.gift.name + '!';
  box.classList.remove('pop'); void box.offsetWidth; box.classList.add('pop');
});
ライブプレビュー
02

Claudeを接続(MCP)

Claude DesktopやClaude Codeから直接ウィジェットを作成・編集できます。トークンを発行してコネクターを追加すれば、Claudeがあなたのアカウントで次のツールを呼び出せます:

get_docs完全な作成ガイドとすべてのトリガー・アクション(Claudeが最初に読みます)。
list_widgets保存したウィジェットをidとともに一覧表示。
get_widgetひとつのウィジェットのhtml / css / jsを取得。
create_widget名前とhtml/css/jsから新しいHTMLウィジェットを作成。
update_widget既存のウィジェットを編集。
delete_widgetidを指定してウィジェットを削除。
list_templatesコピー元にできる内蔵テンプレートを一覧表示。
get_templateテンプレートのhtml/css/jsを読む。
create_from_templateテンプレートを新しいウィジェットにコピー。
list_community_templatesコミュニティが公開したウィジェットを閲覧。
install_community_templateコミュニティテンプレートの非公開・編集可能なフォークをインストール。
読み込み中…
03

TE SDK

ウィジェットの動作はすべてグローバルなwindow.TEオブジェクトを通して行います。

TE.on(type, fn)

ライブイベントを購読します。`type`は下記のいずれかのトリガーで、`fn(ev)`はイベントが起きるたびに実行されます。

TE.on('*', fn)

すべてのイベントを受け取ります。`fn(ev, type)`はペイロードとイベント名を受け取ります。

TE.off(type, fn)

以前に登録したハンドラーを解除します。

TE.onGift(name, fn)

名前が一致するギフト(大文字小文字を区別しない部分一致)でのみ発火します。`name`を省略するとすべてのギフトを受け取ります。

TE.onSticker(idOrUrl, fn)

特定のサブスクエモート/ステッカーひとつでのみ発火します。TikTokのid、画像URL、またはsourceで照合します。

TE.rules.allowUser / allowGift

ロール、許可/拒否リスト、ギフト名、最低コイン数による再利用可能な参加条件フィルター。

TE.metrics

最新の配信スナップショットオブジェクト(viewers、likes、coins、followers、topGifters…)。TE.on('metrics', fn)でも受け取れます。

TE.demo

ウィジェットが見本として表示される場所(ギャラリー、プレビュータイル、ビルダーのDemoスイッチ)ではtrue。ライブのオーバーレイ上や、ビルダー・オーバーレイエディターでテストしている間はfalseで、自分で発火したものか実際に届いたものだけが表示されます。どのウィジェットもそこで自分自身を見せるので、実際のイベントに見えるサンプル(本物のギフト画像、名前、アイコン)をif (TE.demo)ブロックに入れ、ウィジェット本来のコードパスで流してください。このブロックを持つウィジェットにはホストからプレビューイベントが送られないため、二重に発火することはありません。

TE.defineSettings([...])

配信者が調整できるコントロールを宣言し、現在の値(デフォルトと配信者の選択をマージしたもの)を返します。

TE.settings

現在の設定値オブジェクト(defineSettingsが返したものと同じ形)。

TE.on('settings', fn)

配信者がライブ中に設定を変更したときに実行されます。新しい値で再描画してください。

TE.state.get/set/increment

合計値や共有ゲーム状態のための、Promiseベースのアトミックな値。

TE.collection.*

サーバー管理の一度きり参加者リストとスコア表:参加、加算、一覧、件数、削除、クリア。

TE.queue.*

メディア、リクエスト、視聴者が発動するアクション用の、上限付きサーバー管理FIFOキュー。

TE.shared.*

複数のウィジェットをひとつの名前付きチャンネル状態の名前空間に参加させます。無関係なウィジェットは分離されたままです。

TE.random.draw(name, opts)

コレクションから1人以上の当選者を安全に抽選し、結果を記録します。

TE.cooldown.claim(scope, user, ms)

グローバルまたはユーザーごとのクールダウンをアトミックに取得し、claimedとretryAfterMsを返します。

TE.timer.*

リロードしても続く、永続化された実時間タイマーの開始、一時停止、リセット、読み取り。

TE.points.trySpend(user, amount, reason)

ひとつのトランザクションでポイントの確認と引き落としを行います。有料のインタラクションを実行する前に、必ずresult.okを確認してください。

04

トリガー

購読できるライブイベント。すべてのuserには{ id, name, username, avatar, roles }が含まれます。

TE.on('gift')

視聴者がギフトを贈りました。coins = コンボの合計、streakEndはコンボの終了を示します。

{ user, gift: { name, image|null, coins, repeat, combo, streakEnd } }
TE.on('follow')

視聴者がアカウントをフォローしました。

{ user }
TE.on('subscribe')

視聴者がサブスクしました。months = 連続月数。

{ user, months }
TE.on('share')

視聴者がライブをシェアしました。

{ user }
TE.on('chat')

チャットメッセージ。emotes = このメッセージ内のサブスクエモート画像URL。

{ user, comment, emotes:[url,…] }
TE.on('like')

視聴者がいいねを送りました。count = 今回の連打数、total = 累計。

{ user, count, total }
TE.on('join')

視聴者がルームに入室しました。isTop = トップギフターが入室。

{ user, isTop }
TE.on('sticker')

ライブ中に送られたサブスクエモートまたは画面上のステッカー。url = エモート画像、id = そのTikTok id。

{ user|null, id|null, url, source }
TE.on('metrics')

最新の配信スナップショット。TE.metricsが保持し、更新されるたびにイベントが発火します。hostNickとhostAvatarは配信者本人の名前とプロフィール画像です。

{ live, viewers, likes, followers, coins, hostNick, hostAvatar, topGifters:[…], … }
TE.on('milestone')

キリのいい数字の節目を超えました(いいね、コイン、フォロワー、サブスク)。

{ metric, value, label }
TE.on('poll')

TikTok標準のライブ投票。開始から終了まで実際の投票。

{ state:'start'|'update'|'end', title, options:[{text,votes}], endsAt }
TE.on('battle')

LinkMicバトルの更新:バトルカード、ファンチケット、応援団の規模。

{ card|null, tickets|null, armies|null, battleId|null }
TE.on('rank')

時間別ランキングの順位とランクアップの瞬間。

{ rank|null, from|null, to|null, countdown|null }
TE.on('envelope')

ライブで紅包/宝箱がドロップされました。

{ }
TE.on('pinned')

ホストがコメントをピン留めしました。

{ text }
TE.on('deleted')

モデレーターがチャットメッセージを削除しました(idは以前のchatイベントと一致)。

{ id }
TE.on('streamState')

配信がオンラインまたはオフラインになりました。

{ live }
TE.on('apiEvent')

Event API経由で送信されたカスタムイベント。apiEventを購読するか、そのカスタム名を直接購読します。

{ name, data }
TE.on('nowPlaying')

配信者が再生中のSpotifyの曲と、次に流れるキュー。接続時と、曲、再生状態、再生位置、キューが変わるたびに発火します。何も再生していないときplaybackはnull、queueは次に流れる曲のリストです。

{ connected, playback: { isPlaying, progressMs, durationMs, title, artists:[…], album, artwork|null } | null, queue:[{ title, artist, artwork|null, durationMs }] }
特定のギフトやエモートひとつだけ
TE.onGift('Rose', function (ev) { /* … */ });
TE.onSticker('<sticker id>', function (ev) { /* … */ });

チャンネルのエモートはウィジェットビルダーにあります。イベントをシミュレートを開き、ステッカーを選んでひとつ選択してください。テストイベントには実際のidと画像URLが入っているので、どちらをキーにしたハンドラーも本物でテストできます。

05

アクション

ウィジェットが反応としてできること。普通のブラウザAPIで、そのまま貼り付けられます。

画像を表示

ギフト/エモートの画像、アップロードしたアセット、任意のURLの画像を画面に表示。数秒後に自動で消えます。

// Show an image, then fade it out
TE.on('gift', function (ev) {
  var img = document.createElement('img');
  img.src = ev.gift.image;                 // ← any image URL works
  img.style.cssText = 'position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:60%';
  document.body.appendChild(img);
  setTimeout(function () { img.remove(); }, 4000);   // ← how long it stays
});
効果音を再生

イベントで音声を再生。sound設定を用意すれば、配信者がコードを編集せずに自分のファイルを選べます。

// Play a sound the streamer chose in settings
var s = TE.defineSettings([{ key: 'sfx', label: 'Alert sound', type: 'sound', default: '' }]);
TE.on('settings', function (ns) { s = ns; });
TE.on('gift', function (ev) {
  if (s.sfx) { var a = new Audio(s.sfx); a.volume = 0.8; a.play(); }
});
テキストを表示・アニメーション

動的なテキストを書き、クラスを切り替えてCSSアニメーションを再発動します。

// Announce the event with a CSS pop animation
var box = document.getElementById('box');   // your element in the HTML tab
TE.on('follow', function (ev) {
  box.textContent = ev.user.name + ' followed!';
  box.classList.remove('pop'); void box.offsetWidth; box.classList.add('pop');
});
ライブの数値を表示

画面上の数値を、視聴者数、いいね、コイン、フォロワーなどのライブ指標に連動させ、自動更新します。

// Keep a number in sync with the live stream
TE.on('metrics', function (m) {
  document.getElementById('count').textContent = m.viewers.toLocaleString();
});
読み上げ(TTS)

ブラウザの音声合成でイベントを読み上げます。ギフトやフォローのシャウトアウトに最適です。

// Text-to-speech shout-out
TE.on('gift', function (ev) {
  var u = new SpeechSynthesisUtterance(ev.user.name + ' sent ' + ev.gift.name);
  speechSynthesis.speak(u);
});
プレビュー(TE.demo)

どのウィジェットもギャラリーとビルダーで自分自身を見せます。本物のギフト画像、名前、アイコンを使った、実際のイベントに見えるサンプルで。ライブ中はTE.demoがfalseで、実際のイベントだけが表示されます。

// Preview samples through the real code path. Never on a live overlay.
if (TE.demo) {
  var GIFTS = [
    { name: 'Rose', coins: 1, image: 'https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/eba3a9bb85c33e017f3648eaf88d7189~tplv-obj.png' },
    { name: 'Perfume', coins: 20, image: 'https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/20b8f61246c7b6032777bb81bf4ee055~tplv-obj.png' }
  ];
  var NAMES = ['lunaa', 'nightowl_gaming_official'], n = 0;
  function sample() {
    n++;
    onGift({ user: { name: NAMES[n % 2], avatar: window.__TE_AVATAR }, gift: GIFTS[n % 2] });
  }
  sample();
  setInterval(sample, 6000);
}
状態を記憶(TE.store)

見た目の状態のためのシンプルな同期型の永続化。参加者、購入、共有スコアにはトランザクション対応のランタイムを使ってください。

// Persistent state: survives OBS reloads
var total = TE.store.get('total', 0);          // read (with default)
TE.on('gift', function (ev) {
  total += ev.gift.coins;
  TE.store.set('total', total);                 // write (auto-saved)
  render();
});
チャットコマンドに反応

完全一致のチャットコマンドとアトミックなコレクションで、安全な参加受付、投票、ルーレットが実現できます。

// One server-authoritative entry per viewer.
// A function keyword reads s.command on every message, so the
// streamer can change the command in settings without a reload.
TE.onCommand(function () { return s.command || '!join'; }, function (c) {
  TE.collection.join('entrants', c.user.id, c.user).then(function (result) {
    if (result.joined) renderCount(result.count);
  });
});
配信アクションを発動(TE.act)

オーバーレイのアラート、効果音、TTS、カウンター、耐久配信の時間追加、OBSのシーン切り替えをウィジェットから直接リクエスト。

// One call, one stream action
TE.act({ id: 'tts', message: 'New high score!' });
TE.act({ id: 'points', user: ev.user, amount: 50 });
視聴者ポイントを付与

ロイヤリティポイントの確認、消費、付与をトランザクションで行い、結果の残高を受け取ります。

// Only spin after the points were really debited
TE.onCommand(function () { return s.command || '!spin'; }, function (ev) {
  TE.points.trySpend(ev.user, 50, 'Wheel spin').then(function (result) {
    if (result.ok) spin();
    else showMissing(result.missing);
  });
});
公平なゲームを作る

アトミックな状態、コレクション、安全な抽選、クールダウン、永続タイマー。ブラウザソースが重複していても安全です。

// Fair draw from a server-owned entrant collection
TE.random.draw('entrants', { count: 1 }).then(function (result) {
  if (result.ok) reveal(result.winners[0].value);
});
配信者向けコントロールを追加

テキスト、色、数値、トグルを公開。配信者はオーバーレイエディターでライブ中に調整でき、コードは不要です。

// No-code controls for whoever uses the widget
var s = TE.defineSettings([
  { key: 'title',  label: 'Title', type: 'text',  default: 'Goal' },
  { key: 'accent', label: 'Color', type: 'color', default: '#FF2E4D' },
]);
document.body.style.setProperty('--accent', s.accent);
TE.on('settings', function (ns) { s = ns; /* re-render with new values */ });
06

配信者設定

TE.defineSettings([...])でコントロールを宣言すると、ウィジェットを使う人がオーバーレイエディターでライブ中に調整できます。コードは不要です。各フィールド:

'button'フィールドをひとつ以上持つ配置済みウィジェットは、オーバーレイエディター内の設定でそのアクションを表示します。ウィジェットビルダーでも、コーディング中に安全にプレビューテストできるよう同じボタンが表示されます。

タイプ表示されるもの値
'text'1行のテキスト入力string
'number'数値入力number
'color'カラーピッカーhex文字列(例:"#FF2E4D")
'select'ドロップダウン(options: [...]が必要)optionsのいずれか
'toggle'オン/オフスイッチboolean
'range'スライダー(min / max / step)number
'button'宣言型のアクションボタンincrement、set、toggleのいずれか。検証済みJSONで、ダッシュボードのコードは使いません
'sound'配信者がアップロードした効果音から選ぶピッカー+アップロード選んだファイルのURL("" = なし)
'image'配信者がアップロードした画像から選ぶピッカー+アップロード選んだファイルのURL("" = なし)
var s = TE.defineSettings([
  { key: 'title',  label: 'Title', type: 'text',   default: 'Follower goal' },
  { key: 'target', label: 'Goal',  type: 'number', default: 100 },
  { key: 'accent', label: 'Color', type: 'color',  default: '#FF2E4D' },
  { key: 'reset',  label: 'Reset', type: 'button', default: 0,
    action: { type: 'increment', step: 1 }, confirm: true, tone: 'danger' },
]);
// re-render when the streamer changes something live
var lastReset = s.reset;
TE.on('settings', function (ns) {
  s = ns;
  if (ns.reset !== lastReset) { lastReset = ns.reset; resetCounter(); }
  render();
});

コントロールの定義は検証されたデータです。ボタンのactionはincrement、set、toggleのみ受け付けます。HTML、コールバックコード、任意のURLは、ダッシュボードのレンダラーで拒否または無視されます。

07

サンドボックスと制限

ウィジェットは厳格なコンテンツセキュリティポリシーを持つ分離されたiframe内で動くため、壊れたウィジェットや悪意あるウィジェットがあなたのアカウントやページの他の部分に触れることはありません。

許可
  • 外部の画像とGIF(TikTokギフト画像、アイコン、任意のURL)
  • Google Fonts+独自の@font-face
  • new Audio(url)による音声
  • TokElements自身のAPIへのリクエスト(例:/api/files/…)
  • CSSアニメーション、SVG、canvas、Web Audio
ブロック
  • 外部の<script>タグ/CDN
  • 他のホストへのfetch / XHR / WebSocket
  • Cookie、localStorage、親ページへのアクセス
  • npmパッケージの読み込み
08

サンプル

そのままコピー&ペーストできる完成ウィジェット。各プレビューはライブで、デモイベントが発火するので反応を確認できます。

エモートリアクション· チャットでエモートが送られると表示
var img = document.getElementById('emote');
// fires for every emote — use TE.onSticker('<id>', …) for one specific one
TE.on('sticker', function (ev) {
  img.src = ev.url;
  img.classList.remove('show'); void img.offsetWidth; img.classList.add('show');
});
ライブプレビュー
フォロワー目標バー· バーをライブ指標に連動
var target = 200;                       // ← your goal
TE.on('metrics', function (m) {
  var pct = Math.min(100, m.follows / target * 100);
  document.getElementById('fill').style.width = pct + '%';
  document.getElementById('txt').textContent = m.follows + ' / ' + target;
});
ライブプレビュー