StreamElements Custom Widgets

repository·master·Indexed 43 days ago

https://github.com/streamelements/widgets

A community-driven repository and documentation for developing, hosting, and sharing custom widgets for StreamElements.com. Includes guides on creating custom widgets using HTML, CSS, and JS, utilizing the SE_API for data persistence and event queuing, and configuring specific community widgets like Alerts BingTTS, Heart Engagement, and NanoleafLightingOnEvents.

Tokens
14.7K
Snippets
28
Records
47
Agent score
55%

What's inside StreamElements

  1. Understand the StreamElements Custom Code Editor structure

    master

    The StreamElements Custom Code Editor allows you to build widgets using three primary components: HTML, CSS, and JS.

    • HTML: Supports all standard HTML tags. You can import external libraries (like jQuery) or fonts (like Google Fonts) using <script> or <link> tags.
    • CSS: Supports standard CSS syntax, including animations and transitions. You can also use @import to bring in external stylesheets.
    • JS: Supports pure JavaScript and external frameworks.

    Important Sandbox Restrictions: JavaScript runs in a protected sandbox. You cannot access:

    • Cookies
    • console.* methods
    • IndexedDB storage
  2. Access recent events via `recents` or `*-recent` keys

    master

    You can access a list of recent events in two ways:

    1. Use the recents variable provided in the onWidgetLoad event.
    2. Use specific keys within the data object (e.g., data["follower-recent"]).

    Both return an array of up to 25 elements. Each element in the array contains:

    • name: The username.
    • createdAt: An ISO timestamp (e.g., "2018-06-11T08:08:33.180Z").
    • $hashKey: A unique identifier (e.g., "object:5024").
    • type: The event type ("follower", "subscriber", "host", "raid", "cheer", or "tip").

    Type-specific fields:

    • subscriber-recent: Includes tier (e.g., 1000, 2000, 3000) and amount (number of months).
    • host-recent: Includes amount (number of viewers).
    • raid-recent: Includes amount (number of viewers).
    • cheer-recent: Includes amount (number of bits).
    • tip-recent: Includes amount (amount of tip).
    let recentFollows = data["follower-recent"][0]; 
    // recentFollows contains: name, createdAt, $hashKey, type
  3. Use onSessionUpdate for session-wide data

    master

    The onSessionUpdate event is triggered whenever session data is updated (e.g., new tips, cheers, or followers).

    When to use onSessionUpdate vs onEventReceived:

    • Use onEventReceived for most real-time UI reactions (better performance and easier to implement).
    • Use onSessionUpdate when you need access to the full session state, such as checking if the top donator or top cheering user has changed.

    The obj.detail.session object contains keys like tip-session-top-donator and cheer-session-top-donator.

    window.addEventListener('onSessionUpdate', function (obj) {
        const data = obj.detail.session;
        
        // Access top donator info
        const topDonator = data["tip-session-top-donator"];
        if (topDonator) {
            document.getElementById("top-donator").textContent = `${topDonator.name} - ${topDonator.amount}`;
        }
    });
  4. Understand the difference between `donation` and `donator` keys

    master

    When accessing tip or cheer data, the terminology used in the keys determines whether you are looking at a single event or a cumulative total:

    • *-donation: Refers to a single event. This represents the largest one-time donation or cheer recorded within the specified period.
    • *-donator: Refers to the cumulative amount. This represents the sum of all events made by a specific user within the specified period.
  5. Understand the SubFight battle lifecycle and states

    master

    The SubFight widget transitions through four distinct states:

    1. Idle: No battle is active; the widget is hidden from the screen.
    2. Round A: The first option (Option A) is active and accumulating points from events.
    3. Round B: The second option (Option B) is active and accumulating points from events.
    4. Results: The battle has concluded; the widget displays the winner and final scores before auto-hiding.
  6. Listen for SE_API.store updates

    master

    When SE_API.store.set is called, an event is emitted to all Custom Widgets. You can listen for this event to react to data changes in real-time. The event listener is kvstore:update.

    {
    	"detail": {
    		"listener": "kvstore:update",
    		"event": {
    			"data": {
    				"key": "customWidget.keyName",
    				"value": {
    					"array": [33, "foobar"],
    					"date": "2021-03-15T08:46:10.919Z",
    					"test": 15
    				}
    			}
    		}
    	}
    }
  7. Access custom field data in HTML, CSS, and JS

    master

    Once fields are defined in the JSON configuration, you can access their values in your code using different methods.

    In HTML and CSS (Templating)

    Use double curly braces {{variableName}} or single curly braces {variableName} to inject field values directly into your markup or styles. It is recommended to use this method primarily in HTML and CSS for better readability.

    In JavaScript (Event Listener)

    To access field data in JS, listen for the onWidgetLoad event. The data is contained within obj.detail.fieldData.

    You can access values via bracket notation fieldData["fieldName"] or dot notation fieldData.fieldName.

    <!-- HTML Usage -->
    <div class="message">{{someDropdown}} is an option!</div>
    /* CSS Usage */
    .message {
        font-size: {{someSlider}}px;
        color: {{someColorPicker}};
    }
    // JS Usage
    window.addEventListener('onWidgetLoad', function (obj) {
        const {fieldData} = obj.detail;
        
        // Method 1: Bracket notation
        const someVariable = fieldData["someText"];
        
        // Method 2: Dot notation
        const magicNumber = fieldData.someNumber;
        
        // Method 3: Internal templating
        const magicNumberTemplate = parseFloat("{{someNumber}}");
    });
  8. Set up the Alerts BingTTS widget

    master

    The Alerts BingTTS widget allows sirens to use the Azure Text to Speech (TTS) service. It can function as an audio-only widget without a visual display.

    To use this widget, follow these steps:

    1. Sign up for the Azure Text to Speech service.
    2. In the widget's TTS settings, provide your API Key, API Region, and a valid Voice name (refer to Azure's neural voice support for available options).
    3. Verify the setup: once configured correctly, the widget will play a test sound saying "TTS is Load" upon loading.
  9. Create a new Overlay

    master

    To begin building widgets, you must first create an Overlay in the StreamElements dashboard.

    1. Navigate to the Overlays section.
    2. Click the NEW OVERLAY button.
    3. Select your desired resolution and click START.

    Note: The overlay size should typically match your stream's resolution or be smaller if you intend to handle repositioning within your broadcasting software.

  10. Configure the Heart Engagement widget

    master

    To customize the Heart Engagement widget, follow these two steps:

    1. Change the heart animation: In the HTML section of the widget editor, locate the <img> tag and update its src attribute to the URL of your preferred beating heart image.
    2. Adjust animation speed/scale: Use the controls in the left panel of the editor to adjust the multipliers.
    <!-- Example of changing the heart image in the HTML section -->
    <img src="https://your-new-heart-url.png" />
  11. Manage event queuing with widgetDuration and resumeQueue

    master

    To prevent overlapping animations or alerts, you can use the built-in queuing system.

    1. Define Duration: In your widget's JSON configuration, set the widgetDuration property. This defines the maximum time (in seconds) the event queue will hold execution. The default is 0.
    2. Manual Control: You can manually trigger the next item in the queue using SE_API.resumeQueue(). This is useful when an animation has a dynamic duration and you want to resume the queue only after the animation finishes.

    Example Scenario: Preventing overlapping community sub gift animations by calculating a random duration and calling resumeQueue via setTimeout.

    ```json
    // Fields configuration
    {
        "widgetDuration": {
          "type": "hidden",
          "value": 15
        }
    }
    // JavaScript implementation
    let skippable = ["bot:counter", "event", "event:test", "event:skip", "alertService:toggleSound", "message", "delete-message", "delete-messages", "kvstore:update"];
    
    let playAnimation = (event) => {
        $("container").html(`<div id="sender">${event.sender}</div><div class="amount">${event.amount} subs!</div>`);
        return Math.floor(Math.random() * 8) + 7; // Returns duration between 7-15s
    };
    
    window.addEventListener('onEventReceived', function (obj) {
        const listener = obj.detail.listener;
        const data = obj.detail.event;
    
        // If the event is in the skippable list, process it immediately
        if (skippable.indexOf(listener) !== -1) return;
    
        // If it's not a sub event, resume queue immediately
        if (listener !== 'subscriber-latest') {
            SE_API.resumeQueue(); 
            return;
        }
    
        // If it's not a sub gift, resume queue immediately
        if (data.bulkGifted !== true && !data.gifted) {
            SE_API.resumeQueue();
            return;
        }"},
  12. Start and manage battles with SubFight commands

    master

    The SubFight widget uses chat commands to control voting battles. Battles consist of two rounds: in Round 1, only Option A accumulates points, and in Round 2, only Option B accumulates points.

    Battle Commands

    • !vs [seconds];[option A];[option B]: Starts a new battle. The [seconds] parameter defines the duration for each round.
      • Example: !vs 60;Pizza;Burgers (60 seconds for Pizza, then 60 seconds for Burgers).

    Management Commands

    • !vs reset: Immediately hides the widget and clears all battle data. This can be used at any time.
    • !vs end: Ends the current active round (Round A or Round B) early and displays the results. The widget will auto-hide 10 seconds after the results are shown.
    !vs 60;Pizza;Burgers
    !vs reset
    !vs end