# Widget oluşturucu referansı

> KickBot widget oluşturucu için kod referansı: her Kick olay adı ve verisi, globalValues, userVariables, chat yardımcıları ve önizlemenin kodu nasıl çalıştırdığı.

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

Bu sayfa, KickBot [widget oluşturucu](https://kickbot.com/tr/docs/widgets/widget-builder) widget'larında kodunun kullanabileceği her şeyi listeler: `widgetEvent` olayları, `globalValues` nesnesi, `userVariables` nesnesi ve `window.kickbotWidget` yardımcıları. Her widget, OBS'de tarayıcı kaynağı olarak çalışan düz HTML, CSS ve JavaScript'tir. KickBot senin yerine Kick'e bağlanır ve olayları koduna gönderir.

## Widget nasıl çalışır

OBS widget URL'sini açtığında KickBot:

1. Widget sayfasını şeffaf arka planla yükler.
2. CSS'ini bir `<style>` öğesine ekler ve HTML'ini sayfaya koyar.
3. Kanal verilerini Kick'ten (takipçi sayısı, izleyici sayısı, yayın durumu ve son chat mesajları) `globalValues` içine yükler.
4. JavaScript'ini çalıştırır. Kod 3. adımdan sonra bir kez çalışır, yani kodun başladığında `globalValues` hazırdır.
5. Canlı olayları koduna `document` üzerinde `widgetEvent` olayları olarak gönderir.

JavaScript'in hiçbir şey içe aktarmadan iki nesneyi okuyabilir: `globalValues` ve `userVariables`. Yardımcılar `window.kickbotWidget` üzerindedir.

Sınırlar:

| Öğe | Sınır |
| --- | --- |
| Genişlik ve yükseklik | **Temel ayarlar**'dan belirlenir. Yeni boş widget 800 × 600'dür. Yeni widget penceresi en fazla 7680 × 4320 kabul eder. |
| HTML, CSS ve JavaScript | Dosya başına en fazla 2.000.000 karakter |
| Widget adı | En fazla 500 karakter |
| Kullanıcı değişkenleri için dosyalar | Dosya başına en fazla 25 MB |
| Ücretsiz planda oluşturucu widget'ları | 10 (Premium'da sınır yok) |

## Olayları dinle

`document` üzerine `widgetEvent` için tek bir dinleyici ekle. Her olayda üç alanlı bir `event.detail` vardır:

| Alan | Tür | Değer |
| --- | --- | --- |
| `event_name` | string | Olay, örneğin `followEvent` |
| `source` | string | Her zaman `kick` |
| `data` | object | Olay verisi (aşağıya bak) |

```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');
    }
});
```

### Olay listesi

| Olay adı | Ne zaman tetiklenir | Test düğmesi |
| --- | --- | --- |
| `subEvent` | Bir izleyici abone olur | Sub |
| `subGiftEvent` | Bir izleyici hediye abonelik verir | Hediye sub |
| `kicksEvent` | Bir izleyici KICKs gönderir | KICKs |
| `followEvent` | Bir izleyici takip eder | Follow |
| `unfollowEvent` | Bir izleyici takibi bırakır | Unfollow |
| `chatMessageEvent` | Bir chat mesajı gönderilir | Mesaj |
| `chatMessageDeletedEvent` | Bir moderatör mesaj siler | Mesaj silindi |
| `chatMessagePinnedEvent` | Bir mesaj sabitlenir | Mesaj sabitlendi |
| `chatMessageUnpinnedEvent` | Sabitlenen mesaj kaldırılır | Mesaj sabitlemesi kaldırıldı |
| `chatClearedEvent` | Bir moderatör chat'i temizler | Sohbet temizlendi |
| `followerCountUpdatedEvent` | Kick yeni bir takipçi sayısı gönderir | Follower sayısı güncellendi |
| `subCountUpdatedEvent` | Kick'teki abone sayısı değişir | Sub sayısı güncellendi |
| `viewerCountUpdatedEvent` | Kick yeni bir izleyici sayısı gönderir | İzleyici sayısı güncellendi |
| `raidEvent` | Başka bir kanal sana raid atar (host eder) | Raid |
| `streamOnline` | Yayının başlar | Yayın başladı |
| `streamOffline` | Yayının biter | Yayın kapandı |

