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.
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.
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.
Cam360 Control itself — the engine treats "no instructions" as spin, so everything would spin.
Cam360 Control action exists with the v4.5 script compiled (no red errors in the code editor)camera — a blocking, non-concurrent queue (create it under Settings → Queues if it's missing)!cam left pans, !spin spinsIf any of these fail, fix them on the main guide first — the deck layer sits entirely on top of a working engine.
We'll build Cam Spin. Every other wrapper is this exact recipe with a different name and a different camAction value.
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.camAction · Value: spinCam360 Control.camera queue, so button mashing queues moves politely instead of fighting over the yaw. Checked would run it inline and bypass the queue.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 name | camAction value | What the engine does |
|---|---|---|
| Cam Front | front | Pan to front heading, re-level pitch + roll |
| Cam Back | back | Pan to rear, re-level pitch + roll |
| Cam Left | left | Pan left, re-level pitch + roll |
| Cam Right | right | Pan right, re-level pitch + roll |
| Cam Spin | spin | Full 360° yaw spin — holds pitch and zoom |
| Cam Up | up | Pitch preset: look up |
| Cam Down | down | Pitch preset: look down |
| Cam Level | level | Fully level: zero pitch and roll |
| Cam Tilt 45 | tilt 45 | Pitch to an exact angle (−90…90) |
| Cam Dutch | roll 15 | Dutch angle at an exact roll (−180…180) |
| Barrel Roll | barrelroll | Full 360° roll, ends where it started |
| Corkscrew | corkscrew | Flip + roll (+ spin) tumble, lands level (forces normal view) |
| Cam Heading 90 | 90 | Bare number = yaw to that heading |
| Zoom In | zoomin | Step FOV tighter by one zoom step |
| Zoom Out | zoomout | Step FOV wider by one zoom step |
| Zoom Punch | zoom 60 | Jump to an exact FOV (lower = tighter) |
| Zoom Reset | zoomreset | Return to DefaultFov (115) |
| Tiny Planet | planet | Toggle stereographic tiny-planet view on / off |
| Planet On | planet on | Force tiny planet on |
| Planet Off | planet off | Force tiny planet off — back to the normal view |
| Planet Bigger | planet in | Grow the planet (less sky) |
| Planet Smaller | planet out | Shrink the planet (more sky) |
| Planet 280 | planet 280 | Enter planet, set size directly (deck 160–320) |
| Planet Reset | planet reset | Planet 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.
360 Cam). Set rows/columns to fit your hardware or use it on-screen from the Streamer.bot mobile/web deck.Cam Left, Cam Spin, …). One button per wrapper. Label and color it however you like.A layout that's worked well — directions across the top, motion moves in the middle, zoom on the bottom row:
!spin in chat, then immediately press Barrel Roll — spin finishes, then the roll firesTest 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.
"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.
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).
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.
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.