# ウィジェットビルダーのリファレンス

> KickBotウィジェットビルダーのコードリファレンス。Kickのイベント名とペイロード、globalValues、userVariables、チャット用ヘルパー、プレビューでのコードの動き方をまとめています。

Source: https://kickbot.com/ja/docs/widgets/widget-builder-reference

このページでは、KickBotの[ウィジェットビルダー](https://kickbot.com/ja/docs/widgets/widget-builder)で作るウィジェットのコードで使えるものをまとめています。`widgetEvent`イベント、`globalValues`オブジェクト、`userVariables`オブジェクト、`window.kickbotWidget`ヘルパーです。ウィジェットはどれも普通のHTML、CSS、JavaScriptで、OBSのブラウザソースとして動きます。KickBotが代わりにKickに接続し、イベントをコードに送ります。

## ウィジェットが動くしくみ

OBSがウィジェットのURLを開くと、KickBotは次の処理を行います。

1. 背景が透明なウィジェットページを読み込みます。
2. CSSを`<style>`要素に入れ、HTMLをページに入れます。
3. Kickからチャンネルのデータ（フォロワー数、視聴者数、配信の状態、最近のチャット）を読み込み、`globalValues`に入れます。
4. JavaScriptを実行します。実行はステップ3のあとに1回だけなので、コードが動き始めた時点で`globalValues`は準備できています。
5. リアルタイムのイベントを、`document`上の`widgetEvent`イベントとしてコードに送ります。

JavaScriptからは、何もインポートせずに`globalValues`と`userVariables`の2つのオブジェクトを読めます。ヘルパーは`window.kickbotWidget`にあります。

上限：

| 項目 | 上限 |
| --- | --- |
| 幅と高さ | **基本設定**で設定します。新しい空白のウィジェットは800 × 600です。新しいウィジェットのポップアップでは7680 × 4320まで設定できます。 |
| HTML、CSS、JavaScript | 1ファイル2,000,000文字まで |
| ウィジェット名 | 500文字まで |
| ユーザー変数のファイル | 1ファイル25MBまで |
| 無料プランで作れるビルダーのウィジェット | 10個（Premiumは上限なし） |

## イベントを受け取る

`document`に`widgetEvent`のリスナーを1つ追加します。各イベントの`event.detail`には3つのフィールドがあります。

| フィールド | 型 | 値 |
| --- | --- | --- |
| `event_name` | string | イベント名（例：`followEvent`） |
| `source` | string | 常に`kick` |
| `data` | object | イベントのペイロード（下記参照） |

```javascript
document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;

    if (event_name === 'followEvent') {
        showAlert(data.user.username + ' followed!');
    }
    if (event_name === 'subEvent') {
        showAlert(data.username + ' subscribed for ' + data.months + ' months');
    }
});
```

### イベント一覧

| イベント名 | 発生するとき | テストボタン |
| --- | --- | --- |
| `subEvent` | 視聴者がサブスク登録した | サブスク |
| `subGiftEvent` | 視聴者がサブスクをギフトした | ギフトサブスク |
| `kicksEvent` | 視聴者がKICKsを送った | KICKs |
| `followEvent` | 視聴者がフォローした | フォロー |
| `unfollowEvent` | 視聴者がフォローを解除した | フォロー解除 |
| `chatMessageEvent` | チャットメッセージが送られた | メッセージ |
| `chatMessageDeletedEvent` | モデレーターがメッセージを削除した | メッセージ削除 |
| `chatMessagePinnedEvent` | メッセージがピン留めされた | メッセージのピン留め |
| `chatMessageUnpinnedEvent` | ピン留めメッセージが外された | メッセージのピン留め解除 |
| `chatClearedEvent` | モデレーターがチャットをクリアした | チャットのクリア |
| `followerCountUpdatedEvent` | Kickが新しいフォロワー数を送った | フォロワー数の更新 |
| `subCountUpdatedEvent` | Kickのサブスク数が変わった | サブスク数の更新 |
| `viewerCountUpdatedEvent` | Kickが新しい視聴者数を送った | 視聴者数の更新 |
| `raidEvent` | ほかのチャンネルが自分のチャンネルにレイド（ホスト）した | レイド |
| `streamOnline` | 配信が始まった | 配信開始 |
| `streamOffline` | 配信が終わった | 配信終了 |

投げ銭のイベントはありません。投げ銭アラートには、[投げ銭アラートウィジェット](https://kickbot.com/ja/docs/tipping/tip-alerts)を使ってください。

### イベントのペイロード

`event.detail.data`に入るペイロードです。エディターのテストイベントと同じ形です。実際のイベントには、ほかのフィールドが含まれることもあります。ここにある名前、数字、IDは例です。

`subEvent`

```javascript
{
    months: 1,
    username: 'viewer_one',
    chatroom_id: 3847194
}
```

`subGiftEvent`

```javascript
{
    chatroom_id: 3847194,
    gifted_usernames: ['viewer_one', 'viewer_two', 'viewer_three'],
    gifter_username: 'big_gifter'
}
```

`kicksEvent`

```javascript
{
    message: 'Great stream!',
    sender: { id: 12345678, username: 'viewer_one', username_color: '#93EBE0' },
    gift: {
        gift_id: 'full_send',
        name: 'Full Send',
        amount: 100,
        type: 'BASIC',
        tier: 'BASIC',
        character_limit: 0,
        pinned_time: 0
    },
    channel: 'channel_3984507'
}
```

`followEvent`と`unfollowEvent`（同じ形です。`followers_count`は新しいフォロワー数です）

```javascript
{
    id: 'd4e5f6a7-89b0-12c3-d456-78901e2f3a4b',
    channel: { id: 3984507, slug: 'kickbotdev' },
    user: { id: 14873539, slug: 'viewer_one', username: 'viewer_one' },
    followers_count: 36,
    created_at: '2024-05-13T22:19:07+00:00'
}
```

`chatMessageEvent`

```javascript
{
    id: '85c884b3-7377-478c-b6aa-22b7db752b93',
    chatroom_id: 3974112,
    content: 'hello [emote:37226:KEKW]',
    type: 'message',
    created_at: '2024-05-13T22:29:52+00:00',
    sender: {
        id: 4063326,
        username: 'viewer_one',
        slug: 'viewer_one',
        identity: {
            color: '#72ACED',
            badges: [{ type: 'subscriber', text: 'Subscriber', count: 3 }]
        }
    }
}
```

Kickのエモートは、`content`の中に`[emote:ID:NAME]`の形で入っています。画像に変換するには、`createChatMessageFragment`を使います（[チャットのテキストを安全に表示する](#show-chat-text-safely)を参照）。

`chatMessageDeletedEvent`

```javascript
{
    id: '9cd3788a-ecd2-4051-a162-a7ea9be8ce7a',
    message: { id: '89d6be86-63db-4581-922e-14a6c4a9c2e6' }
}
```

表示したメッセージを探して消すには、`data.message.id`を使います。

`chatMessagePinnedEvent`（`data.message`は`chatMessageEvent`のペイロードと同じ形です）

```javascript
{
    message: {
        id: '5d798a38-ad17-45e4-8169-bda2faa85b79',
        chatroom_id: 3974112,
        content: 'This is a pinned message!',
        type: 'message',
        created_at: '2024-05-13T22:30:41+00:00',
        sender: { id: 4063326, username: 'kickbotdev', slug: 'kickbotdev', identity: { color: '#72ACED', badges: [] } }
    }
}
```

`chatMessageUnpinnedEvent`：`data`は空の配列（`[]`）です。

`chatClearedEvent`

```javascript
{ id: '47e3596f-0274-46e0-85b1-029fa3bfc5ea' }
```

`followerCountUpdatedEvent`（キャメルケースの`followersCount`に注意してください）

```javascript
{ followersCount: 1532, channel_id: 4599, created_at: 1715639984 }
```

`subCountUpdatedEvent`

```javascript
{ subscriber_count: 184, channel_id: 4599 }
```

`viewerCountUpdatedEvent`

```javascript
{ viewer_count: 320, channel_id: 5937485 }
```

`raidEvent`

```javascript
{
    chatroom_id: 839485,
    optional_message: 'gg stream',
    number_viewers: 150,
    host_username: 'raiding_channel'
}
```

`streamOnline`

```javascript
{
    livestream: {
        id: 3984507,
        channel_id: 3984507,
        session_title: 'Test stream!',
        created_at: '2024-05-13T22:30:41+00:00'
    }
}
```

`streamOffline`

```javascript
{
    livestream: {
        id: 3984507,
        channel: { id: 3984507, is_banned: false }
    }
}
```

## グローバル値

`globalValues`には、チャンネルの現在の状態が入っています。KickBotはコードが動く前に値を入れ、イベントが届くたびに最新の状態に保ちます。イベントが届く前の最初の表示に使ってください。

```javascript
globalValues = {
    subCount: 184,
    followerCount: 1532,
    viewerCount: 320,
    lastFollower: { /* the last follow */ },
    lastSub: { /* the last sub, for example { username, months } */ },
    lastGiftedSub: { /* the last gift, for example { gifter_username, gifted_usernames } */ },
    chatMessages: [ /* chatMessageEvent payloads */ ],
    streamerInfo: {
        kick: {
            username: 'KickBotDev',
            slug: 'kickbotdev',
            profile_picture: 'https://files.kick.com/images/user/.../fullsize.webp',
            user_id: '4063326',
            channel_id: '3984507',
            chatroom_id: '3974112',
            bio: 'Channel bio',
            subscriber_badges: [ /* your channel's sub badges from Kick */ ]
        }
    },
    currentStream: {
        is_live: true,
        title: 'Stream title',
        started_at: '2026-10-24 18:00:00'
    }
}
```

| 値 | 更新のされ方 |
| --- | --- |
| `subCount` | Kickから読み込みます。`subEvent`1回ごとに1、ギフトサブスク1件ごとに1増え、`subCountUpdatedEvent`で設定し直されます。 |
| `followerCount` | Kickから読み込みます。`followEvent`、`unfollowEvent`、`followerCountUpdatedEvent`で設定されます。 |
| `viewerCount` | Kickから読み込みます（オフライン時は0）。`viewerCountUpdatedEvent`で設定されます。 |
| `lastFollower`、`lastSub`、`lastGiftedSub` | KickBotがチャンネルで最後に記録したもの。なければ`null`。対応するイベントで更新されます。 |
| `chatMessages` | ウィジェットを読み込んだときのKickの最近のチャットと、その後の新しいメッセージ。新しいものから100件を保持します。`chatClearedEvent`で空になります。削除されたメッセージを隠すには、自分のコードで`chatMessageDeletedEvent`を処理してください。 |
| `streamerInfo.kick` | Kickのプロフィール。ウィジェットの実行中は変わりません。 |
| `currentStream` | ウィジェットを読み込んだときにKickから読み込みます。`streamOnline`や`streamOffline`では更新されません。配信中かどうかをリアルタイムで知りたい場合は、これらのイベントを受け取ってください。 |

## ユーザー変数

ユーザー変数は、配信者が保存したウィジェットでウィジェットを開いたときに表示される設定です。エディターの**ユーザー変数**で追加します。コードでは`userVariables.<variable name>.value`で値を読みます。

```javascript
const goal = Number(userVariables.follower_goal.value);
document.body.style.color = userVariables.text_color.value;
```

変数のフィールド：

| フィールド | 内容 |
| --- | --- |
| タイトル | 配信者に表示されるラベル。 |
| 変数名 | コードで使う名前。使えるのは英字、数字、`_`だけです。変数を作ったあとは変更できません。 |
| ツールチップ | タイトルの下に出る補足のヘルプテキスト。 |
| 変数の種類 | 下の表をご覧ください。 |
| デフォルト値 | 配信者が変更する前の値。空でもかまいません。 |
| 必須 | 配信者は値を入力しないと保存できません。 |

| 種類 | 配信者に表示されるもの | コードでの`value` |
| --- | --- | --- |
| テキスト | テキストボックス | 文字列 |
| 数値 | 数値ボックス | 数値、または数字の文字列。念のため`Number()`を使ってください。 |
| 色 | カラーピッカー | 16進数の色の文字列（例：`#ffffff`） |
| ドロップダウン | 設定した選択肢のメニュー | 選ばれた選択肢の文字列。デフォルトは最初の選択肢です。 |
| トグル | オン/オフのスイッチ | `true`または`false` |
| 画像/GIF | URLボックスとアップロードボタン | ファイルのURL |
| 動画 | URLボックスとアップロードボタン | ファイルのURL |
| 音声 | URLボックスとアップロードボタン | ファイルのURL |

アップロードしたファイルはKickBotに保存され、`value`はファイルのURLになります。変数の横のメニューで、上下に移動、編集、削除ができます。エディターでの並び順が、配信者に表示される順番です。

## チャットのテキストを安全に表示する

イベントのフィールドとユーザー変数は、すべて知らない人が書いたテキストとして扱ってください。KickBotはチャットとイベントのテキストをコードに渡す前にクリーンにしているので、HTMLのテキストとしては安全ですが、URL、CSS、スクリプトとしては安全ではありません。イベントのフィールドをそのまま`innerHTML`に入れないでください。次のヘルパーを使います。

| ヘルパー | 内容 |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | テキストノードとKickのエモート画像が入った`DocumentFragment`を返します。エモートのサイズは`font_size + 3`ピクセルです。`font_size`のデフォルトは20です。 |
| `window.kickbotWidget.createTextNode(value)` | どんな値でもテキストノードにして返します。 |
| `window.kickbotWidget.escapeHtmlText(value)` | どうしてもHTMLの文字列を組み立てる必要があるときに、HTMLタグの間に入れるテキストをエスケープします。URL、CSS、スクリプトには使わないでください。 |

```javascript
document.addEventListener('widgetEvent', (event) => {
    if (event.detail.event_name !== 'chatMessageEvent') return;
    const data = event.detail.data;

    const line = document.createElement('div');
    line.id = 'msg-' + data.id;
    const name = document.createElement('strong');
    name.style.color = data.sender.identity.color;
    name.append(window.kickbotWidget.createTextNode(data.sender.username + ': '));
    line.append(name);
    line.append(window.kickbotWidget.createChatMessageFragment(data.content, 20));
    document.getElementById('chat').append(line);
});
```

それ以外のテキストには、`textContent`か`createTextNode`を使ってください。

## プレビュー

エディターのプレビューはOBSと同じように動きますが、テスト用にいくつか違いがあります。

- コードやユーザー変数を変えると、プレビューはJavaScriptをもう一度実行します。その前に、KickBotは前回の実行で追加された`widgetEvent`のリスナーを外します。`setInterval`と`setTimeout`のタイマーは外されないので、たまってきたら再読み込みボタンをクリックしてください。
- 幅や高さを変えると、プレビューが再読み込みされます。
- テストイベントはプレビューにだけ送られます。テストの**フォロー**は`globalValues.followerCount`に1を足し、**フォロー解除**は1を引きます。**視聴者数の更新**はサンプルの数字を送ります。**メッセージ削除**は、プレビューのチャットからランダムに1件のメッセージを消します。
- チャンネルにまだ最新のフォロワー、サブスク、ギフトサブスクがない場合、プレビューでは`lastFollower`、`lastSub`、`lastGiftedSub`にサンプルのデータを使います。
- `console.log`の出力やエラーを見るには、ポップアウトボタンをクリックし、そのウィンドウで開発者ツールを開きます。

## 例：フォロワー目標

短いフォロワー目標の例です。イベントリスナー、`globalValues`、2つのユーザー変数`follower_goal`（数値）と`bar_color`（色）を使います。

HTML：

```html
<div class="goal">
    <span id="count"></span> / <span id="target"></span>
    <div class="bar"><div class="fill"></div></div>
</div>
```

CSS：

```css
body { margin: 0; font-family: Arial, sans-serif; color: #fff; }
.goal { padding: 12px; background: #100c28; border-radius: 16px; font-size: 32px; font-weight: bold; }
.bar { height: 24px; margin-top: 8px; background: #3d3957; border-radius: 12px; overflow: hidden; }
.fill { height: 100%; width: 0; transition: width 0.3s ease; }
```

JavaScript：

```javascript
const target = Number(userVariables.follower_goal.value) || 100;
document.getElementById('target').textContent = target;
document.querySelector('.fill').style.background = userVariables.bar_color.value;

function update(count) {
    document.getElementById('count').textContent = count;
    document.querySelector('.fill').style.width = Math.min((count / target) * 100, 100) + '%';
}

document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;
    if (event_name === 'followEvent' || event_name === 'unfollowEvent') update(data.followers_count);
    if (event_name === 'followerCountUpdatedEvent') update(data.followersCount);
});

update(globalValues.followerCount);
```

設定がもっと多い完全版がほしい場合は、**Simple Follower Goal**テンプレートから新しいウィジェットを作ってください。

## ヒント

- 最初の状態は`globalValues`から描画し、イベントが来たら変えるようにします。イベントを待つだけのウィジェットは、何かが起きるまで空のままに見えます。
- 保存したウィジェットには、JavaScriptに書かれているイベント名のテストボタンだけが表示されます。配信者がウィジェットをテストできるように、コードにはイベント名を省略せずに書いてください（例：`'followEvent'`）。
- デザインに背景が必要な場合を除き、背景は透明のままにします。そうすると、ウィジェットがシーンの上に重なります。
- ビルダーのウィジェットは、KickBot APIでも管理できます。[ウィジェットAPIのリファレンス](https://kickbot.com/docs/api/reference/widgets)をご覧ください。