Bahşiş olayı yok. Bahşiş alertleri için [bahşiş alerti widget'ını](https://kickbot.com/tr/docs/tipping/tip-alerts) kullan.

### Olay verileri

Bunlar `event.detail.data` içindeki verilerdir. Editördeki test olaylarıyla aynıdır. Gerçek olaylarda daha fazla alan olabilir. Buradaki adlar, sayılar ve ID'ler örnektir.

`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` ve `unfollowEvent` (aynı yapı; `followers_count` yeni sayıdır)

```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 emote'ları `content` içinde `[emote:ID:NAME]` olarak gelir. Onları görsele çevirmek için `createChatMessageFragment` kullan ([Chat metnini güvenle göster](#show-chat-text-safely) bölümüne bak).

`chatMessageDeletedEvent`

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

Gösterdiğin mesajı bulup kaldırmak için `data.message.id` kullan.

`chatMessagePinnedEvent` (`data.message`, `chatMessageEvent` verisiyle aynı yapıdadır)

```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` boş bir dizidir (`[]`).

`chatClearedEvent`

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

`followerCountUpdatedEvent` (camelCase yazılan `followersCount`'a dikkat et)

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

## Genel değerler

`globalValues`, kanalının o anki durumunu tutar. KickBot onu kodun çalışmadan önce doldurur ve olaylar geldikçe güncel tutar. Widget'ını, daha hiçbir olay gelmeden en başta çizmek için kullan.

```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'
    }
}
```

| Değer | Nasıl güncellenir |
| --- | --- |
| `subCount` | Kick'ten yüklenir. Her `subEvent` için 1, her hediye abonelik için 1 artar ve `subCountUpdatedEvent` ile yeniden ayarlanır. |
| `followerCount` | Kick'ten yüklenir. `followEvent`, `unfollowEvent` ve `followerCountUpdatedEvent` ile ayarlanır. |
| `viewerCount` | Kick'ten yüklenir (yayında değilken 0). `viewerCountUpdatedEvent` ile ayarlanır. |
| `lastFollower`, `lastSub`, `lastGiftedSub` | KickBot'un kanalında gördüğü sonuncusu ya da `null`. İlgili olayla güncellenir. |
| `chatMessages` | Widget yüklendiğinde Kick'ten gelen son chat mesajları, sonra her yeni mesaj. En yeni 100 mesajı tutar. `chatClearedEvent` listeyi boşaltır. Silinen mesajları gizlemek için kendi kodunda `chatMessageDeletedEvent`'i işle. |
| `streamerInfo.kick` | Kick profilin. Widget çalışırken değişmez. |
| `currentStream` | Widget yüklendiğinde Kick'ten yüklenir. `streamOnline` veya `streamOffline` ile güncellenmez. Canlı durumu bilmen gerekiyorsa bu olayları dinle. |

## Kullanıcı değişkenleri

Kullanıcı değişkenleri, yayıncıların widget'ını Kayıtlı widget'larda açtığında gördüğü ayarlardır. Onları editörde **Kullanıcı değişkenleri** altında eklersin. Kodunda değeri `userVariables.<variable name>.value` ile oku.

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

Bir değişkenin alanları:

| Alan | Ne işe yarar |
| --- | --- |
| Başlık | Yayıncıların gördüğü etiket. |
| Değişken adı | Kodundaki ad. Sadece harf, rakam ve `_`. Değişkeni oluşturduktan sonra değiştiremezsin. |
| Tooltip | Başlığın altındaki ek yardım metni. |
| Değişken türü | Aşağıdaki tabloya bak. |
| Varsayılan değer | Yayıncı değiştirmeden önceki değer. Boş olabilir. |
| Zorunlu | Yayıncılar kaydetmeden önce bir değer girmek zorundadır. |

| Tür | Yayıncının gördüğü | Kodundaki `value` |
| --- | --- | --- |
| Metin | Bir metin kutusu | Bir string |
| Sayı | Bir sayı kutusu | Bir sayı veya sayısal bir string. Garanti olsun diye `Number()` kullan. |
| Renk | Bir renk seçici | Bir hex renk string'i, örneğin `#ffffff` |
| Açılır menü | Senin seçeneklerinin olduğu bir menü | Seçilen seçenek, string olarak. Varsayılan ilk seçenektir. |
| Anahtar | Bir aç/kapat anahtarı | `true` veya `false` |
| Görsel/GIF | Bir URL kutusu ve yükleme düğmesi | Dosyanın URL'si |
| Video | Bir URL kutusu ve yükleme düğmesi | Dosyanın URL'si |
| Ses | Bir URL kutusu ve yükleme düğmesi | Dosyanın URL'si |

