Implement Transition Tree plugin - #1
Merged
Merged
Conversation
Adds a full OBS Studio plugin for per-switch transition rules, covering the feature set of Exeldro's Transition Table and extending it. Marks are applied the same way Transition Table does it: OBS's own per-scene transition override is written on every possible destination scene before a switch, and OBS picks it up. Only scenes the plugin itself wrote to are ever cleared again, so overrides set in OBS directly are left alone. Features: - Presets, each stored either locally in the scene collection or globally in the plugin config dir. Every scene collection remembers its own active preset. - Several transitions per mark, chosen sequentially, at random, at random without immediate repeat, or by weighted random. The pick is made on arrival at a scene and held until departure, so each switch consumes one roll; sequential positions advance only for the mark that actually fired. - Scene matching by explicit list, "any", or "any except", on both sides. Resolution prefers the most specific match, from-side first. - Per-mark enable/disable, falling through to the next matching rule. - Editor grouped as a tree by from-scene with a detail panel. The search box only filters the view; adding a mark is a separate button, so narrowing the list cannot hide the controls needed to create one. - Hotkeys for per-preset activation, next/previous preset, and a global enable/disable pair. - obs-websocket vendor "transition-tree" for preset and mark control, plus Transition Table's request names for compatibility, and a proc handler. - JSON import/export, accepting Transition Table exports, and a one-time offer to migrate Transition Table data found in a scene collection. - Creating transitions from the window by driving OBS's own add-transition flow, since no public API exists for registering one. Warns when Transition Table is loaded alongside, as both write the same per-scene settings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MBcrZqvWJy32tBVg5i9VD9
All three platform builds failed with "QDialog: No such file or directory". The `template` preset that every other preset inherits from pins ENABLE_FRONTEND_API and ENABLE_QT to false, and a preset cache variable overrides the option() default in CMakeLists.txt, so flipping the defaults there had no effect on preset-driven builds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MBcrZqvWJy32tBVg5i9VD9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Turns the plugin template into the full Transition Tree plugin: ~4,400 lines across a model, resolution engine, Qt editor, and obs-websocket vendor.
How it applies transitions
Same mechanism Exeldro's Transition Table uses, because it's the only one OBS supports: the plugin never performs a transition itself. Before each switch it writes OBS's own per-scene override (
transition/transition_durationprivate settings) onto every scene that could be the next destination, and OBS'sGetOverrideTransition()picks it up. Overrides are recomputed ontransition_start,channel_changeandSCENE_CHANGED, for every canvas.One improvement over the reference: the plugin tracks which scenes it wrote to, and only clears those. A transition override you set in OBS yourself survives unless a mark actually targets that scene.
What's implemented
Presets — each is local (scene collection blob) or global (
global-presets.jsonin the plugin config dir), switchable per preset. Every scene collection remembers its own active preset. Global presets whose scenes are missing from the current collection are kept, shown in red, and skipped at runtime.Multiple transitions per mark — sequential, random, random-no-immediate-repeat, and weighted, with per-candidate duration and weight.
The selection timing is the subtle part: picks are armed on arrival at a scene and held until departure, so each switch consumes exactly one random roll rather than re-rolling on every incidental signal. Sequential positions advance only for the mark that actually fired, detected by comparing the program scene against the armed pick.
Scene matching — explicit scene lists (multi-scene),
Any, andAny except …on both sides. Resolution is most-specific-first, from-side dominant (A → not-CbeatsAny → D, loses toA → D), ties going to the first-listed mark.Editor — a tree grouped by from-scene with a detail panel. This is the fix for the reported Transition Table UX problem: there,
fromCombo/toComboare simultaneously the add-row inputs and the table filter, so picking a scene to add a mark hides every unrelated row. Here the search box only filters the view and "Add Mark" is a separate button, so narrowing the list can never hide the controls needed to create one.Hotkeys — per-preset activation (registered dynamically, bindings survive renames by matching on hotkey id), next/previous preset, and a global enable/disable pair.
obs-websocket — vendor
transition-treewith preset and mark control plus apreset_changedevent, and Transition Table'sget_transition/set_transition/get_tableunder the same names for script compatibility. Requests are marshalled onto the Qt main thread so they stay race-free while still answering synchronously.Import/export — versioned JSON, accepting our format, a bare preset, and Transition Table exports. If a scene collection has Transition Table data and no Transition Tree data, the plugin offers once to migrate it.
Creating transitions — OBS exposes no API for adding a transition to its list (
obs_frontend_get_transitionsonly reads it; OBS resolves names against the main window'stransitionscombo, and only what's in that combo persists). The "New Transition…" button therefore drives OBS's owntransitionAddbutton, so the transition is initialised, named and saved exactly as if added from the transitions dock. Injecting a private source into the combo directly was rejected — it skips OBS's privateInitTransition(), which wires thetransition_stopsignals that re-enable the transition widgets.Verification
-Wall -Wextra) against the real OBS 31.1.1 headers and Qt6, including the generated moc output.CMakeLists.txtconfigures correctly (fails only atfind_package(libobs), expected without OBS installed).Not verified: runtime behaviour. There's no OBS instance here, so this proves it compiles, not that transitions fire correctly. Worth a local smoke test of a scene switch, a preset hotkey, and the sequential/weighted picking before merging.
Notes
transition-tree/ Voidscape Development / https://voidscape.dev /dev.voidscape.transition-tree, version 0.1.0. GPL-2.0, crediting Transition Table as prior art.🤖 Generated with Claude Code
https://claude.ai/code/session_01MBcrZqvWJy32tBVg5i9VD9
Generated by Claude Code