@lumiastream/lumia-types 3.8.1 → 3.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,16 +20,53 @@ Let's get started:
20
20
 
21
21
  #### Before we begin, let's dissect this.
22
22
 
23
- `base`: will be the base of actions that can be used with Custom Code. The different bases are:
24
- `delay, lumia, overlay, api, websocket, commandRunner, inputEvent, obs, slobs, twitch, twitter, streamerbot, midi, osc, artnet, mqtt, serial, broadlink, spotify, vlc, voicemod`
23
+ `base`: will be the base of actions that can be used with Custom Code. There are two groups of bases.
25
24
 
26
- `type`: Every base has different action types. For instance, the base `lumia` has: `chatbot, tts, setStreamMode, toggleStreamMode` and much more.
27
- To find the list of types that each base has below. Check in the side bar to quickly get to the base you're interested in.
25
+ **System bases** (built into Lumia):
26
+ `delay, lumia, overlay, api, commandRunner, inputEvents`
27
+
28
+ > Note: `lumia` and `overlay` also accept the aliases `lumiaActions` and `overlayActions`, and the input base is `inputEvents` (plural).
29
+
30
+ **Integration bases** — every connected integration is also a valid base. These include (and more are added over time):
31
+ `twitch, youtube, facebook, tiktok, kick, discord, obs, slobs, meld, spotify, youtubemusic, nowplaying, vlc, voicemod, streamerbot, vtubestudio, midi, osc, artnet, mqtt, serial, websocket, broadlink, hue, lifx, nanoleaf, govee, wled, wiz, tplink, tuya, yeelight, elgato, streamdeck, touchportal, loupedeck, homeassistant, switchbot` plus any installed plugin (use the plugin's id as the base).
32
+
33
+ `type`: Every base has different action types. For instance, the base `lumia` has `chatbot, tts, setStreamMode, toggleStreamMode` and many more. The full type lists for the system bases are below; integration and plugin types vary per integration — the easiest way to discover the exact `base`, `type`, and `value` for an integration action is to configure that action once in Lumia's normal Action editor.
28
34
 
29
35
  `value`: can sometimes be an object and sometimes a string, it all depends on the `base` and `type`
30
36
 
31
37
  `variables`: allows you to send in different variables for each action. But do note that the variables that are already on the command/alert will also be spread on to this variables object. Variables are not required
32
38
 
33
- There are more fields that are sometimes used in actions. We will try to list out as many common examples down below along with the schema for them
39
+ There are more fields that are sometimes used in actions. `delay` (a number in milliseconds) can be added to any action to wait before running it.
40
+
41
+ ### Passing an array of actions
42
+
43
+ ```js
44
+ async function() {
45
+ // Runs the TTS, then sends a chatbot message
46
+ await actions([
47
+ { base: "lumia", type: "tts", value: { message: "Hello {{username}}" } },
48
+ { base: "lumia", type: "chatbot", value: { message: "Welcome {{username}}" } }
49
+ ]);
50
+ done();
51
+ }
52
+ ```
53
+
54
+ ### System base type reference
55
+
56
+ These are the built-in `type` values for each system base.
57
+
58
+ **`base: "lumia"`** — `callCommand, callRandomCommand, chatbot, tts, setStreamMode, toggleStreamMode, setFuzeAudioSensitivity, playAudio, writeToFile, setConnection, updateVariable, updateCounter, appendToVariable, unappendFromVariable, saveLocal, addToUserlevel, removeFromUserlevel, addToRestrictionsList, removeFromRestrictionsList, setFolder, setAlert, setAlertVariation, setCommand, setChatbotCommand, setTwitchPointsCommand, setTwitchExtensionCommand, setKickPointsCommand, setChatMatchCommand, setTwitchPointValue, setLoyaltyPointValue, setUserLoyaltyPoint, setTwitchExtensionBitsValue, setAutomation, setVoicecommands, sendToDiscordWebhook, sendToDiscordWithMediaWebhook, sendToWebhook, sendToPrinter, raffleEntry, raffleRemoveEntry, raffleGetWinner, raffleStart, raffleStop, raffleEnd, viewerQueueEntry, viewerQueueLeave, tournamentEntry, tournamentRemoveEntry, tournamentUpdatePoints, tournamentStart, tournamentEnd, viewerQueuePlayPause, viewerQueueEndQueue, viewerQueuePickPlayer, backToDefault, replayLastEventListEvent, runLastQueueItem, resumeQueue, pauseQueue, removeCurrentQueueItem, clearQueue, clearCooldowns, resetSession, cleanAll, refreshSettings, addSongRequest, skipSongRequest, clearSongRequestQueue, delay`
59
+
60
+ **`base: "overlay"`** — `alertTrigger, alertEvent, setOverlayVisibility, setLayerVisibility, setLayerPosition, setLayerSize, setTextContent, setImageContent, setVideoContent, setAudioContent, setLayerVolume, playPauseMedia, setContent, sendShoutout, sendCustomOverlayContent, sendGameTrigger, sendGameUpdate, takeScreenshot, spinwheelReset, spinwheelAddItem, spinwheelRemoveItem, sendHfx, hudOverlayChange, hudToggle, hudVolumeSet, hudOpacitySet, timerIncrement, pollTrigger, pollStart, pollResetVotes, pollSetTimer, pollAddItem, pollRemoveItem, delay`
61
+
62
+ **`base: "api"`** — `get, put, post, patch, delete, delay`
63
+
64
+ **`base: "commandRunner"`** — `app/file, shell command, delay`
65
+
66
+ **`base: "inputEvents"`** — `keyboard, mouse, delay`
67
+
68
+ **`base: "delay"`** — no `type`; pass the millisecond delay directly as the value, e.g. `{ base: "delay", value: 1000 }`.
69
+
70
+ > Tip: most of the `lumia` and `overlay` actions already have dedicated helper functions (`tts`, `chatbot`, `overlaySetTextContent`, etc.) in `helper-functions.md`. Reach for `actions()` mainly when you need an integration action that does not have a helper yet.
34
71
 
35
- #### More documentation coming soon
72
+ This documentation can get extremely broad for every integration, so if you get stuck please visit our [**Discord**](https://discord.gg/R8rCaKb) to ask us any questions.
@@ -10,15 +10,12 @@ e.g. the code below will trigger a command named **'money-12'** when the **count
10
10
  ```js
11
11
  async function() {
12
12
 
13
- // You can get your variable's value that you just set here
14
- let redeemCount = await getVariable('redeemCount');
15
-
16
- if (!redeemCount) {
17
- // If variable does not exist it will create it
18
- redeemCount = await setVariable({ name: 'redeemCount', value: 10 });
19
- }
13
+ // Variables come back as strings, so wrap with Number(). Defaults to 0 the first time the variable doesn't exist yet
14
+ let redeemCount = Number(await getVariable('redeemCount')) || 0;
20
15
 
21
16
  redeemCount++;
17
+
18
+ // setVariable creates the variable if it doesn't exist, or updates it
22
19
  await setVariable({ name: 'redeemCount', value: redeemCount });
23
20
 
24
21
  if (redeemCount === 12) {
@@ -9,6 +9,9 @@ You can call requests from integrations that we support that have an access toke
9
9
 
10
10
  ```js
11
11
  async function() {
12
+ // Declared outside the try so it's still in scope when we call done()
13
+ let randomClip;
14
+
12
15
  try {
13
16
  const twitchToken = await getToken('twitch');
14
17
  const twitchClientId = await getClientId('twitch');
@@ -20,14 +23,20 @@ async function() {
20
23
  'Client-ID': twitchClientId
21
24
  }
22
25
  });
23
- const clips = (await clipsRes.json())?.data;
24
- const randomClip = clips[Math.floor(Math.random() * clips.length)];
25
- chatbot({ message: `${randomClip.title}: ${randomClip.url}` });
26
+ const clips = (await clipsRes.json())?.data ?? [];
27
+ if (clips.length) {
28
+ randomClip = clips[Math.floor(Math.random() * clips.length)];
29
+ chatbot({ message: `${randomClip.title}: ${randomClip.url}` });
30
+ }
26
31
  } catch (err) {
27
32
  showToast({ message: 'error: ' + err.message });
28
33
  }
29
34
 
30
- done({ variables: { user_clip_title: randomClip.title, user_clip: randomClip.url } });
35
+ if (randomClip) {
36
+ done({ variables: { user_clip_title: randomClip.title, user_clip: randomClip.url } });
37
+ } else {
38
+ done();
39
+ }
31
40
  }
