<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>&#x2F;</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>OBS</tabi:current_section>
    </tabi:metadata><title>Ox's Blog - OBS</title>
        <subtitle>Where I write stuff in case you want to read it</subtitle>
    <link href="/tags/obs/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="/tags/obs/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-07-14T00:00:00+00:00</updated>
    <id>/tags/obs/atom.xml</id><entry xml:lang="en">
        <title>Sliding Puzzle OBS Streamer Bot Thing</title>
        <published>2026-07-14T00:00:00+00:00</published>
        <updated>2026-07-14T00:00:00+00:00</updated>
        <author>
            <name>Ox</name>
        </author>
        <link rel="alternate" href="/blog/sliding-puzzle-obs-thing/" type="text/html"/>
        <id>/blog/sliding-puzzle-obs-thing/</id>
        
            <content type="html">&lt;h1 id=&quot;huh&quot;&gt;Huh?&lt;&#x2F;h1&gt;
&lt;p&gt;Sometimes a section of your stream interface is boring. Sometimes you need a way to raise your engagement. Sometimes you just allow the intrusive thoughts to take root and you want to make a bad idea barely work.&lt;&#x2F;p&gt;
&lt;p&gt;In all of these scenarios, the correct response is to implement The Sliding Puzzle OBS Streamer Bot Thing. Give your viewers a minigame to play made of whatever you’re trying to show them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;sliding-puzzle-obs-thing&#x2F;Example.mp4&quot;&gt;It technically works!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;All of this was created 9 months or so before the blog post was written, so the details are a bit hazy.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-solution&quot;&gt;The Solution&lt;&#x2F;h1&gt;
&lt;p&gt;The plan is to combine Streamer.bot’s ability to run code on a trigger to send events to OBS through the built in websocket connections using their C# functionality.&lt;&#x2F;p&gt;
&lt;p&gt;First, the Split function is run. This function finds the relevant source and grabs a bunch of metadata, like transforms and locations and offsets. After it gets this information, it clones the source 8 times and applies some math to each of those transforms to turn each of them into a chunk of 1&#x2F;9 of the source. During that creation, it sets a bunch of variables to keep track of where the empty space is, and which scene item is in each spot on the grid. Finally, it hides the original source because you probably don’t want to actually mess with the original.&lt;&#x2F;p&gt;
&lt;p&gt;The other part of the puzzle is the sliding actions. Each of these kind of do the same thing, but just manipulate the offsets in slightly different ways. First, check if the empty space is on an edge that would make the movement impossible (like sliding a piece up when the empty space is on the bottom row). Assuming the move is relevant, we fetch the scene item transforms for the piece that will be moving into the empty position, apply some math to the location, and push the new values to OBS then update the global variable state.&lt;&#x2F;p&gt;
&lt;p&gt;The global state should stay up to date through all of the moves as long as you don’t run split again, so you can just hide the child scene items and unhide the parent to get the input back to normal, and vice-versa to re-enable.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-technical-bits&quot;&gt;The Technical Bits&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;global-variables&quot;&gt;Global Variables&lt;&#x2F;h2&gt;
&lt;p&gt;First, you need to figure out the sceneItemId for the thing that you want to turn into a sliding puzzle. The easy way to do this is to hook into OBS through the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;obs-raw.streamer.bot&#x2F;#GetSceneItemList&quot;&gt;OBS Raw Streamer Bot page&lt;&#x2F;a&gt; which takes in a scene name and returns all of the items. You can figure out the name of the relevant one by checking the sourceName values.&lt;&#x2F;p&gt;
&lt;p&gt;Grab that and head over to the global variables section and add all of these settings.&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt; Global variables &lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_currentX = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_currentY = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix00 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix01 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix02 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix10 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix11 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix12 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix20 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix21 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_matrix22 = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_SceneName = [Your Scene Name]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_SourceSceneItemId = [the sceneItemId we got earlier]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_xCropDelta = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;slider_yCropDelta = -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;h2 id=&quot;splits&quot;&gt;Splits&lt;&#x2F;h2&gt;
&lt;p&gt;Create an action to do the Split with this code implemented as a sub-action.&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt; slider_SplitSubAction.cs &lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using System;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using Newtonsoft.Json.Linq;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;public class CPHInline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public bool Execute()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneName = CPH.GetGlobalVar&amp;lt;string&amp;gt;(&amp;quot;slider_SceneName&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneItemId = CPH.GetGlobalVar&amp;lt;string&amp;gt;(&amp;quot;slider_SourceSceneItemId&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Duplicate, set global vars&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for (int i = 0; i &amp;lt; 8; i++)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            var responseStr = CPH.ObsSendRaw(&amp;quot;DuplicateSceneItem&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId},\&amp;quot;destinationSceneName\&amp;quot;:null}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CPH.LogDebug(responseStr.ToString());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            JObject resp = JObject.Parse(responseStr);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            var itemId = (int)resp[&amp;quot;sceneItemId&amp;quot;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            var matrixId = $&amp;quot;{(int)i &#x2F; 3}{i % 3}&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CPH.LogDebug($&amp;quot;Item Id: {itemId}, Matrix Id: {matrixId}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CPH.SetGlobalVar($&amp;quot;slider_matrix{matrixId}&amp;quot;, itemId, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Get some offsets&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var itemTransformResp = CPH.ObsSendRaw(&amp;quot;GetSceneItemTransform&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId}}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        JObject originalTransform = JObject.Parse(itemTransformResp);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var xOrigin = (int)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var yOrigin = (int)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var xCropDelta = (int)((int)(originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;sourceWidth&amp;quot;]) &#x2F; 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var yCropDelta = (int)((int)(originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;sourceHeight&amp;quot;]) &#x2F; 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug($&amp;quot;{xOrigin} - {yOrigin} - {xCropDelta} - {yCropDelta}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Clean up each one&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for (int i = 0; i &amp;lt; 8; i++)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            var matrixId = $&amp;quot;{(int)i &#x2F; 3}{i % 3}&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            var tmpSceneItemId = CPH.GetGlobalVar&amp;lt;int&amp;gt;($&amp;quot;slider_matrix{matrixId}&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F;Let&amp;#39;s get weird with JObject copying&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            var newFancyTransform = JObject.FromObject(originalTransform).DeepClone().ToObject&amp;lt;JObject&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F;Okay they send back 0 but require a minimum value of 1 even though you send back NO_BOUNDS ??? That took a hot minute to figure out&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsWidth&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsHeight&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform.Add(&amp;quot;sceneName&amp;quot;, sceneName);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemId&amp;quot;] = tmpSceneItemId;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropLeft&amp;quot;] = (int)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropLeft&amp;quot;] + (((int)i &#x2F; 3) * xCropDelta);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropRight&amp;quot;] = (int)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropRight&amp;quot;] + ((2 - ((int)i &#x2F; 3)) * xCropDelta);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropTop&amp;quot;] = (int)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropTop&amp;quot;] + ((i % 3) * yCropDelta);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropBottom&amp;quot;] = (int)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;cropBottom&amp;quot;] + ((2 - (i % 3)) * yCropDelta);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;] = (int)((int)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;] + (((int)i &#x2F; 3) * xCropDelta) * (double)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;scaleX&amp;quot;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;] = (int)((int)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;] + ((i % 3) * yCropDelta) * (double)newFancyTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;scaleY&amp;quot;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            string tmpJson = newFancyTransform.ToString();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CPH.ObsSendRaw(&amp;quot;SetSceneItemTransform&amp;quot;, tmpJson, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Make the original invisible&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.ObsSendRaw(&amp;quot;SetSceneItemEnabled&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId},\&amp;quot;sceneItemEnabled\&amp;quot;:false}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_currentX&amp;quot;, 2, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_currentY&amp;quot;, 2, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_xCropDelta&amp;quot;, xCropDelta, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_yCropDelta&amp;quot;, yCropDelta, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;h2 id=&quot;slides&quot;&gt;Slides&lt;&#x2F;h2&gt;
&lt;p&gt;Finally, create actions for the slides with the following sub-actions&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt; slider_DownSubAction.cs &lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using System;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using Newtonsoft.Json.Linq;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;public class CPHInline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public bool Execute()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneName = CPH.GetGlobalVar&amp;lt;string&amp;gt;(&amp;quot;slider_SceneName&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentX = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentX&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentY = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentY&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var xCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_xCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var yCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_yCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if (currentY == 0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneItemId = CPH.GetGlobalVar&amp;lt;int&amp;gt;($&amp;quot;slider_matrix{currentX}{currentY - 1}&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug($&amp;quot;{sceneName} - {currentX} - {currentY} - {xCropDelta} - {yCropDelta} - {sceneItemId}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var itemTransformResp = CPH.ObsSendRaw(&amp;quot;GetSceneItemTransform&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId}}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        JObject originalTransform = JObject.Parse(itemTransformResp);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;] = (int)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;] + (yCropDelta * (double)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;scaleY&amp;quot;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsWidth&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsHeight&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneName&amp;quot;, sceneName);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneItemId&amp;quot;, sceneItemId);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var tmpJson = originalTransform.ToString();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug(tmpJson);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.ObsSendRaw(&amp;quot;SetSceneItemTransform&amp;quot;, tmpJson, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&#x2F;&#x2F;Write new state in global vars&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.SetGlobalVar(&amp;quot;slider_currentY&amp;quot;, currentY - 1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX}{currentY - 1}&amp;quot;, -1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX}{currentY}&amp;quot;, sceneItemId, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt; slider_UpSubAction.cs &lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using System;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using Newtonsoft.Json.Linq;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;public class CPHInline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public bool Execute()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneName = CPH.GetGlobalVar&amp;lt;string&amp;gt;(&amp;quot;slider_SceneName&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentX = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentX&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentY = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentY&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var xCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_xCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var yCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_yCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if (currentY == 2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneItemId = CPH.GetGlobalVar&amp;lt;int&amp;gt;($&amp;quot;slider_matrix{currentX}{currentY + 1}&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug($&amp;quot;{sceneName} - {currentX} - {currentY} - {xCropDelta} - {yCropDelta} - {sceneItemId}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var itemTransformResp = CPH.ObsSendRaw(&amp;quot;GetSceneItemTransform&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId}}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        JObject originalTransform = JObject.Parse(itemTransformResp);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;] = (int)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionY&amp;quot;] - (yCropDelta * (double)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;scaleY&amp;quot;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsWidth&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsHeight&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneName&amp;quot;, sceneName);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneItemId&amp;quot;, sceneItemId);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var tmpJson = originalTransform.ToString();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug(tmpJson);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.ObsSendRaw(&amp;quot;SetSceneItemTransform&amp;quot;, tmpJson, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&#x2F;&#x2F;Write new state in global vars&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.SetGlobalVar(&amp;quot;slider_currentY&amp;quot;, currentY + 1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX}{currentY + 1}&amp;quot;, -1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX}{currentY}&amp;quot;, sceneItemId, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt; slider_LeftSubAction.cs &lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using System;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using Newtonsoft.Json.Linq;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;public class CPHInline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public bool Execute()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneName = CPH.GetGlobalVar&amp;lt;string&amp;gt;(&amp;quot;slider_SceneName&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentX = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentX&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentY = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentY&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var xCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_xCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var yCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_yCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if (currentX == 2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneItemId = CPH.GetGlobalVar&amp;lt;int&amp;gt;($&amp;quot;slider_matrix{currentX + 1}{currentY}&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug($&amp;quot;{sceneName} - {currentX} - {currentY} - {xCropDelta} - {yCropDelta} - {sceneItemId}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var itemTransformResp = CPH.ObsSendRaw(&amp;quot;GetSceneItemTransform&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId}}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        JObject originalTransform = JObject.Parse(itemTransformResp);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;] = (int)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;] - (xCropDelta * (double)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;scaleX&amp;quot;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsWidth&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsHeight&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneName&amp;quot;, sceneName);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneItemId&amp;quot;, sceneItemId);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var tmpJson = originalTransform.ToString();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug(tmpJson);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.ObsSendRaw(&amp;quot;SetSceneItemTransform&amp;quot;, tmpJson, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&#x2F;&#x2F;Write new state in global vars&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.SetGlobalVar(&amp;quot;slider_currentX&amp;quot;, currentX + 1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX + 1}{currentY}&amp;quot;, -1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX}{currentY}&amp;quot;, sceneItemId, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt; slider_RightSubAction.cs &lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using System;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using Newtonsoft.Json.Linq;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;public class CPHInline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public bool Execute()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneName = CPH.GetGlobalVar&amp;lt;string&amp;gt;(&amp;quot;slider_SceneName&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentX = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentX&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var currentY = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_currentY&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var xCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_xCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var yCropDelta = CPH.GetGlobalVar&amp;lt;int&amp;gt;(&amp;quot;slider_yCropDelta&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if (currentX == 0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var sceneItemId = CPH.GetGlobalVar&amp;lt;int&amp;gt;($&amp;quot;slider_matrix{currentX - 1}{currentY}&amp;quot;, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug($&amp;quot;{sceneName} - {currentX} - {currentY} - {xCropDelta} - {yCropDelta} - {sceneItemId}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var itemTransformResp = CPH.ObsSendRaw(&amp;quot;GetSceneItemTransform&amp;quot;, $&amp;quot;{{\&amp;quot;sceneName\&amp;quot;:\&amp;quot;{sceneName}\&amp;quot;,\&amp;quot;sceneItemId\&amp;quot;:{sceneItemId}}}&amp;quot;, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        JObject originalTransform = JObject.Parse(itemTransformResp);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;] = (int)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;positionX&amp;quot;] + (xCropDelta * (double)originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;scaleX&amp;quot;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsWidth&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform[&amp;quot;sceneItemTransform&amp;quot;][&amp;quot;boundsHeight&amp;quot;] = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneName&amp;quot;, sceneName);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        originalTransform.Add(&amp;quot;sceneItemId&amp;quot;, sceneItemId);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        var tmpJson = originalTransform.ToString();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.LogDebug(tmpJson);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.ObsSendRaw(&amp;quot;SetSceneItemTransform&amp;quot;, tmpJson, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&#x2F;&#x2F;Write new state in global vars&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		CPH.SetGlobalVar(&amp;quot;slider_currentX&amp;quot;, currentX - 1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX - 1}{currentY}&amp;quot;, -1, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        CPH.SetGlobalVar($&amp;quot;slider_matrix{currentX}{currentY}&amp;quot;, sceneItemId, true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;h1 id=&quot;reasonably-asked-questions&quot;&gt;Reasonably Asked Questions&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h2&gt;
&lt;p&gt;I have never worked with OBS or Streamer.bot before and this seemed like a good crash course.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;will-this-break-if-i-resize-parts-of-it-or-the-parent&quot;&gt;Will this break if I resize parts of it, or the parent?&lt;&#x2F;h2&gt;
&lt;p&gt;Yeah, almost assuredly. If you want to do that then run split again and reset it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;are-global-variables-the-correct-place-to-hold-this-information&quot;&gt;Are global variables the correct place to hold this information?&lt;&#x2F;h2&gt;
&lt;p&gt;User persistent storage might work too? I am reasonably sure that it needs to be stateless so everything has to be written off somewhere.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;can-this-be-made-to-have-smooth-animations&quot;&gt;Can this be made to have smooth animations?&lt;&#x2F;h2&gt;
&lt;p&gt;Maybe! You can probably just update the location in the movement direction in a loop or something. If I try that then I can make a follow up post. Or you can do it and let me know.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;all-of-the-movement-functions-are-essentially-the-same-but-with-additions-and-subtractions-moved-around-surely-that-can-be-condensed&quot;&gt;All of the movement functions are essentially the same but with additions and subtractions moved around, surely that can be condensed?&lt;&#x2F;h2&gt;
&lt;p&gt;If it can, let me know. The C# functionalty in Streamer.bot is pretty obtuse and I didn’t see a good way to make a reusable function to call from each slide method with parameters. I also did not look particularly hard.&lt;&#x2F;p&gt;
</content>
        <summary type="html">A way to allow you to turn any OBS source into a sliding puzzle controlled through Streamer Bot</summary>
        </entry>
</feed>
