├── Final └── getting_start_with_lua_script.lua ├── README.md ├── getting_start_with_lua_script.lua └── media └── example.gif /README.md: -------------------------------------------------------------------------------- 1 | # Cheat Sheet for Creating Scenes and Scene Items Functions in Lua 2 | 3 | ## Creating A Custom Interface With A Simple Lua Script Inside OBS Studio 4 | 5 |  6 | 7 | This cheatsheet is a TL;DR for the things covered in the [lua scripting tutorial I created](https://morebackgroundsplease.medium.com/use-a-lua-script-to-import-your-twitch-streaming-overlay-designs-into-obs-studio-b8f688aeb9e8) for scripting with Lua for OBS Studio and adding scenes and importing overlays, images, and text. 8 | 9 | For an example code of the some of the functions used below please go here: [Example Code](Final/getting_start_with_lua_script.lua) 10 | 11 | Please also refer to upgradeQ's Python scripting Cheatsheet here, as it may contain similar items written in Python: [upgradeQ's Python Cheat Sheet](https://github.com/upgradeQ/OBS-Studio-Python-Scripting-Cheatsheet-obspython-Examples-of-API#using-classes) 12 | 13 | For more resources definitely check out the amazing group of devs over at the Wiki and the official OBS scripting documentation here: 14 | - [The OBS Getting Started Wiki](https://obsproject.com/wiki/Getting-Started-With-OBS-Scripting) 15 | - [The Official OBS Scripting Documentation](https://obsproject.com/docs/scripting.html) 16 | 17 | # Table Of Contents 18 | - [Image to Base64 Converter](#image-to-base64-converter) 19 | - [Setting Keys](#setting-keys) 20 | - [Ffmpeg_source Setting Keys](#ffmpeg_source-setting-keys) 21 | - [Image_source Setting Keys](#image_source-setting-keys) 22 | - [Text_gdiplus Setting Keys](#text_gdiplus_setting_keys) 23 | - [Color_filter Setting Keys](#color-filter-setting-keys) 24 | - [Source Creation Functions](#source-creation-functions) 25 | - [Scene Exists Function](#scene-exists-function) 26 | - [Create Scene Function](#create-scene-function) 27 | - [Create Loop Overlay Function](#create-loop-overlay-function) 28 | - [Create Image Function](#create-image-function) 29 | - [Create Text Function](#create-text-function) 30 | - [Create Color Filter Function](#create-color-filter-function) 31 | - [Import All Scenes Function](#import-all-scenes-function) 32 | - [OBS Lua Library Methods](#obs-lua-library-methods) 33 | - [Initiate The OBS Lua Library](#initiate-the-obs-lua-library) 34 | - [Get The Script Path](#get-the-script-path) 35 | - [Useful Scene Methods](#useful-scene-methods) 36 | - [Get All The Scene Names](#get-all-the-scene-names) 37 | - [Create A New Scene Object And Release The Scene Object](#create-a-new-scene-object-and-release-the-scene-object) 38 | - [Get The Source Of A Specific Scene](#get-the-source-of-a-specific-scene) 39 | - [Get The Source Of The Current Viewed/Selected Scene](#get-the-source-of-the-current-viewed/selected-scene) 40 | - [Set The Current Viewed Scene Inside OBS](#set-the-current-viewed-scene-inside-obs) 41 | - [Get The Scene Context From A Scene](#get-the-scene-context-from-a-scene) 42 | - [Release A Scene Object](#release-a-scene-object) 43 | - [Useful Source Methods](#useful-source-methods) 44 | - [Create A Data Settings Object](#create-a-data-settings-object) 45 | - [Set A String Key](#set-a-string-key) 46 | - [Set A Bool Key](#set-a-bool-key) 47 | - [Create A Blank Object Value Array](#create-a-blank-object-value-array) 48 | - [Set An Object Key](#set-an-object-key) 49 | - [Create A Source Object And Release It](#create-a-source-object-and-release-it) 50 | - [Update The Settings Of Your Source](#update-the-settings-of-your-source) 51 | - [Add A Source Object To A Scene](#add-a-source-object-to-a-scene) 52 | - [Create An OBS Vector](#create-an-obs-vector) 53 | - [Get The Scene Item From A Scene](#get-the-scene-item-from-a-scene) 54 | - [Set The Position Of A Scene Item](#set-the-position-of-a-scene-item) 55 | - [Set The Scale Of A Scene Item](#set-the-scale-of-a-scene-item) 56 | - [Release The Settings Object](#release-the-settings-object) 57 | - [Release A Source Object](#release-a-source-object) 58 | - [Get A List Of All The Scenes Created In OBS In Source Object Form](#get-a-list-of-all-the-sccenes-created-in-obs-in-source-object-form) 59 | - [Useful Properties Methods](#useful-properties-methods) 60 | - [Create A Properties Object](#create-a-properties-object) 61 | - [Create A Button](#create-a-button) 62 | 63 | 64 | # Image To Base64 Converter 65 | [Converter](https://www.base64-image.de/) 66 | 67 | # Setting Keys 68 | 69 | ## Ffmpeg_source Setting Keys 70 | | Key | Type | Set With | 71 | | --- | --- | --- | 72 | | "local_file" | string | obs.obs_data_set_string() | 73 | | "looping" | bool | obs.obs_data_set_bool() | 74 | 75 | ## Image_source Setting Keys 76 | | Key | Type | Set With | 77 | | --- | --- | --- | 78 | | "file" | string | obs.obs_data_set_string() | 79 | 80 | ## Text_gdiplus Setting Keys 81 | 82 | ***For Face, Flags, Size, and Style make sure to set them to a json data object then set the json data object to the Font key.*** 83 | 84 | | Key | Type | Set With | 85 | | --- | --- | --- | 86 | | "face" | string | obs.obs_data_set_string() | 87 | | "flags" | int | obs.obs_data_set_int() | 88 | | "size" | int | obs.obs_data_set_int() | 89 | | "style" | string | obs.obs_data_set_string() | 90 | | "font" | object | obs.obs_data_set_obj() | 91 | | "text" | string | obs.obs_data_set_string() | 92 | | "align" | string | obs.obs_data_set_string() | 93 | | "color" | int | obs.obs_data_set_int() | 94 | | "outline" | bool | obs.obs_data_set_bool() | 95 | | "outline_color" | int | obs.obs_data_set_int() | 96 | | "outline_size" | int | obs.obs_data_set_int() | 97 | 98 | ## Color_Filter Setting Keys 99 | 100 | | Key | Type | Set With | 101 | | --- | --- | --- | 102 | | "brightness" | int | obs.obs_data_set_int() | 103 | | "contrast" | int | obs.obs_data_set_int() | 104 | | "gamma" | int | obs.obs_data_set_int() | 105 | | "hue_shift" | int | obs.obs_data_set_int() | 106 | | "opacity" | int | obs.obs_data_set_int() | 107 | | "saturation" | int | obs.obs_data_set_int() | 108 | 109 | # Source Creation Functions 110 | 111 | ## Scene Exists Function 112 | ```lua 113 | function scene_exists(scene_name) 114 | 115 | local scene_names = obs.obs_frontend_get_scene_names() 116 | local value = 0 117 | 118 | for i, name in ipairs(scene_names) do 119 | if string.find(scene_names[i], scene_name) then 120 | value = value + 1 121 | end 122 | end 123 | 124 | return value 125 | 126 | end 127 | ``` 128 | 129 | ## Create Scene Function 130 | ```lua 131 | function create_scene(scene_name) 132 | 133 | if scene_exists(scene_name) >= 1 then 134 | scene_name = scene_name .. " " .. scene_exists(scene_name) 135 | end 136 | 137 | local new_scene = obs.obs_scene_create(scene_name) 138 | 139 | obs.obs_frontend_set_current_scene(obs.obs_scene_get_source(new_scene)) 140 | local current_scene = obs.obs_frontend_get_current_scene() 141 | local scene = obs.obs_scene_from_source(current_scene) 142 | 143 | obs.obs_scene_release(new_scene) 144 | obs.obs_scene_release(scene) 145 | 146 | return new_scene, scene 147 | 148 | end 149 | ``` 150 | 151 | ## Create Loop Overlay Function 152 | ```lua 153 | function create_loop_overlay(file_location, name, new_scene, scene, xpos, ypos, xscale, yscale) 154 | 155 | local pos = obs.vec2() 156 | local scale = obs.vec2() 157 | 158 | local overlay_settings = obs.obs_data_create() 159 | obs.obs_data_set_string(overlay_settings, "local_file", script_path() .. file_location) 160 | obs.obs_data_set_bool(overlay_settings, "looping", true) 161 | local overlay_source = obs.obs_source_create("ffmpeg_source", name, overlay_settings, nil) 162 | obs.obs_scene_add(new_scene, overlay_source) 163 | 164 | local overlay_sceneitem = obs.obs_scene_find_source(scene, name) 165 | local overlay_location = pos 166 | local overlay_scale = scale 167 | if overlay_sceneitem then 168 | overlay_location.x = xpos 169 | overlay_location.y = ypos 170 | overlay_scale.x = xscale 171 | overlay_scale.y = yscale 172 | obs.obs_sceneitem_set_pos(overlay_sceneitem, overlay_location) 173 | obs.obs_sceneitem_set_scale(overlay_sceneitem, overlay_scale) 174 | end 175 | 176 | obs.obs_source_update(overlay_source, overlay_settings) 177 | obs.obs_data_release(overlay_settings) 178 | obs.obs_source_release(overlay_source) 179 | 180 | end 181 | ``` 182 | 183 | ## Create Image Function 184 | ```lua 185 | function create_image(file_location, name, new_scene, scene, xpos, ypos, xscale, yscale) 186 | 187 | local pos = obs.vec2() 188 | local scale = obs.vec2() 189 | 190 | local image_settings = obs.obs_data_create() 191 | obs.obs_data_set_string(image_settings, "file", script_path() .. file_location) 192 | local image_source = obs.obs_source_create("image_source", name, image_settings, nil) 193 | obs.obs_scene_add(new_scene, image_source) 194 | 195 | local image_sceneitem = obs.obs_scene_find_source(scene, name) 196 | local image_location = pos 197 | local image_scale = scale 198 | if image_sceneitem then 199 | image_location.x = xpos 200 | image_location.y = ypos 201 | image_scale.x = xscale 202 | image_scale.y = yscale 203 | obs.obs_sceneitem_set_pos(image_sceneitem, image_location) 204 | obs.obs_sceneitem_set_scale(image_sceneitem, image_scale) 205 | end 206 | 207 | obs.obs_source_update(image_source, image_settings) 208 | obs.obs_data_release(image_settings) 209 | obs.obs_source_release(image_source) 210 | 211 | end 212 | ``` 213 | 214 | ## Create Text Function 215 | ```lua 216 | function create_text(face, size, style, text, align, name, new_scene, scene, x, y) 217 | 218 | local pos = obs.vec2() 219 | local scale = obs.vec2() 220 | 221 | local text_settings = obs.obs_data_create() 222 | local text_font_object = obs.obs_data_create_from_json('{}') 223 | obs.obs_data_set_string(text_font_object, "face", face) 224 | obs.obs_data_set_int(text_font_object, "flags", 0) 225 | obs.obs_data_set_int(text_font_object, "size", size) 226 | obs.obs_data_set_string(text_font_object, "style", style) 227 | obs.obs_data_set_obj(text_settings, "font", text_font_object) 228 | obs.obs_data_set_string(text_settings, "text", text) 229 | obs.obs_data_set_string(text_settings, "align", align) 230 | local text_source = obs.obs_source_create("text_gdiplus", name, text_settings, nil) 231 | obs.obs_scene_add(new_scene, text_source) 232 | 233 | local text_sceneitem = obs.obs_scene_find_source(scene, name) 234 | local text_location = pos 235 | if text_sceneitem then 236 | text_location.x = x 237 | text_location.y = y 238 | obs.obs_sceneitem_set_pos(text_sceneitem, text_location) 239 | end 240 | 241 | obs.obs_source_update(text_source, text_settings) 242 | obs.obs_data_release(text_settings) 243 | obs.obs_data_release(text_font_object) 244 | obs.obs_source_release(text_source) 245 | 246 | end 247 | ``` 248 | 249 | ## Create Color Filter Function 250 | ```lua 251 | function add_color_filter(name, brightness, contrast, gamma, hue_shift, opacity, saturation) 252 | 253 | source = obs.obs_get_source_by_name(name) 254 | 255 | filter_settings = obs.obs_data_create() 256 | obs.obs_data_set_int(filter_settings, "brightness", brightness) 257 | obs.obs_data_set_int(filter_settings, "contrast", contrast) 258 | obs.obs_data_set_int(filter_settings, "gamma", gamma) 259 | obs.obs_data_set_int(filter_settings, "hue_shift", hue_shift) 260 | obs.obs_data_set_int(filter_settings, "opacity", opacity) 261 | obs.obs_data_set_int(filter_settings, "saturation", saturation) 262 | color_filter = obs.obs_source_create_private("color_filter", "Color Correct", filter_settings) 263 | obs.obs_source_filter_add(source, color_filter) 264 | 265 | obs.obs_source_update(color_filter, filter_settings) 266 | obs.obs_source_release(source) 267 | obs.obs_data_release(filter_settings) 268 | obs.obs_source_release(color_filter) 269 | 270 | end 271 | ``` 272 | 273 | ## Import All Scenes Function 274 | ```lua 275 | function import_all_scenes() 276 | 277 | -- 278 | -- your hard coded list of scene functions 279 | -- 280 | 281 | local scene_names = obs.obs_frontend_get_scene_names() 282 | local scene_list = obs.obs_frontend_get_scenes() 283 | 284 | for i, name in ipairs(scene_names) do 285 | if scene_names[i] == "Welcome" then 286 | scene = scene_list[i] 287 | obs.obs_frontend_set_current_scene(scene) 288 | break 289 | end 290 | end 291 | 292 | for i, scene in ipairs(scene_list) do 293 | obs.obs_source_release(scene) 294 | end 295 | 296 | end 297 | ``` 298 | 299 | # OBS Lua Library Methods 300 | 301 | Below covers some of the library methods I used in my tutorial. There are definitely plenty more and you can find them referring to the C documentation in the [OBS Documentation](https://obsproject.com/docs/index.html) 302 | 303 | ## Initiate the OBS Lua library 304 | 305 | ```lua 306 | obs = obslua 307 | ``` 308 | 309 | ## Get The Script Path 310 | 311 | This is useful in returning the location of your script on your local machine. You can use this to make relative paths to files located near your script such as a folder with your overlays. 312 | 313 | ```lua 314 | script_path() 315 | ``` 316 | 317 | # Useful Scene Methods 318 | 319 | Use the following methods I commonly used in my tutorial for creating and editing scenes. 320 | 321 | ## Get All The Scene Names 322 | 323 | This will return a list of all the names of your scenes created inside OBS. 324 | 325 | ```lua 326 | list_of_scene_names = obs.obs_frontend_get_scene_names() 327 | ``` 328 | 329 | ## Create A New Scene Object And Release The Scene Object 330 | 331 | Add a New Scene into OBS using this method, make sure to release the reference to the scene after. 332 | 333 | The release method will only expect a scene object. 334 | 335 | ```lua 336 | scene_name = "My New Scene" 337 | 338 | local scene_object = obs.obs_scene_create(scene_name) -- This will create your scene object and make your new scene appear inside OBS 339 | 340 | obs.obs_scene_release(scene_object) 341 | ``` 342 | 343 | ## Get The Source Of A Specific Scene 344 | 345 | A scene can also be considered a source. So to return the scene as a source object do the following: 346 | 347 | ```lua 348 | obs.obs_scene_get_source(scene_object) 349 | ``` 350 | 351 | ## Get the Source of the Current Viewed/Selected Scene 352 | 353 | Do the following to get the source object of the currently selected scene inside OBS: 354 | 355 | ```lua 356 | local current_scene = obs.obs_frontend_get_current_scene() 357 | ``` 358 | 359 | ## Set The Current Viewed Scene Inside OBS 360 | 361 | This method expects a source object instead of a scene object. So use the obs_scene_get_source method to get the source from a scene. 362 | 363 | ```lua 364 | obs.obs_frontend_set_current_scene(obs.obs_scene_get_source(scene_object)) 365 | ``` 366 | 367 | ## Get The "Scene Context" From A Scene 368 | 369 | This is different from obs_scene_get_source because scene_get_source returns the scene's source object. This returns the window or context of what the scene consists of. 370 | 371 | ```lua 372 | local scene_context = obs.obs_scene_from_source(source_object) 373 | ``` 374 | 375 | ## Release A Scene Object 376 | 377 | Do this after creating a Scene Object 378 | 379 | ```lua 380 | obs.obs_Scene_release(scene_object) 381 | ``` 382 | 383 | # Useful Source Methods 384 | 385 | The following covers methods related around creating sources within a scene, which can also be known as sceneitems. Sceneitems have properties or settings that can set by using specific methods for editing various setting keys. In my tutorial I go over a few source types, but the following can be applied generally to all types of sources. 386 | 387 | ## Create A Data Settings Object 388 | 389 | After creating your data settings object, make sure to release it. 390 | 391 | ```lua 392 | local settings_object = obs.obs_data_create() 393 | 394 | obs.obs_data_release(settings_object) 395 | ``` 396 | 397 | ## Set A String Key 398 | 399 | In this example we will set the "local_file" string key for a source type "ffmpeg_source" 400 | 401 | ```lua 402 | local file_path = path/to/a/video 403 | 404 | obs.obs_data_set_string(settings_object, "local_file", file_path) 405 | ``` 406 | 407 | ## Set A Bool Key 408 | 409 | For this example we will set the "looping" bool key for a source type "ffmpeg_source". The following method will expect three input parameters, the last one being a bool of either true or false. 410 | 411 | ```lua 412 | obs.obs_data_set_bool(settings_object, "looping", true) 413 | ``` 414 | 415 | ## Create A Blank Object Value Array 416 | 417 | ```lua 418 | local blank_object = obs.obs_data_create_from_json('{}') 419 | ``` 420 | 421 | ## Set An Object Key 422 | 423 | Object Keys are Keys that expect an Array of values instead of just one value. This method is useful for when you have to set the font. Below is an example of how to set the "font" key for a source type of "text_gdiplus" or basically a text source: 424 | 425 | ```lua 426 | local settings_object = obs.obs_data_create() 427 | 428 | local font_object = obs.obs_data_create_from_json('{}') 429 | 430 | obs.obs_data_set_string(font_object, "face", face) 431 | obs.obs_data_set_int(font_object, "flags", 0) 432 | obs.obs_data_set_int(font_object, "size", size) 433 | obs.obs_data_set_string(font_object, "style", style) 434 | 435 | obs.obs_data_set_obj(settings_object, "font", text_font_object) 436 | ``` 437 | 438 | ## Create A Source Object And Release It 439 | 440 | It is a good idea to create your source object after you have created your settings object. Your Settings object will be used as an input paramater for creating the source object. 441 | 442 | The following method will expect 4 input parameters: the type of source, a string value for name, the settings object, and hotkeydata. We will not be inputting any hotkey data so we will leave this as nil, or basically null. 443 | 444 | This example will show how to create a source type of "ffmpeg_source". Always make sure to release your data settings object and your source object. 445 | 446 | ```lua 447 | local settings_object = obs.obs_data_create() 448 | local file_path = path/to/a/video 449 | local name = "my_source_name" 450 | 451 | obs.obs_data_set_string(settings_object, "local_file", script_path() .. file_path) 452 | obs.obs_data_set_bool(settings_object, "looping", true) 453 | 454 | local source_object = obs.obs_source_create("ffmpeg_source", name, settings_object, nil) 455 | 456 | obs.obs_data_release(settings_object) 457 | obs.obs_source_release(source_object) 458 | 459 | ``` 460 | 461 | ## Update the Settings Of Your Source 462 | 463 | It is a good idea to always update your source settings with any key you have set. Do the following: 464 | ```lua 465 | obs.obs_source_update(source_object, settings_object) 466 | ``` 467 | 468 | ## Add A Source Object To A Scene 469 | 470 | After you succesfully created your source object, you can add it to your scene like so: 471 | 472 | ```lua 473 | obs.obs_scene_add(scene_object, source_object) 474 | ``` 475 | 476 | ## Create an OBS Vector 477 | 478 | This is useful for whenever you have to set a value for position or scale. 479 | 480 | ```lua 481 | local position = obs.vec2() 482 | ``` 483 | 484 | ## Get The Scene Item From A Scene 485 | 486 | In order to edit or change the position or scale of a Source Object in a scene, you need to call it as a scene item. The following method will expect a scene object, and the name given to your source that you added to your scene. To get the scene item from a source do: 487 | 488 | ```lua 489 | local sceneitem_object = obs.obs_scene_find_source(scene_object, name) 490 | ``` 491 | 492 | ## Set The Position Of A Scene Item 493 | 494 | Position is based on x,y coordinates in pixels, with the top left corner of the OBS Stream Viewer being 0,0. The following method will expect the sceneitem object and a vector for position x and position y. 495 | 496 | ```lua 497 | local position = obs.vec2() 498 | 499 | position.x = 25 500 | position.y = 25 501 | 502 | obs.obs_sceneitem_set_pos(sceneitem_object, position) 503 | ``` 504 | 505 | ## Set The Scale Of A Scene Item 506 | 507 | Scale is based on a scalar percentage of your original source's size. If you were to have a 1920 by 1080 video, then 1 would be 100% of your video's scale, and 0.5 being half the size. Use the following method to set your size of your source. Note that the Scale needs to be a vector, so create a vector first: 508 | 509 | ```lua 510 | local scale = obs.vec2() 511 | 512 | scale.x = 1 513 | scale.y = 0.5 514 | 515 | obs.obs_sceneitem_set_scale(sceneitem_object, scale) 516 | ``` 517 | 518 | ## Release The Settings Object 519 | 520 | ```lua 521 | obs.obs_data_release(settings_object) 522 | ``` 523 | 524 | ## Release A Source Object 525 | 526 | ```lua 527 | obs.obs_source_release(source_object) 528 | 529 | ``` 530 | 531 | ## Get A List Of All The Scenes Created In OBS In Source Object Form 532 | 533 | This is useful if you want to retrieve a full list of all scenes in the form of source objects you made inside OBS. Always make sure to release your source objects as well. Please don't confuse this as a list of all the sceneitems you have in your scene. 534 | 535 | ```lua 536 | local scene_list = obs.obs_front_end_get_scenes() 537 | 538 | for i, scene in ipairs(scene_list) do 539 | obs.obs_source_release(scene) 540 | end 541 | ``` 542 | 543 | # Useful Properties Methods 544 | 545 | ## Create A Properties Object 546 | 547 | Here is where you can create and add cool menu items, buttons, and sliders into your script. You start with first creating the actual properties object that will contain all your cool stuff. 548 | 549 | ```lua 550 | local properties_object = obs.obs_properties_create() 551 | ``` 552 | 553 | ## Create A Button 554 | 555 | This will show how to add a button to your UI by incorporating it into your properties object. This method will expect 4 input parameters which are your properties object, a name, the actual displayed text, and a callback function. In the example below I have a "welcome_scene_function" function that will act as my callback function. Please note that I intentionally left this function blank 556 | 557 | ```lua 558 | function welcome_scene_function) 559 | end 560 | 561 | local properties_object = obs.obs_properties_create() 562 | 563 | local welcome_button = obs.obs_properties_add_button(properties_object, "welcome_button", "Welcome!", welcome_scene_function) 564 | ``` -------------------------------------------------------------------------------- /getting_start_with_lua_script.lua: -------------------------------------------------------------------------------- 1 | obs = obslua 2 | 3 | local icon1 = "put base64 data here" 4 | 5 | local description = [[ 6 |
8 |
10 |