Skip to content

Instantly share code, notes, and snippets.

@Windows81
Last active March 23, 2026 07:49
Show Gist options
  • Select an option

  • Save Windows81/76c13c3ec634d4c28ea27323c7da8eab to your computer and use it in GitHub Desktop.

Select an option

Save Windows81/76c13c3ec634d4c28ea27323c7da8eab to your computer and use it in GitHub Desktop.
Lua script for Advanced Scene Switcher (on OBS) to make the video scale fully to "Display Capture"; also moving other elements without scaling them
local obs = obslua
local WIDTH_OFFSET_BEFORE = 0
local WIDTH_OFFSET_AFTER = 0
local HEIGHT_OFFSET_BEFORE = 120
local HEIGHT_OFFSET_AFTER = 0
local SCREEN_SCALAR = 2
function transform(sceneitem, x, y, w, h)
local transform_info = obs.obs_transform_info()
obs.vec2_set(transform_info.pos, x, y)
obs.vec2_set(transform_info.scale, w, h)
transform_info.alignment = 5 -- OBS_ALIGN_LEFT | OBS_ALIGN_TOP
obs.obs_sceneitem_set_info2(sceneitem, transform_info)
end
function get_video_scale(config)
local base_width = obs.config_get_uint(config, "Video", "BaseCX")
local base_height = obs.config_get_uint(config, "Video", "BaseCY")
local output_width = obs.config_get_uint(config, "Video", "OutputCX")
local output_height = obs.config_get_uint(config, "Video", "OutputCY")
return {
base = {
w = base_width,
h = base_height,
},
scale = {
w = output_width / base_width,
h = output_height / base_height,
},
}
end
function get_sceneitem_transform(sceneitem)
local transform_info = obs.obs_transform_info()
obs.obs_sceneitem_get_info2(sceneitem, transform_info)
return transform_info
end
function get_source_scale(source)
return {
w = obs.obs_source_get_width(source),
h = obs.obs_source_get_height(source),
}
end
function get_all_sceneitems_in_all_scenes()
local result = {}
local scene_list = obs.obs_frontend_get_scenes()
for _, source in next, scene_list do
local sceneitem_list = obs.obs_scene_enum_items(obs.obs_scene_from_source(source))
obs.script_log(obs.LOG_WARNING, tostring(sceneitem_list))
for _, sceneitem in next, sceneitem_list do
table.insert(result, sceneitem)
end
obs.obs_source_release(source)
end
return result
end
function calc_new_pos(
transform_info,
old_w,
old_h,
new_w,
new_h,
offset_w_before,
offset_h_before,
offset_w_after,
offset_h_after
)
local function determine_alpha(pos, size, start, finish)
if pos > finish then
return 1
end
return 0
--[[
local alpha = (pos - start) / (finish - start) - size
if alpha < 0 then
return 0
elseif alpha > 1 then
return 1
end
return alpha
]]
end
local pos_x = transform_info.pos.x
local pos_y = transform_info.pos.y
local scene_w = transform_info.scale.x
local scene_h = transform_info.scale.y
local delta_w = new_w - old_w
local delta_h = new_h - old_h
return {
x = pos_x + delta_w * determine_alpha(pos_x, scene_w, offset_w_before, old_w - offset_w_after),
y = pos_y + delta_h * determine_alpha(pos_y, scene_h, offset_h_before, old_h - offset_h_after),
}
end
function calc_new_scale(transform_info, old_w, old_h, new_w, new_h)
local scalar = old_h / new_h
return {
x = transform_info.scale.x * scalar,
y = transform_info.scale.y * scalar,
}
end
function run()
local scene_source = obs.obs_frontend_get_current_scene()
local scene = obs.obs_scene_from_source(scene_source)
local display_sceneitem = obs.obs_scene_find_source(scene, "Display Capture")
local display_source = obs.obs_sceneitem_get_source(display_sceneitem)
local display_size = get_source_scale(display_source)
local sceneitem_list = get_all_sceneitems_in_all_scenes()
local sceneitem_transform_dict = {}
for i, sceneitem in next, sceneitem_list do
if sceneitem ~= display_sceneitem then
sceneitem_transform_dict[sceneitem] = get_sceneitem_transform(sceneitem)
end
end
local config = obs.obs_frontend_get_profile_config()
local video_scale = get_video_scale(config)
local total_width = SCREEN_SCALAR * display_size.w + WIDTH_OFFSET_BEFORE + WIDTH_OFFSET_AFTER
local total_height = SCREEN_SCALAR * display_size.h + HEIGHT_OFFSET_BEFORE + HEIGHT_OFFSET_AFTER
obs.config_set_uint(config, "Video", "BaseCX", total_width)
obs.config_set_uint(config, "Video", "BaseCY", total_height)
obs.config_set_uint(config, "Video", "OutputCX", total_width)
obs.config_set_uint(config, "Video", "OutputCY", total_height)
obs.obs_frontend_reset_video()
obs.config_save(config)
obs.obs_source_release(scene_source)
for sceneitem, sceneitem_transform in next, sceneitem_transform_dict do
local new_pos = calc_new_pos(
sceneitem_transform,
video_scale.base.w,
video_scale.base.h,
total_width,
total_height,
WIDTH_OFFSET_BEFORE,
HEIGHT_OFFSET_BEFORE,
WIDTH_OFFSET_AFTER,
HEIGHT_OFFSET_AFTER
)
local new_scale =
calc_new_scale(sceneitem_transform, video_scale.base.w, video_scale.base.h, total_width, total_height)
obs.vec2_set(sceneitem_transform.pos, new_pos.x, new_pos.y)
obs.vec2_set(sceneitem_transform.scale, new_scale.x, new_scale.y)
obs.obs_sceneitem_set_info2(sceneitem, sceneitem_transform)
end
transform(display_sceneitem, WIDTH_OFFSET_BEFORE, HEIGHT_OFFSET_BEFORE, SCREEN_SCALAR, SCREEN_SCALAR)
obs.sceneitem_list_release(sceneitem_list)
--obs.script_log(obs.LOG_WARNING, tostring(obs.config_get_uint(config, "Video", "BaseCY")))
return true
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment