Mushbox 360 Cam · Deck Guide · matches script v4.5

Streamer.bot Decks & Actions Setup

Companion to the 360 Cam setup guide. That page gets the camera working from chat — this page wires the same moves to Stream Deck buttons (and any other trigger) using wrapper actions, without duplicating a single line of code.

Part 1 How it fits together

Everything runs through one action: Cam360 Control. It holds the v4.5 C# script, the OBS WebSocket plumbing, the chat command triggers, and the blocking camera queue. You never copy that script anywhere else.

Deck buttons don't talk to the engine directly. Each button fires a tiny wrapper action whose only job is to hand the engine a note — an argument named camAction — and ring its doorbell. The engine reads the note and performs the move.

STREAM DECK SPIN Wrapper: Cam Spin Set Argument → Run Action Wrapper: Cam Left camAction = left Wrapper: Barrel Roll camAction = barrelroll Cam360 Control v4.5 script · triggers blocking “camera” queue → OBS shader (yaw · pitch · fov · roll)

Chat commands (!cam, !spin, !zoom, !barrelroll, !corkscrew) skip the wrappers and hit the engine directly — both paths merge in the same queue, so a deck press landing mid-!spin simply waits its turn.

Rule of thumb: triggers and code live on the core; decks, raids, subs, and redemptions point at wrappers. Never attach a Raid/Sub/deck trigger to Cam360 Control itself — the engine treats "no instructions" as spin, so everything would spin.

Part 2 Before you start

If any of these fail, fix them on the main guide first — the deck layer sits entirely on top of a working engine.

Part 3 Build your first wrapper

We'll build Cam Spin. Every other wrapper is this exact recipe with a different name and a different camAction value.

  1. Create the action. In Streamer.bot's Actions tab, right-click → Add Action. Name it Cam Spin. Optional but tidy: put all wrappers in a group called Cam Deck. Leave the wrapper's queue blank — the queueing happens on the core.
  2. Add the note. Right-click its Sub-Actions pane → Core → Arguments → Set Argument.
    Variable Name: camAction  ·  Value: spin
  3. Ring the doorbell. Right-click Sub-Actions again → Core → Actions → Run Action → select Cam360 Control.
    Leave "Run Immediately" UNCHECKED. This is the whole trick — unchecked means the engine runs on its own camera queue, so button mashing queues moves politely instead of fighting over the yaw. Checked would run it inline and bypass the queue.
  4. Test it. Right-click the wrapper → Test Trigger. The camera should do a full spin. If it does, you've built your last hard one — the rest take about five seconds each.
The #1 mistake: checking "Run Immediately." Everything still works in isolation, but two quick presses will fight each other mid-animation. If your camera ever stutters or snaps when buttons stack, check this box first — it should be unchecked on every wrapper.

Part 4 The full wrapper set

Make one wrapper per move you want on the deck. Same recipe every time; only the name and the camAction value change. Two-word values go in as a single string — e.g. Value: tilt 45, roll 15, or planet out.

Wrapper namecamAction valueWhat the engine does
Cam FrontfrontPan to front heading, re-level pitch + roll
Cam BackbackPan to rear, re-level pitch + roll
Cam LeftleftPan left, re-level pitch + roll
Cam RightrightPan right, re-level pitch + roll
Cam SpinspinFull 360° yaw spin — holds pitch and zoom
Cam UpupPitch preset: look up
Cam DowndownPitch preset: look down
Cam LevellevelFully level: zero pitch and roll
Cam Tilt 45tilt 45Pitch to an exact angle (−90…90)
Cam Dutchroll 15Dutch angle at an exact roll (−180…180)
Barrel RollbarrelrollFull 360° roll, ends where it started
CorkscrewcorkscrewFlip + roll (+ spin) tumble, lands level (forces normal view)
Cam Heading 9090Bare number = yaw to that heading
Zoom InzoominStep FOV tighter by one zoom step
Zoom OutzoomoutStep FOV wider by one zoom step
Zoom Punchzoom 60Jump to an exact FOV (lower = tighter)
Zoom ResetzoomresetReturn to DefaultFov (115)
Tiny PlanetplanetToggle stereographic tiny-planet view on / off
Planet Onplanet onForce tiny planet on
Planet Offplanet offForce tiny planet off — back to the normal view
Planet Biggerplanet inGrow the planet (less sky)
Planet Smallerplanet outShrink the planet (more sky)
Planet 280planet 280Enter planet, set size directly (deck 160–320)
Planet Resetplanet resetPlanet size back to DefaultPlanetFov (250)

Deck wrappers get the trusted FOV range (30–150). Chat's !zoom is clamped tighter (60–120) inside the script — so your deck can punch in further than viewers can.

While tiny planet is active, the Zoom In / Zoom Out wrappers automatically resize the planet instead of changing FOV — the same reroute chat's !zoom gets. Any framing wrapper (front, left, a heading, etc.) snaps back out of planet mode; spin and barrelroll keep it on.

Free bonus: anything in Streamer.bot can fire a wrapper. Put a Twitch → Channel → Raid trigger on the Barrel Roll wrapper and raids roll the camera. Add Subscription / Resub / Gift Sub triggers to the same wrapper to stack more events on one move. Channel point redemptions and hotkeys work the same way — the triggers always go on the wrapper, never the core.

Part 5 Put them on the deck

  1. In Streamer.bot, open the Decks tab and create a deck (e.g. 360 Cam). Set rows/columns to fit your hardware or use it on-screen from the Streamer.bot mobile/web deck.
  2. Add a button → set its action to a wrapper (Cam Left, Cam Spin, …). One button per wrapper. Label and color it however you like.
  3. Using the official Elgato Stream Deck instead? Install the Streamer.bot Stream Deck plugin, then drag its "Do Action" tile onto a key and pick the wrapper from the dropdown. Same wrappers, same queue, same behavior.

A layout that's worked well — directions across the top, motion moves in the middle, zoom on the bottom row:

Part 6 Test checklist

Part 7 Troubleshooting

Button does nothing

Test the wrapper directly (right-click → Test Trigger). If that works, the deck button is pointed at the wrong action. If it doesn't, open the wrapper and check the two sub-actions: Set Argument spelling must be exactly camAction (capital A, no spaces), and Run Action must point at Cam360 Control.

Moves fight each other / camera snaps mid-animation

"Run Immediately" is checked on one of your wrappers. Uncheck it everywhere so every move rides the blocking camera queue. Also confirm the queue on Cam360 Control is set to camera and that queue is non-concurrent.

Deck press spins instead of doing its move

The engine got "empty hands" — no camAction arrived. Usually the Set Argument name is misspelled, or the trigger was attached to Cam360 Control instead of the wrapper. The engine's rule is: no instructions = spin (that's how the follower spin works).

Zoom won't return to your DefaultFov

Streamer.bot's stored globals (like cam360_fov) persist across recompiles and override script constants. Fire Zoom Reset (or chat !zoom reset), or restart Streamer.bot to clear stored globals.

Script won't compile after pasting

CS1519/CS0103 errors usually mean truncated or dirty paste. Use the Copy button on the main guide or a downloaded file — selecting code out of a chat window can carry invisible characters. The file should end with the Escape method and a closing brace.