Yüklenen dosyaları KickBot saklar ve `value` dosyanın URL'sidir. Bir değişkeni yukarı veya aşağı taşımak, düzenlemek ya da silmek için yanındaki menüyü kullan. Editördeki sıra, yayıncıların gördüğü sıradır.

## Chat metnini güvenle göster

Her olay alanını ve kullanıcı değişkenini bir yabancıdan gelen metin gibi düşün. KickBot chat ve olay metnini koduna ulaşmadan önce temizler. Bu yüzden HTML metni olarak güvenlidir ama URL, CSS veya script olarak değil. Ham olay alanlarını `innerHTML` içine koyma. Şu yardımcıları kullan:

| Yardımcı | Ne yapar |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | Metin düğümleri ve Kick emote görselleri içeren bir `DocumentFragment` döndürür. Emote'lar `font_size + 3` piksel olur. `font_size` varsayılan olarak 20'dir. |
| `window.kickbotWidget.createTextNode(value)` | Herhangi bir değer için bir metin düğümü döndürür. |
| `window.kickbotWidget.escapeHtmlText(value)` | Mutlaka bir HTML string'i oluşturman gerektiğinde, metni HTML etiketleri arasında kullanmak için kaçışlar. URL, CSS veya script için kullanma. |

```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);
});
```

Diğer metinler için `textContent` veya `createTextNode` kullan.

## Önizleme

Editördeki önizleme OBS gibi çalışır, test için birkaç fark var:

- Kodu veya bir kullanıcı değişkenini değiştirdiğinde önizleme JavaScript'ini yeniden çalıştırır. KickBot önce bir önceki çalıştırmadan kalan `widgetEvent` dinleyicilerini kaldırır. `setInterval` ve `setTimeout` zamanlayıcıları kaldırılmaz, birikirlerse yenile düğmesine tıkla.
- Genişliği veya yüksekliği değiştirdiğinde önizleme yeniden yüklenir.
- Test olayları sadece önizlemeye gider. Test **Follow** olayı `globalValues.followerCount` değerine 1 ekler, **Unfollow** 1 çıkarır. **İzleyici sayısı güncellendi** örnek bir sayı gönderir. **Mesaj silindi** önizleme chat'inden rastgele bir mesajı kaldırır.
- Kanalında henüz son takipçi, abone veya hediye abonelik yoksa önizleme `lastFollower`, `lastSub` ve `lastGiftedSub` için örnek veri kullanır.
- `console.log` çıktısını ve hataları görmek için açılır pencere düğmesine tıkla ve o pencerede geliştirici araçlarını aç.

## Örnek: takipçi hedefi

Bu kısa bir takipçi hedefi. Bir olay dinleyicisi, `globalValues` ve iki kullanıcı değişkeni kullanır: `follower_goal` (Sayı) ve `bar_color` (Renk).

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

Daha fazla ayarı olan tam sürüm için **Simple Follower Goal** şablonundan yeni bir widget başlat.

## İpuçları

- İlk durumu `globalValues`'tan çiz, sonra olaylarda değiştir. Bir olay bekleyen widget, bir şey olana kadar boş görünür.
- Kayıtlı widget'lar sadece JavaScript'inde geçen olay adları için test düğmeleri gösterir. Yayıncılar widget'ını test edebilsin diye kodunda olay adının tamamını yaz (örneğin `'followEvent'`).
- Arka plan tasarımın bir parçası değilse şeffaf bırak, böylece widget sahnenin üstünde durur.
- Oluşturucu widget'larını KickBot API ile de yönetebilirsin. [Widget API referansı](https://kickbot.com/docs/api/reference/widgets) sayfasına bak.