32
41
  ```
33
42
 
@@ -11,7 +11,7 @@ This can be very useful if other apps are reading and writing to a text file. An
11
11
  ```js
12
12
  async function() {
13
13
  // You have the ability to overwrite the whole file by setting append to false, or appending to the file in case you would like to keep a log of things
14
- await writeFile({ path: 'C: \\Users\\Lumia\\Desktop\\lastSubscriber.txt', message: '{{username}}\n', append: true });
14
+ await writeFile({ path: 'C:\\Users\\Lumia\\Desktop\\lastSubscriber.txt', message: '{{username}}\n', append: true });
15
15
 
16
16
  // You can get your variable's value that you just set here
17
17
  const lastSubscribers = await readFile('C:\\Users\\Lumia\\Desktop\\lastSubscriber.txt');
@@ -1,29 +1,50 @@
1
1
  # Lumia Stream Custom Code GPT Instructions
2
2
 
3
- Use this with the Custom Code docs:
4
- - `what-is-custom-javascript.md`
5
- - `important-notes.md`
6
- - `helper-functions.md`
7
- - `custom-actions.md`
8
- - `examples/*.md`
9
-
10
- ## Required Output Rules
11
-
12
- 1. Always generate JavaScript (not TypeScript).
13
- 2. Prefer returning a full Lumia Custom Code wrapper:
14
-
15
- ```js
16
- async function() {
17
- // logic
18
-
19
- // Make sure you call done() to avoid memory leaks
20
- done();
21
- }
22
- ```
23
-
24
- 3. Always call `done()` exactly once before finishing the function, unless the user explicitly asks for a partial snippet.
25
- 4. Do not output markdown fences or prose when the caller expects code-only output.
26
- 5. Use helper functions documented in `helper-functions.md` instead of inventing undocumented APIs.
27
- 6. Keep examples compatible with Lumia variable syntax (e.g. `{{username}}`).
28
- 7. When accessing numeric variables, parse values safely before math/comparisons.
29
- 8. If a capability is not documented, state that clearly and provide a safe alternative.
3
+ You generate **Lumia Stream Custom Code**: JavaScript snippets that a streamer pastes into the "Custom Javascript" tab of a Command or Alert. Use this together with the Custom Code docs:
4
+
5
+ - `what-is-custom-javascript.md` — what the feature is
6
+ - `important-notes.md` — variables, runtime environment, gotchas
7
+ - `helper-functions.md` — every available helper function (the API surface)
8
+ - `custom-actions.md` — the `actions([...])` escape hatch and base/type lists
9
+ - `examples/*.md` — worked examples
10
+
11
+ ## Runtime model (read this first)
12
+
13
+ - Code runs in a sandboxed browser **Web Worker**, not Node.js. `fetch`, `Promise`, `async/await`, `JSON`, `Math`, `Date`, `setTimeout` are available. There is **no** `require`, `import`, `fs`, `process`, or `Buffer`.
14
+ - Helper functions are injected as **globals** — never import or redefine them. Most return a Promise, so `await` them.
15
+ - Lumia **rejects any code that does not contain a `done(` call.** Always call `done()` exactly once, as the last thing the code does.
16
+ - `{{variable}}` tokens are string-replaced **before** the code runs. They are not wrapped in quotes automatically, so wrap them yourself when you need a string: `tts({ message: "{{username}}" })`. When you need the raw value (object/number), read it instead with `await getVariable('name')`.
17
+
18
+ ## Required output rules
19
+
20
+ 1. Always generate **JavaScript** (not TypeScript). No type annotations.
21
+ 2. Wrap the logic in the standard Lumia Custom Code shell, unless the user explicitly asks for a partial snippet:
22
+
23
+ ```js
24
+ async function() {
25
+ // logic
26
+
27
+ // Always call done() to close the worker and avoid memory leaks
28
+ done();
29
+ }
30
+ ```
31
+
32
+ 3. Call `done()` **exactly once** before finishing. Use `done({ shouldStop: true })` to also stop the rest of the command, `done({ actionsToStop: ['tts','chatbot'] })` to stop specific parts, and `done({ variables: { key: 'value' } })` to pass variables to later actions.
33
+ 4. Only use helpers documented in `helper-functions.md`. Do **not** invent undocumented APIs. The complete set of globals is:
34
+
35
+ `done, log, addLog, showToast, delay, getVariable, getAllVariables, setVariable, deleteVariable, getStore, getStoreItem, removeStoreItem, setStore, resetStore, getLights, sendColor, hexToRgb, getCommands, getAllCommands, getApiOptions, getToken, getClientId, callAlert, callCommand, callChatbotCommand, callTwitchPoint, callTwitchExtension, callKickPoint, readFile, writeFile, tts, chatbot, playAudio, playSound, sendRawObsJson, execShellCommand, actions, overlayAlertTrigger, overlaySetVisibility, overlaySetLayerVisibility, overlaySetLayerPosition, overlaySetLayerSize, overlaySetTextContent, overlaySetImageContent, overlaySetVideoContent, overlaySetAudioContent, overlaySetVolume, overlayPlayPauseMedia, overlaySendHfx, overlayTimer, overlayShoutout, overlaySendCustomContent`
36
+
37
+ Plus standard browser globals including `fetch` and `console.log`. For anything an integration supports that has no dedicated helper (Spotify, OBS raw, Streamer.bot, etc.), use `actions([...])` as documented in `custom-actions.md`.
38
+ 5. Do not output markdown fences or prose when the caller expects code-only output.
39
+ 6. Keep `{{...}}` variable tokens intact and unescaped (write `{{username}}`, never `\{\{username\}\}`).
40
+ 7. When using numeric variables, parse them safely before math or comparisons: `const n = Number(await getVariable('count')) || 0;`. `getVariable` returns strings.
41
+ 8. For `callAlert`, the `name` must be a valid alert key from the list in `helper-functions.md` (e.g. `twitch-subscriber`, `kick-follower`, `kofi-donation`). Do not guess keys that aren't on that list.
42
+ 9. If a capability is not documented, say so clearly and offer a documented alternative rather than fabricating an API.
43
+
44
+ ## Quality checklist before returning code
45
+
46
+ - Wrapped in `async function() { ... }` and calls `done()` once.
47
+ - Every helper that returns a Promise is `await`ed.
48
+ - Any variable referenced in `done()`/later code is declared in an outer scope (not trapped inside a `try` block).
49
+ - API calls are wrapped in `try/catch` and still reach `done()` on failure.
50
+ - Numeric variables parsed with `Number(...)`; string variables quoted when interpolated as `{{token}}`.
@@ -13,7 +13,7 @@ If you would like to modify/add variables that other actions could use, you can
13
13
 
14
14
  You can also choose to only stop some actions rather than stopping the whole command by using actionsToStop.
15
15
  The different actionsToStop keys relate to the action. The keys are:
16
- `devices, tts, chatbot, hfx, lumia, overlay, voicemod, streamerbot, obs, slobs, midi, osc, mqtt, serial, broadlink, websocket, twitter, twitch, spotify, vlc, artnet, api, commandRunner, inputEvent`
16
+ `devices, tts, chatbot, hfx, lumia, overlay, api, commandRunner, inputEvent, actions, voicemod, streamerbot, obs, slobs, midi, osc, mqtt, serial, broadlink, websocket, twitter, twitch, spotify, vlc, artnet`
17
17
 
18
18
  ```js
19
19
  // Basic done
@@ -161,6 +161,17 @@ async function() {
161
161
  }
162
162
  ```
163
163
 
164
+ ### Remove Persisted Store Item
165
+
166
+ `removeStoreItem(name: string)`: Removes a single item from the custom code store by its name. The rest of the store is left untouched
167
+
168
+ ```js
169
+ async function() {
170
+ await removeStoreItem('users');
171
+ done();
172
+ }
173
+ ```
174
+
164
175
  ### Set Persisted Store Item
165
176
 
166
177
  `setStore({ name: string; value: any })`: Sets an item in the store. You can use any data type as your value
@@ -219,6 +230,18 @@ async function() {
219
230
  }
220
231
  ```
221
232
 
233
+ ### Hex To RGB
234
+
235
+ `hexToRgb(value: string)`: Helper that converts a hex color string into an `{ r, g, b }` object. Useful when an integration expects an rgb object instead of a hex string
236
+
237
+ ```js
238
+ async function() {
239
+ const rgb = await hexToRgb('#FF4076');
240
+ // rgb is { r: 255, g: 64, b: 118 }
241
+ done();
242
+ }
243
+ ```
244
+
222
245
  ### Get API Options
223
246
 
224
247
  `getApiOptions()`: Contains information like commands, types, connections, and more
@@ -229,14 +252,81 @@ async function() {
229
252
  }
230
253
  ```
231
254
 
255
+ ### Get Commands
256
+
257
+ `getCommands({ formatted?: boolean; onlyOn?: boolean; onlyUser?: boolean })`: Returns the list of chat command names. Pass `onlyOn: true` to only include commands that are enabled and shown in the commands list, `onlyUser: true` to only include commands the current user has access to (based on their user levels), and `formatted: true` to get a single comma separated string instead of an array
258
+
259
+ ```js
260
+ async function() {
261
+ // Array of command names the chatter is allowed to use, only the ones that are turned on
262
+ const commands = await getCommands({ onlyOn: true, onlyUser: true });
263
+ // Or get a ready to print string for a !commands message
264
+ const list = await getCommands({ formatted: true, onlyOn: true });
265
+ chatbot({ message: `Commands: ${list}` });
266
+ done();
267
+ }
268
+ ```
269
+
270
+ ### Get All Commands
271
+
272
+ `getAllCommands({ onlyOn?: boolean })`: Returns an object containing the names of every command type: `commands`, `chatbotCommands`, `twitchPointsCommands`, `twitchExtensionsCommands`, `kickPointsCommands`, `chatMatch`, and `folders`. Pass `onlyOn: true` to only include enabled entries
273
+
274
+ ```js
275
+ async function() {
276
+ const all = await getAllCommands({ onlyOn: true });
277
+ log(all.chatbotCommands);
278
+ done();
279
+ }
280
+ ```
281
+
232
282
  ### Call Alert
233
283
 
234
284
  `callAlert({ name: string; variation?: string; variableValues?: {[key: string]: string|number } })`: Call an alert based on your conditions. You can also call a variation given it's name. When calling an alert/command from custom code the variableValues will be inherited from the parent, but you can also override variable values by passing it in to the call function.
235
285
 
236
- The valid alert keys are:
286
+ The `name` must be one of the valid alert keys (the `LumiaAlertValues` list). This is the full current list, grouped by platform:
237
287
 
238
288
  ```
239
- lumia-redemption, twitch-streamLive, twitch-streamOffline, twitch-follower, twitch-subscriber, twitch-giftSubscription, twitch-host, twitch-raid, twitch-bits, twitch-redemption, twitch-hypetrainStarted, twitch-hypetrainProgressed, twitch-hypetrainLevelProgressed, twitch-hypetrainEnded, twitch-pollStarted, twitch-pollProgressed, twitch-pollEnded, twitch-predictionStarted, twitch-predictionProgressed, twitch-predictionLocked, twitch-predictionEnded, twitch-goalStarted, twitch-goalProgressed, twitch-goalEnded, twitch-categoryChanged, twitch-clip, youtube-member, youtube-subscriber, youtube-superchat, youtube-supersticker, facebook-follower, facebook-reaction, facebook-star, facebook-support, facebook-subscriptionGift, facebook-share, facebook-fan, tiktok-follower, tiktok-like, tiktok-gift, tiktok-share, tiktok-streamEnd, streamlabs-donation, streamlabs-charity, streamlabs-merch, streamlabs-redemption, streamlabs-primegift, streamelements-donation, extralife-donation, donordrive-donation, tiltify-campaignDonation, tipeeestream-donation, treatstream-treat, patreon-pledge, obs-switchProfile, obs-switchScene, obs-sceneItemVisibility, obs-sceneItemHidden, obs-switchTransition, obs-transitionBegin, obs-transitionEnd, obs-streamStarting, obs-streamStopping, obs-recordingStarting, obs-recordingStopping, slobs-switchSceneCollection, slobs-switchScene, slobs-sceneItemVisibility, slobs-sceneItemHidden, spotify-switchSong, spotify-songPlayed, spotify-songPaused, vlc-switchSong, vlc-songPlayed, vlc-songPaused, pulse-heartrate, pulse-calories, twitter-follower, twitter-like, twitter-retweet, woocommerce-order, kofi-donation, kofi-subscription, kofi-commission, kofi-shopOrder, streamerbot-action
289
+ // Lumia Stream
290
+ lumiastream-donation, lumiastream-lumiaOpened, lumiastream-lumiaClosed, lumiastream-streammodeOn, lumiastream-streammodeOff, lumiastream-raffleStart, lumiastream-raffleStop, lumiastream-raffleWinner, lumiastream-tournamentStart, lumiastream-tournamentEnd, lumiastream-tournamentWinner, lumiastream-spinwheelWinner, lumiastream-pollStarted, lumiastream-pollProgressed, lumiastream-pollEnded, lumiastream-viewerqueueStarted, lumiastream-viewerqueueEnded, lumiastream-viewerAchievement, lumiastream-variableChanged, lumiastream-rouletteWinner, lumiastream-slotsWinner
291
+
292
+ // Twitch
293
+ twitch-extension, twitch-points, twitch-streamLive, twitch-streamOffline, twitch-firstChatter, twitch-entrance, twitch-follower, twitch-sessionFollowers, twitch-subscriber, twitch-sessionSubs, twitch-giftSubscription, twitch-sessionGiftSubscriptions, twitch-raid, twitch-raidOut, twitch-bits, twitch-bitsCombo, twitch-sessionBits, twitch-redemption, twitch-hypetrainStarted, twitch-hypetrainProgressed, twitch-hypetrainLevelProgressed, twitch-hypetrainEnded, twitch-pollStarted, twitch-pollProgressed, twitch-pollEnded, twitch-predictionStarted, twitch-predictionProgressed, twitch-predictionLocked, twitch-predictionEnded, twitch-goalStarted, twitch-goalProgressed, twitch-goalEnded, twitch-charityDonation, twitch-charityCampaignStarted, twitch-charityCampaignProgressed, twitch-charityCampaignStopped, twitch-categoryChanged, twitch-clip, twitch-channelJoin, twitch-channelLeave, twitch-banned, twitch-timeout, twitch-timeoutOver, twitch-shoutoutReceive, twitch-warned, twitch-suspiciousUserMessage, twitch-suspiciousUserUpdated, twitch-shieldModeStarted, twitch-shieldModeEnded, twitch-adStarted, twitch-adStopped, twitch-watchStreak, twitch-powerups
294
+
295
+ // YouTube
296
+ youtube-streamLive, youtube-streamOffline, youtube-firstChatter, youtube-entrance, youtube-subscriber, youtube-sessionSubs, youtube-member, youtube-sessionMembers, youtube-giftMembers, youtube-sessionGiftMembers, youtube-superchat, youtube-sessionSuperchats, youtube-supersticker, youtube-sessionSuperstickers, youtube-gifts, youtube-sessionGifts, youtube-like, youtube-viewers
297
+
298
+ // Facebook
299
+ facebook-streamLive, facebook-streamOffline, facebook-firstChatter, facebook-entrance, facebook-follower, facebook-reaction, facebook-star, facebook-support, facebook-subscriptionGift, facebook-share, facebook-fan
300
+
301
+ // TikTok
302
+ tiktok-firstChatter, tiktok-entrance, tiktok-follower, tiktok-like, tiktok-totalLikes, tiktok-gift, tiktok-superFan, tiktok-superFanBox, tiktok-treasureChest, tiktok-question, tiktok-poll, tiktok-shopPurchase, tiktok-pinMessage, tiktok-battleStart, tiktok-battleProgress, tiktok-battleEnd, tiktok-share, tiktok-streamEnd, tiktok-newVideo
303
+
304
+ // Kick
305
+ kick-points, kick-firstChatter, kick-entrance, kick-follower, kick-sessionFollowers, kick-subscriber, kick-sessionSubs, kick-subscriptionGift, kick-sessionGiftSubscriptions, kick-kicks, kick-sessionKicks, kick-host, kick-banned, kick-unbanned
306
+
307
+ // Discord
308
+ discord-firstChatter, discord-entrance
309
+
310
+ // Donations & monetization
311
+ streamlabs-donation, streamlabs-charity, streamlabs-merch, streamlabs-redemption, streamlabs-primegift, streamelements-donation, extralife-donation, donordrive-donation, tiltify-campaignDonation, throne-giftPurchase, throne-contributionPurchase, throne-giftCrowdfunded, tipeeestream-donation, treatstream-treat, patreon-campaignPledge, kofi-donation, kofi-subscription, kofi-commission, kofi-shopOrder, fourthwall-shopOrder, fourthwall-donation, fourthwall-subscription, fourthwall-subscriptionChanged, fourthwall-subscriptionExpired, fourthwall-giftpurchase, fourthwall-giveawayStarted, fourthwall-giveawayEnded, fourthwall-thankyouSent, fourthwall-newsletterSubscribed, woocommerce-order
312
+
313
+ // OBS Studio
314
+ obs-switchProfile, obs-switchScene, obs-sceneItemVisibility, obs-sceneItemHidden, obs-switchTransition, obs-transitionBegin, obs-transitionEnd, obs-streamStarting, obs-streamStopping, obs-recordingStarting, obs-recordingStopping, obs-mediaInputPlaybackStarted, obs-mediaInputPlaybackEnded, obs-virtualcamStateChanged, obs-screenshotSaved, obs-replayBufferSaved, obs-verticalBacktrackSaved, obs-vendorEvent
315
+
316
+ // Streamlabs Desktop (SLOBS)
317
+ slobs-switchSceneCollection, slobs-switchScene, slobs-sceneItemVisibility, slobs-sceneItemHidden
318
+
319
+ // Meld Studio
320
+ meld-streamStarting, meld-streamStopping, meld-recordingStarting, meld-recordingStopping, meld-switchScene, meld-switchVerticalScene
321
+
322
+ // Music players
323
+ spotify-switchSong, spotify-songPlayed, spotify-songPaused, youtubemusic-switchSong, youtubemusic-songPlayed, youtubemusic-songPaused, nowplaying-switchSong, nowplaying-songPlayed, nowplaying-songPaused, vlc-switchSong, vlc-songPlayed, vlc-songPaused
324
+
325
+ // VTube Studio
326
+ vtubestudio-hotkeyTriggered, vtubestudio-modelLoaded, vtubestudio-animationStart, vtubestudio-animationEnd, vtubestudio-itemAdded, vtubestudio-itemRemoved, vtubestudio-backgroundChanged
327
+
328
+ // Other
329
+ pulse-heartrate, pulse-calories, twitter-follower, twitter-like, twitter-retweet, streamerbot-action, crowdcontrol-effect
240
330
  ```
241
331
 
242
332
  ```js
@@ -257,6 +347,17 @@ async function() {
257
347
  }
258
348
  ```
259
349
 
350
+ ### Call Chatbot Command
351
+
352
+ `callChatbotCommand({ name: string; variableValues?: {[key: string]: string|number } })`: Call a chatbot command based on your conditions. When calling an alert/command from custom code the variableValues will be inherited from the parent, but you can also override variable values by passing it in to the call function.
353
+
354
+ ```js
355
+ async function() {
356
+ // This will call chatbot command called 'welcome' and change the variable named "message" to the value "you are awesome"
357
+ callChatbotCommand({ name: 'welcome', variableValues: {'message': 'you are awesome' } })
358
+ }
359
+ ```
360
+
260
361
  ### Call Twitch Point Command
261
362
 
262
363
  `callTwitchPoint({ name: string; variableValues?: {[key: string]: string|number } })`: Call a twitch point command based on your conditions. When calling an alert/command from custom code the variableValues will be inherited from the parent, but you can also override variable values by passing it in to the call function.
@@ -279,6 +380,17 @@ async function() {
279
380
  }
280
381
  ```
281
382
 
383
+ ### Call Kick Point Command
384
+
385
+ `callKickPoint({ name: string; variableValues?: {[key: string]: string|number } })`: Call a kick point command based on your conditions. When calling an alert/command from custom code the variableValues will be inherited from the parent, but you can also override variable values by passing it in to the call function.
386
+
387
+ ```js
388
+ async function() {
389
+ // This will call Kick Point called 'point' and change the variable named "message" to the value "you are awesome"
390
+ callKickPoint({ name: 'point', variableValues: {'message': "you are awesome" } });
391
+ }
392
+ ```
393
+
282
394
  ### Read File
283
395
 
284
396
  `readFile(path: string)`: Read from a file on your local computer to get the contents of it to be displayed in your code. This is useful for other Apps that write and read to files so you can combine the usage of them in Lumia. To keep things consistent, try to use an absolute file path
@@ -297,7 +409,7 @@ async function() {
297
409
  ```js
298
410
  async function() {
299
411
  // This will create a new file in the 'C:\Documents\Lumiastream\' named helper.txt and add the text "text inside this file" inside that file
300
- await writeFile({ path: 'C:\\Documents\\Lumiastream\\helper.txt', value: 'text inside this file', append: true });
412
+ await writeFile({ path: 'C:\\Documents\\Lumiastream\\helper.txt', message: 'text inside this file', append: true });
301
413
  }
302
414
  ```
303
415
 
@@ -328,7 +440,7 @@ async function() {
328
440
 
329
441
  ### Play Audio
330
442
 
331
- `playAudio({ path: string | string[]; volume?: number; waitForAudioToStop?: boolean })`: You can play an audio file from either a URL or from a local path on your computer inside of your code. You can even wait for the audio to stop playing before the code continues by setting an await before while also setting waitForAudioToStop to true. You can also allow Lumia Stream to randomly play an audio file from a selection by passing an array of strings to path
443
+ `playAudio({ path: string | string[]; volume?: number; waitForAudioToStop?: boolean })`: You can play an audio file from either a URL or from a local path on your computer inside of your code. You can even wait for the audio to stop playing before the code continues by setting an await before while also setting waitForAudioToStop to true. You can also allow Lumia Stream to randomly play an audio file from a selection by passing an array of strings to path. `playSound` is an alias of `playAudio` and takes the exact same parameters
332
444
 
333
445
  ```js
334
446
  async function() {
@@ -434,6 +546,16 @@ async function() {
434
546
  }
435
547
  ```
436
548
 
549
+ ### Overlay Set Layer Size (Width and Height)
550
+
551
+ `overlaySetLayerSize({ layer: string, content: string })`: You can set the width and height of an overlay layer using this function. `content` is a string with the width and height separated by a comma. Like position, the overlay can interpolate so the resize can animate smoothly.
552
+
553
+ ```js
554
+ async function() {
555
+ overlaySetLayerSize({ layer: "My layer", content: "640,360" });
556
+ }
557
+ ```
558
+
437
559
  ### Overlay Set Text Content
438
560
 
439
561
  `overlaySetTextContent({ layer: string, content: string })`: You can set the text content of a text layer using this function. `content` is just a string that will correspond to the text that you want to set it to.
@@ -446,7 +568,7 @@ async function() {
446
568
 
447
569
  ### Overlay Set Image Content
448
570
 
449
- `overlaySetImageContent({ layer: string, content: string })`: You can set the image content of an image layer using this function. `content` is just a string that will correspond to the image name or url that you want to set it to. If you use a name it will try to find the name of an asset that you have in your overlay library. So if you have an asset named `lumia_logo.gif` you can set the content to the exact name with or without the file extension. This can be useful to allow chat to change the media using a \{\{message\}\} variable. After the content is changed it will automatically make the layer visibile and start playing
571
+ `overlaySetImageContent({ layer: string, content: string })`: You can set the image content of an image layer using this function. `content` is just a string that will correspond to the image name or url that you want to set it to. If you use a name it will try to find the name of an asset that you have in your overlay library. So if you have an asset named `lumia_logo.gif` you can set the content to the exact name with or without the file extension. This can be useful to allow chat to change the media using a `{{message}}` variable. After the content is changed it will automatically make the layer visibile and start playing
450
572
 
451
573
  ```js
452
574
  async function() {
@@ -460,7 +582,7 @@ async function() {
460
582
 
461
583
  ### Overlay Set Video Content
462
584
 
463
- `overlaySetVideoContent({ layer: string, content: string })`: You can set the video content of an video layer using this function. `content` is just a string that will correspond to the video name or url that you want to set it to. If you use a name it will try to find the name of an asset that you have in your overlay library. So if you have an asset named `lumia_video.webm` you can set the content to the exact name with or without the file extension. This can be useful to allow chat to change the media using a \{\{message\}\} variable. After the content is changed it will automatically make the layer visibile and start playing
585
+ `overlaySetVideoContent({ layer: string, content: string })`: You can set the video content of an video layer using this function. `content` is just a string that will correspond to the video name or url that you want to set it to. If you use a name it will try to find the name of an asset that you have in your overlay library. So if you have an asset named `lumia_video.webm` you can set the content to the exact name with or without the file extension. This can be useful to allow chat to change the media using a `{{message}}` variable. After the content is changed it will automatically make the layer visibile and start playing
464
586
 
465
587
  ```js
466
588
  async function() {
@@ -474,7 +596,7 @@ async function() {
474
596
 
475
597
  ### Overlay Set Audio Content
476
598
 
477
- `overlaySetAudioContent({ layer: string, content: string })`: You can set the audio content of an audio layer using this function. `content` is just a string that will correspond to the audio name or url that you want to set it to. If you use a name it will try to find the name of an asset that you have in your overlay library. So if you have an asset named `lumia_land.mp3` you can set the content to the exact name with or without the file extension. This can be useful to allow chat to change the media using a \{\{message\}\} variable. After the content is changed it will automatically make the layer visibile and start playing
599
+ `overlaySetAudioContent({ layer: string, content: string })`: You can set the audio content of an audio layer using this function. `content` is just a string that will correspond to the audio name or url that you want to set it to. If you use a name it will try to find the name of an asset that you have in your overlay library. So if you have an asset named `lumia_land.mp3` you can set the content to the exact name with or without the file extension. This can be useful to allow chat to change the media using a `{{message}}` variable. After the content is changed it will automatically make the layer visibile and start playing
478
600
 
479
601
  ```js
480
602
  async function() {
@@ -529,7 +651,7 @@ async function() {
529
651
 
530
652
  ### Overlay Shoutout
531
653
 
532
- `overlayShoutout({ layer: string, clipType: "clipFromTarget" | "clipFromSender" | "clipFromStreamer", clipRandom: boolean, clipLimit: number, clipMaxTime: string })`: You can send a shoutout directly to a shoutout layer using this function. `clipType` has three types. `clipFromTarget` will take a clip from the user who was tagged in the \{\{message\}\} variable. So you can use @lumiastream in the message and it will take a clip from that channel. `clipFromSender` will take a clip from the person who triggered the command. This normally corresponds to the \{\{user\}\} variable. `clipFromStreamer` will take a clip from your channel and send it over. You can decide to take a random clip by setting `clipRandom` to true. Or if you would like to take the first clip that matched the `clipMaxTime` given in milliseconds then you can set `clipRandom` to false. `clipLimit` will determing how many of the newest clips should be brought in to determine which clip should be selected. After a clip is selected it will start running immediately
654
+ `overlayShoutout({ layer: string, clipType: "clipFromTarget" | "clipFromSender" | "clipFromStreamer", clipRandom: boolean, clipLimit: number, clipMaxTime: string })`: You can send a shoutout directly to a shoutout layer using this function. `clipType` has three types. `clipFromTarget` will take a clip from the user who was tagged in the `{{message}}` variable. So you can use @lumiastream in the message and it will take a clip from that channel. `clipFromSender` will take a clip from the person who triggered the command. This normally corresponds to the `{{user}}` variable. `clipFromStreamer` will take a clip from your channel and send it over. You can decide to take a random clip by setting `clipRandom` to true. Or if you would like to take the first clip that matched the `clipMaxTime` given in milliseconds then you can set `clipRandom` to false. `clipLimit` will determing how many of the newest clips should be brought in to determine which clip should be selected. After a clip is selected it will start running immediately
533
655
 
534
656
  ```js
535
657
  async function() {
@@ -13,6 +13,15 @@ title: Important notes
13
13
  The different options are: `isSelf, mod, vip, tier3, tier2, tier1, subscriber, follower`.
14
14
  In your code you should use `const levels = await getVariable('userLevelsRaw');` and then you can check a level with `if (levels.subscriber) {}` since these are all booleans
15
15
 
16
+ ## Runtime environment
17
+
18
+ Your code runs inside a sandboxed browser Web Worker, not Node.js. That means:
19
+
20
+ - **`fetch` is available** — you can call any HTTP/REST API directly (see the Random Twitch Clip example). `Promise`, `async/await`, `JSON`, `Math`, `Date`, `setTimeout`, etc. all work.
21
+ - **Node.js APIs are NOT available** — there is no `require`, `import`, `fs`, `process`, `Buffer`, or `__dirname`. To read/write local files use the `readFile` / `writeFile` helpers, and to run a shell command use `execShellCommand`.
22
+ - **You must call `done()`.** Lumia will refuse to run any code that does not contain a `done(` call, and the worker stays alive (leaking memory) until `done()` is reached, so always call it exactly once as the last thing your code does.
23
+ - All the helper functions in `helper-functions.md` are injected as globals — you do not import them. Most return a Promise, so `await` them.
24
+
16
25
  ## Origin and queue type variables
17
26
 
18
27
  We expose `{{originType}}` and `{{queueType}}` so custom code can tell where an activity came from and what kind of queued activity is running.
@@ -1,5 +1,12 @@
1
1
  /// <reference path="./custom-overlays.d.ts" />
2
2
 
3
+ /*
4
+ * Only the most common alerts are modeled here as concrete types (a curated
5
+ * subset of the ~220 `LumiaAlertValues`). Any alert not in `LumiaAlert` below
6
+ * still arrives — just as the generic `AlertEvent` from `custom-overlays.d.ts`.
7
+ * Read `data.alert`, `data.dynamic`, and `data.extraSettings` directly for those.
8
+ */
9
+
3
10
  import { LumiaAlertValues } from './custom-overlays';
4
11
 
5
12
  /* -------------------------------------------------------------------------- */
@@ -360,9 +360,18 @@ export interface ChatEvent {
360
360
  export interface AlertEvent {
361
361
  /** Type of alert from LumiaAlertValues enum */
362
362
  alert: LumiaAlertValues;
363
- /** Dynamic value associated with the alert (e.g., donation amount, sub months) */
364
- dynamic: { value: number | string };
365
- /** Additional metadata about the alert */
363
+ /**
364
+ * Event-specific mutable values. `value` is the common amount (bits, raid
365
+ * viewers, sub tier, donation amount, …) but most alerts add their own fields —
366
+ * e.g. subs carry `isGift`, `giftAmount`, `isResub`, `subMonths`. For the exact
367
+ * per-alert shape see `AlertDynamic<T>` in `custom-overlays-alerts.d.ts`.
368
+ */
369
+ dynamic: { value?: number | string; [key: string]: unknown };
370
+ /**
371
+ * Additional metadata about the alert. The fields below are common to most
372
+ * alerts; alert-specific fields are merged in too — see `AlertExtra<T>` in
373
+ * `custom-overlays-alerts.d.ts`.
374
+ */
366
375
  extraSettings: {
367
376
  /** Username of the person triggering the alert */
368
377
  username: string;
@@ -384,6 +393,8 @@ export interface AlertEvent {
384
393
  timingType: string;
385
394
  /** Alert display duration in milliseconds */
386
395
  duration: number;
396
+ /** Alert-specific extra fields (e.g. subPlan, gifter, recipients, message). */
397
+ [key: string]: unknown;
387
398
  };
388
399
  /** Whether this alert was triggered from Lumia itself */
389
400
  fromLumia: boolean;
@@ -476,6 +487,19 @@ export type OverlayEventHandler = (data: OverlayEvent) => void;
476
487
  * Available globally as `window.Overlay` in custom overlays.
477
488
  */
478
489
  export interface Overlay {
490
+ /**
491
+ * Current values from the Data tab (defaults seeded from Configs `value`s,
492
+ * then overridden by what the user set). Read Config/Data values from here,
493
+ * e.g. `Overlay.data.fontSize`. There is no bare top-level `data` variable.
494
+ */
495
+ data: Record<string, any>;
496
+
497
+ /**
498
+ * This overlay's `codeId` (letters, numbers, hyphens, underscores; max 25 chars).
499
+ * Scopes `saveStorage`/`getStorage` and targets `overlaycontent` messages.
500
+ */
501
+ codeId: string;
502
+
479
503
  /**
480
504
  * Register an event listener for chat messages
481
505
  * @param event - Event type "chat"
@@ -521,6 +545,19 @@ export interface Overlay {
521
545
  */
522
546
  on(event: 'overlaycontent', handler: (data: CustomOverlayContentEvent) => void): void;
523
547
 
548
+ /**
549
+ * Register a handler for Configs `actionbutton` clicks. Not a platform event —
550
+ * it's Configs-driven, needs no `events` declaration, and is independent of the
551
+ * `OverlayListener` subscriptions. `key` is the field's JSON key; `value` is its
552
+ * optional `value`.
553
+ * @param event - Event type "configAction"
554
+ * @example
555
+ * window.Overlay.on('configAction', ({ key }) => {
556
+ * if (key === 'resetGame') resetGame();
557
+ * });
558
+ */
559
+ on(event: 'configAction', handler: (data: { key: string; value?: unknown }) => void): void;
560
+
524
561
  /**
525
562
  * Execute a Lumia Stream command
526
563
  * @param command - Name of the command to execute
@@ -2260,3 +2297,23 @@ export declare enum SystemVariables {
2260
2297
  }
2261
2298
 
2262
2299
  // <auto-generated-end name="SystemVariables" />
2300
+
2301
+ // -----------------------------------------------------------------------------
2302
+ // Globals available inside a custom overlay's JS tab
2303
+ // -----------------------------------------------------------------------------
2304
+
2305
+ declare global {
2306
+ /** The Overlay API. Available unprefixed as `Overlay` or as `window.Overlay`. */
2307
+ const Overlay: Overlay;
2308
+
2309
+ interface Window {
2310
+ Overlay: Overlay;
2311
+ }
2312
+
2313
+ /**
2314
+ * Show a toast notification in Lumia.
2315
+ * @param message - Text to display
2316
+ * @param type - Toast style (defaults to "info")
2317
+ */
2318
+ function toast(message: string, type?: 'info' | 'success' | 'warning' | 'error'): void;
2319
+ }
@@ -0,0 +1,204 @@
1
+ # Lumia Custom Overlays GPT — Extended Reference
2
+
3
+ This is the companion knowledge file to `gpt-instructions.md`. The system prompt is capped at 8000 characters so long-form reference material lives here. When a rule here conflicts with `gpt-instructions.md`, the system prompt wins.
4
+
5
+ ---
6
+
7
+ ## SystemVariables Quick Reference
8
+
9
+ Curated short list. For anything not here, check `custom-overlays.d.ts` before suggesting a name. If a name is not in the enum, it does not exist — fall back to Config/Data or a custom variable.
10
+
11
+ ### Followers (lifetime / session count)
12
+
13
+ - Twitch: `{{twitch_total_follower_count}}` / `{{twitch_session_follower_count}}`
14
+ - Kick: `{{kick_total_follower_count}}` / `{{kick_session_follower_count}}`
15
+ - YouTube: `{{youtube_total_subscriber_count}}` (YouTube calls followers "subscribers")
16
+
17
+ ### Subscribers / members (lifetime / session count)
18
+
19
+ - Twitch: `{{twitch_total_subscriber_count}}` / `{{twitch_session_subscribers_count}}`
20
+ - Kick: `{{kick_total_subscriber_count}}` / `{{kick_session_subscriber_count}}`
21
+ - YouTube: `{{youtube_session_subscriber_count}}`
22
+
23
+ ### Donations (cross-platform aggregate)
24
+
25
+ - Lifetime: `{{total_donation_amount}}`, `{{total_donation_amount_currency}}`, `{{total_donation_amount_currency_symbol}}`
26
+ - Session: `{{session_donation_amount}}`, `{{session_donation_count}}`
27
+ - Top donor: `{{session_top_donator}}`, `{{session_top_donator_amount}}`
28
+
29
+ ### Bits (Twitch only)
30
+
31
+ - Lifetime / session count: `{{twitch_total_bits_count}}` / `{{twitch_session_bits_count}}`
32
+ - Last bit: `{{twitch_last_bit}}`, `{{twitch_last_bit_amount}}`
33
+
34
+ ### Last-event names (great for "recent X" overlays)
35
+
36
+ - `{{twitch_last_follower}}`, `{{twitch_last_subscriber}}`, `{{twitch_last_gifter}}`, `{{twitch_last_gifter_amount}}`, `{{twitch_last_raider}}`, `{{twitch_last_raid_amount}}`, `{{twitch_last_chatter}}`
37
+
38
+ ### Stream state
39
+
40
+ - Live state: `{{twitch_live}}`, `{{kick_live}}`, `{{youtube_live}}`
41
+ - Uptime: `{{twitch_uptime}}`, `{{youtube_uptime}}`
42
+ - Viewers: `{{twitch_current_viewer_count}}`, `{{kick_current_viewer_count}}`, `{{youtube_current_viewer_count}}`
43
+
44
+ ### Channel info
45
+
46
+ - Twitch: `{{twitch_username}}`, `{{twitch_avatar}}`, `{{twitch_channel_title}}`, `{{twitch_category}}`
47
+ - Kick: `{{kick_username}}`, `{{kick_avatar}}`, `{{kick_channel_title}}`, `{{kick_category}}`
48
+
49
+ ### Function-style SystemVariables (useful in Config `input` with `enableVariables: true`)
50
+
51
+ - Math / logic: `{{math=...}}`, `{{round=...}}`, `{{compare=...}}`, `{{if=...}}`, `{{between=...}}`, `{{min=...}}`, `{{max=...}}`, `{{coalesce=...}}`
52
+ - Random: `{{random=min,max}}`, `{{random_input=a,b,c}}`, `{{selection=first,second}}`
53
+ - Strings / dates: `{{regex_extract=...}}`, `{{replace=...}}`, `{{format_date=...}}`, `{{time_since=...}}`
54
+
55
+ Rules: SystemVariables are read-only from overlays. Never `setVariable` on a SystemVariable key. Do not create Config/Data keys that duplicate SystemVariable concepts.
56
+
57
+ ---
58
+
59
+ ## Alert Values (`data.alert`)
60
+
61
+ Always match with exact string equality — never `includes`, never substring matching.
62
+
63
+ ### Twitch
64
+
65
+ - `twitch-follower`, `twitch-subscriber`, `twitch-giftSubscription`, `twitch-raid`, `twitch-raidOut`
66
+ - `twitch-bits`, `twitch-bitsCombo`, `twitch-points`, `twitch-redemption`, `twitch-extension`
67
+ - `twitch-channelJoin`, `twitch-channelLeave`, `twitch-firstChatter`, `twitch-entrance`, `twitch-clip`
68
+ - `twitch-streamLive`, `twitch-streamOffline`, `twitch-categoryChanged`
69
+ - `twitch-hypetrainStarted`, `twitch-hypetrainProgressed`, `twitch-hypetrainLevelProgressed`, `twitch-hypetrainEnded`
70
+ - `twitch-pollStarted`, `twitch-pollProgressed`, `twitch-pollEnded`
71
+ - `twitch-predictionStarted`, `twitch-predictionProgressed`, `twitch-predictionLocked`, `twitch-predictionEnded`
72
+ - `twitch-goalStarted`, `twitch-goalProgressed`, `twitch-goalEnded`
73
+ - `twitch-charityDonation`, `twitch-charityCampaignStarted`, `twitch-charityCampaignProgressed`, `twitch-charityCampaignStopped`
74
+ - `twitch-banned`, `twitch-timeout`, `twitch-timeoutOver`, `twitch-shoutoutReceive`
75
+ - `twitch-adStarted`, `twitch-adStopped`, `twitch-watchStreak`, `twitch-powerups`
76
+
77
+ ### Kick
78
+
79
+ - `kick-follower`, `kick-subscriber`, `kick-giftSubscription`, `kick-points`, `kick-raid`, `kick-hosted`
80
+ - `kick-streamLive`, `kick-streamOffline`, `kick-firstChatter`, `kick-entrance`
81
+ - `kick-banned`, `kick-unbanned`
82
+
83
+ ### YouTube
84
+
85
+ - `youtube-subscriber`, `youtube-member`, `youtube-giftMembers`, `youtube-superchat`, `youtube-superstickers`
86
+ - `youtube-streamLive`, `youtube-streamOffline`, `youtube-firstChatter`, `youtube-entrance`
87
+
88
+ ### Donations (all cross-platform)
89
+
90
+ - `streamlabs-donation`, `streamelements-donation`, `extralife-donation`, `donordrive-donation`
91
+ - `tiltify-campaignDonation`, `kofi-donation`, `kofi-subscription`, `kofi-shopOrder`
92
+ - `fourthwall-donation`, `fourthwall-orderPlaced`, `fourthwall-giftPurchase`, `fourthwall-subscriptionPurchased`
93
+ - `patreon-pledge`, `lumiastream-donation`
94
+
95
+ For the canonical full enum see `custom-overlays-alerts.d.ts`.
96
+
97
+ ---
98
+
99
+ ## `Overlay.chatbot` Platform Values
100
+
101
+ `platform` is optional. Omit to send to every connected chat. When set, use exactly one of:
102
+
103
+ - `"twitch"`, `"youtube"`, `"kick"`, `"tiktok"`, `"facebook"`, `"trovo"`
104
+
105
+ Never invent other values. Never capitalize.
106
+
107
+ ---
108
+
109
+ ## OBS Events
110
+
111
+ When the overlay runs inside OBS with Lumia connected, OBS events are forwarded to `window` as real DOM `CustomEvent`s. Lumia auto-detects which events the overlay uses from string literals in `addEventListener` calls — so always use a direct string literal.
112
+
113
+ ### Supported event names
114
+
115
+ - `obsRecordingStarted`, `obsRecordingStopped`, `obsRecordingPaused`, `obsRecordingUnpaused`
116
+ - `obsStreamingStarted`, `obsStreamingStopped`
117
+ - `obsReplaybufferStarted`, `obsReplaybufferStopped`
118
+ - `obsVirtualcamStarted`, `obsVirtualcamStopped`
119
+ - `obsSceneChanged`
120
+ - `obsTransitionBegin`, `obsTransitionEnd`
121
+ - `obsSourceVisibleChanged`, `obsSourceActiveChanged`
122
+
123
+ ### Usage
124
+
125
+ ```js
126
+ window.addEventListener("obsSceneChanged", (e) => {
127
+ const sceneName = e.detail?.name;
128
+ // react to scene change
129
+ });
130
+ ```
131
+
132
+ Notes:
133
+
134
+ - `e.detail` is correct here because these are real `CustomEvent` objects. Lumia's own overlay events (`chat`, `alert`, `hfx`, `virtuallight`, `overlaycontent`) still use the raw-payload `Overlay.on` API — don't confuse the two.
135
+ - OBS events only fire when the overlay runs inside OBS with Lumia running. Handle the case where they never fire.
136
+
137
+ ---
138
+
139
+ ## Free CDN Assets (no API key, hotlink-safe)
140
+
141
+ Safe to recommend to normal users. Stable URLs, permissive licenses, no signup required.
142
+
143
+ ### Images
144
+
145
+ - **Lorem Picsum** — random photos, CC0.
146
+ - Pattern: `https://picsum.photos/{width}/{height}?random={seed}`
147
+ - Example: `https://picsum.photos/800/600?random=12`
148
+ - **DiceBear** — deterministic avatars. Great for chat-avatar fallbacks.
149
+ - Pattern: `https://api.dicebear.com/9.x/{style}/svg?seed={anything}`
150
+ - Styles: `bottts`, `pixel-art`, `lorelei`, `thumbs`, `shapes`, `adventurer`, `avataaars`, `fun-emoji`, `identicon`, `initials`, `micah`, `miniavs`, `notionists`, `open-peeps`, `personas`.
151
+ - Example: `https://api.dicebear.com/9.x/bottts/svg?seed=lumia`
152
+
153
+ ### Icons and logos
154
+
155
+ - **Simple Icons** — brand logos for 3000+ companies.
156
+ - Pattern: `https://cdn.simpleicons.org/{slug}/{color?}`
157
+ - Example: `https://cdn.simpleicons.org/twitch/9146FF`
158
+ - **Twemoji** — Twitter's open emoji set (MIT).
159
+ - Pattern: `https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/72x72/{codepoint}.png`
160
+ - Example (🔥 = 1f525): `https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/72x72/1f525.png`
161
+ - **OpenMoji** — CC BY-SA open emoji.
162
+ - Pattern: `https://openmoji.org/data/color/svg/{CODEPOINT}.svg`
163
+
164
+ ### Pokemon sprites (used by the Pokemon example)
165
+
166
+ - `https://img.pokemondb.net/sprites/home/{normal|shiny}/{slug}.png`
167
+
168
+ ### Do NOT recommend
169
+
170
+ Services requiring an API key or signup (Unsplash API, Pexels, Pixabay, Giphy, Tenor, Freesound) — normal users won't do the setup.
171
+
172
+ ---
173
+
174
+ ## Lumia-Hosted Asset Library (existing placeholders)
175
+
176
+ Already hosted on Lumia's CDN — safe to use as fallbacks when the user hasn't supplied an asset:
177
+
178
+ - Generic image: `https://storage.lumiastream.com/placeholderLogo.png`
179
+ - Empty avatar: `https://storage.lumiastream.com/placeholderUserIcon.png`
180
+ - Game art: `https://storage.lumiastream.com/overlays/2/bed3ba31-f516-476d-975a-3498f5b5f33e.png`
181
+ - Spin SFX: `https://storage.lumiastream.com/overlays/lumia/audio/Wheel_of_Fortune.mp3`
182
+ - Win SFX: `https://storage.lumiastream.com/overlays/lumia/audio/crowdClap.mp3`
183
+ - Lose SFX: `https://storage.lumiastream.com/overlays/lumia/audio/youLose.mp3`
184
+
185
+ ---
186
+
187
+ ## Lumia-Hosted Asset Library — NOT YET AVAILABLE (do not suggest)
188
+
189
+ ⚠️ There is **no** general `https://storage.lumiastream.com/overlays/lumia/assets/...` asset library yet — those URLs do **not** resolve. Never invent, guess, or hand a user any `.../overlays/lumia/assets/...` path. An expanded CC0 SFX/image library is planned for that location, but until it ships, only point users at the two safe sources:
190
+
191
+ - The confirmed Lumia-hosted placeholders in the **Lumia-Hosted Asset Library (existing placeholders)** section above.
192
+ - The keyless free-CDN patterns in the **Free CDN Assets** section above.
193
+
194
+ If a user needs a sound or image you can't source from those, have them upload their own through a Config `soundupload` / `imageupload` / `videoupload` field instead of pointing at a URL that may not exist.
195
+
196
+ ---
197
+
198
+ ## Style Crib Sheet
199
+
200
+ - Numbers from Config/Data: `const n = Number(Overlay.data?.key) || defaultValue;`
201
+ - Guard against missing chat fields: `const msg = (data.message || "").trim();`
202
+ - Check moderator status: `const isMod = data.userLevels?.mod || data.userLevels?.isSelf;`
203
+ - Get a Config value as string via token replacement: `const color = "{{accentColor}}";`
204
+ - Lumia wraps the JS tab in `(async () => { ... })()`, so top-level `await` works.
@@ -360,9 +360,18 @@ export interface ChatEvent {
360
360
  export interface AlertEvent {
361
361
  /** Type of alert from LumiaAlertValues enum */
362
362
  alert: LumiaAlertValues;
363
- /** Dynamic value associated with the alert (e.g., donation amount, sub months) */
364
- dynamic: { value: number | string };
365
- /** Additional metadata about the alert */
363
+ /**
364
+ * Event-specific mutable values. `value` is the common amount (bits, raid
365
+ * viewers, sub tier, donation amount, …) but most alerts add their own fields —
366
+ * e.g. subs carry `isGift`, `giftAmount`, `isResub`, `subMonths`. For the exact
367
+ * per-alert shape see `AlertDynamic<T>` in `custom-overlays-alerts.d.ts`.
368
+ */
369
+ dynamic: { value?: number | string; [key: string]: unknown };
370
+ /**
371
+ * Additional metadata about the alert. The fields below are common to most
372
+ * alerts; alert-specific fields are merged in too — see `AlertExtra<T>` in
373
+ * `custom-overlays-alerts.d.ts`.
374
+ */
366
375
  extraSettings: {
367
376
  /** Username of the person triggering the alert */
368
377
  username: string;
@@ -384,6 +393,8 @@ export interface AlertEvent {
384
393
  timingType: string;
385
394
  /** Alert display duration in milliseconds */
386
395
  duration: number;
396
+ /** Alert-specific extra fields (e.g. subPlan, gifter, recipients, message). */
397
+ [key: string]: unknown;
387
398
  };
388
399
  /** Whether this alert was triggered from Lumia itself */
389
400
  fromLumia: boolean;
@@ -476,6 +487,19 @@ export type OverlayEventHandler = (data: OverlayEvent) => void;
476
487
  * Available globally as `window.Overlay` in custom overlays.
477
488
  */
478
489
  export interface Overlay {
490
+ /**
491
+ * Current values from the Data tab (defaults seeded from Configs `value`s,
492
+ * then overridden by what the user set). Read Config/Data values from here,
493
+ * e.g. `Overlay.data.fontSize`. There is no bare top-level `data` variable.
494
+ */
495
+ data: Record<string, any>;
496
+
497
+ /**
498
+ * This overlay's `codeId` (letters, numbers, hyphens, underscores; max 25 chars).
499
+ * Scopes `saveStorage`/`getStorage` and targets `overlaycontent` messages.
500
+ */
501
+ codeId: string;
502
+
479
503
  /**
480
504
  * Register an event listener for chat messages
481
505
  * @param event - Event type "chat"
@@ -521,6 +545,19 @@ export interface Overlay {
521
545
  */
522
546
  on(event: 'overlaycontent', handler: (data: CustomOverlayContentEvent) => void): void;
523
547
 
548
+ /**
549
+ * Register a handler for Configs `actionbutton` clicks. Not a platform event —
550
+ * it's Configs-driven, needs no `events` declaration, and is independent of the
551
+ * `OverlayListener` subscriptions. `key` is the field's JSON key; `value` is its
552
+ * optional `value`.
553
+ * @param event - Event type "configAction"
554
+ * @example
555
+ * window.Overlay.on('configAction', ({ key }) => {
556
+ * if (key === 'resetGame') resetGame();
557
+ * });
558
+ */
559
+ on(event: 'configAction', handler: (data: { key: string; value?: unknown }) => void): void;
560
+
524
561
  /**
525
562
  * Execute a Lumia Stream command
526
563
  * @param command - Name of the command to execute
@@ -2260,3 +2297,23 @@ export declare enum SystemVariables {
2260
2297
  }
2261
2298
 
2262
2299
  // <auto-generated-end name="SystemVariables" />
2300
+
2301
+ // -----------------------------------------------------------------------------
2302
+ // Globals available inside a custom overlay's JS tab
2303
+ // -----------------------------------------------------------------------------
2304
+
2305
+ declare global {
2306
+ /** The Overlay API. Available unprefixed as `Overlay` or as `window.Overlay`. */
2307
+ const Overlay: Overlay;
2308
+
2309
+ interface Window {
2310
+ Overlay: Overlay;
2311
+ }
2312
+
2313
+ /**
2314
+ * Show a toast notification in Lumia.
2315
+ * @param message - Text to display
2316
+ * @param type - Toast style (defaults to "info")
2317
+ */
2318
+ function toast(message: string, type?: 'info' | 'success' | 'warning' | 'error'): void;
2319
+ }
@@ -309,14 +309,6 @@ export const VARIABLE_EXAMPLES = {
309
309
  { label: 'Post each line of a URL', snippet: 'filesay=https://example.com/list.txt' },
310
310
  { label: 'Post each line of a local file', snippet: 'filesay=C:/path/list.txt' },
311
311
  ],
312
- set_alerts_paused: [
313
- { label: 'Pause alerts', snippet: 'set_alerts_paused=true' },
314
- { label: 'Resume alerts', snippet: 'set_alerts_paused=false' },
315
- ],
316
- set_sfx_muted: [
317
- { label: 'Mute sound effects', snippet: 'set_sfx_muted=true' },
318
- { label: 'Unmute sound effects', snippet: 'set_sfx_muted=false' },
319
- ],
320
312
  loyalty_top: [
321
313
  { label: 'Top 3 users', snippet: 'loyalty_top=3' },
322
314
  { label: 'Top 5 users', snippet: 'loyalty_top=5' },
@@ -312,14 +312,6 @@ exports.VARIABLE_EXAMPLES = {
312
312
  { label: 'Post each line of a URL', snippet: 'filesay=https://example.com/list.txt' },
313
313
  { label: 'Post each line of a local file', snippet: 'filesay=C:/path/list.txt' },
314
314
  ],
315
- set_alerts_paused: [
316
- { label: 'Pause alerts', snippet: 'set_alerts_paused=true' },
317
- { label: 'Resume alerts', snippet: 'set_alerts_paused=false' },
318
- ],
319
- set_sfx_muted: [
320
- { label: 'Mute sound effects', snippet: 'set_sfx_muted=true' },
321
- { label: 'Unmute sound effects', snippet: 'set_sfx_muted=false' },
322
- ],
323
315
  loyalty_top: [
324
316
  { label: 'Top 3 users', snippet: 'loyalty_top=3' },
325
317
  { label: 'Top 5 users', snippet: 'loyalty_top=5' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumiastream/lumia-types",
3
- "version": "3.8.1",
3
+ "version": "3.8.3",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",