Stash-TCode - USB

Modded from Spunkle’s original script: Stash-TCode

MAIN Download: tcode-usb-v5.3 ← Updated to version 5.3 with axis inversion

BETA-5.6: tcode-usb-v5.6 ← Updated with possible 5.6 Multi Axis Fix by buffering the tcodes sent and sending them as a single packet verses streaming them.

USE BETA VERSIONS AT YOUR OWN RISK

Stash-TCode-USB is a userscript that integrates TCode-compatible haptic devices with the Stash media server via USB Web Serial. This modified version includes USB connectivity fixes to enable direct serial communication with TCode devices like the OSR2, SR6, and other compatible hardware.

this is in Beta currently


:bullseye: Purpose

This script bridges the gap between your Stash media library and TCode-compatible haptic devices by:

  1. Connecting to TCode devices via USB using the Web Serial API

  2. Loading and parsing funscript files (both single-axis and multi-axis formats)

  3. Synchronizing device movements with video playback in real-time

  4. Managing up to 6 axes (L0, L1, L2, R0, R1, R2)

  5. Providing a user-friendly settings interface for device configuration


:gear: Technical Requirements

Browser Requirements

| Requirement | Details |

| Web Serial API Support | Chrome/Edge 89+, Opera 75+ |

| Secure Context | HTTPS OR localhost/127.0.0.1 OR chrome://flags insecure origins whitelist |

| UserScript Manager | Tampermonkey, Violentmonkey, or Greasemonkey |

Hardware Requirements

  • TCode-compatible device (OSR2, SR6, etc.)

  • USB connection to the device

  • Device must support TCode serial protocol at 115200 baud

Software Requirements

  • Stash media server running on port 9999

  • Stash Interactive Tools plugin (for multi-funscript support)

  • Funscript files (.funscript) associated with your media


:electric_plug: Key Features

1. USB Serial Connection

  • Direct connection via Web Serial API (no WebSocket server needed)

  • 115200 baud rate (TCode standard)

  • Automatic device detection and axis capability discovery

2. Multi-Axis Funscript Support

Supports both formats:

  • Legacy single-axis (.funscript)

  • Multi-axis format (funscript version 1, 1.1, and V2 with axes array containing multiple axis definitions)

3. Axis Management

| Axis | TCode Name | Common Usage |

|------|-----------|--------------|

| L0 | Stroke | Up/down linear motion |

| L1 | Sway | Left/right motion |

| L2 | Surge | Forward/backward motion |

| R0 | Twist | Rotation around vertical axis |

| R1 | Pitch | Tilt forward/backward |

| R2 | Roll | Tilt left/right |

4. Live Range Adjustment

  • Mouse wheel + modifier keys to adjust min/max ranges on the fly

  • Initial Key (Shift): Save current ranges as baseline

  • Min Key (Meta/Win): Adjust minimum range

  • Visual overlay shows current axis limits

5. Random Motion Generation

  • Generate procedural motion for axes without funscripts

  • Based on timing from another axis with offset variation

6. Settings Interface

Beautiful dark-themed modal with tabs:

  • Device: USB connection, sync offset adjustment

  • Keys: Customize keyboard shortcuts

  • Axes: Enable/disable axes, set ranges (0-9999), configure random motion

  • Advanced: Debug mode, notifications, settings hotkey


:clipboard: Setup Instructions

Step 1: Install UserScript Manager

Install Tampermonkey or Violentmonkey for your browser.

Step 2: Install The Script

  1. Copy the contents of Stash-TCode.js

  2. Create a new userscript in Tampermonkey/Violentmonkey

  3. Paste the code and save

Step 3: Enable Web Serial API

If using a custom domain (not localhost):

  1. Open chrome://flags

  2. Find “Insecure origins treated as secure”

  3. Add your Stash URL (e.g., http://example.lan:9999)

  4. Restart browser

Step 4: Connect Your Device

  1. Navigate to a scene in Stash (http://your-stash:9999/scenes/[ID])

  2. Press F2 (default settings key) to open settings

  3. Click :link: Connect Serial (USB)”

  4. Select your TCode device from the browser’s serial port picker

  5. The script will auto-detect available axes

Step 5: Verify Funscripts

Ensure your scene has associated .funscript files:

  • Single axis: SceneName.funscript

  • Multi-axis: SceneName.funscript (with axes array) OR separate files:

  • SceneName.sway.funscript (L1)

  • SceneName.surge.funscript (L2)

  • SceneName.twist.funscript (R0)

  • SceneName.pitch.funscript (R1)

  • SceneName.roll.funscript (R2)


:video_game: Usage

Keyboard Shortcuts (Default)

| Key | Action |

|-----|--------|

| F2 | Open settings menu |

| Shift + Scroll | Set initial range baseline |

| Win/Meta + Scroll | Adjust minimum range |

| Mouse wheel (while holding modifier) | Adjust max range |

| Middle click | Reset to saved range |

Video Playback

Once connected, the script automatically:

  1. Loads funscripts when you navigate to a scene

  2. Syncs device motion with video playback

  3. Updates device position every 10ms during playback

  4. Resets axis positions when seeking in video

Sync Adjustment

If your device motion is ahead/behind the video:

  1. Open settings (F2)

  2. Go to Device tab

  3. Adjust Sync slider (-250ms to +250ms)

  4. Positive values delay device, negative values advance it


:wrench: Configuration Options

Axis Settings

For each axis (L0-R2):

  • Enable/Disable: Toggle whether the axis is active

  • Range: Set min/max values (0-9999) to limit motion

  • Random: Generate motion based on another axis’s timing

Advanced Options

  • Debug Mode: Enable console logging for troubleshooting

  • Show Notifications: Display toast messages for script events

  • Settings Hotkey: Change the key to open settings


Known Issues:

  • multi axis scripts are still a titch funky trying to figure out why If someone understands Tcode better please feel free to modify it or tell me
16 Likes

My brother this could not have shown up at a more perfect time.

2 Likes

Lmao let me know how it works for you! it’s still in beta, and i’m working out kinks but its in a usable state

1 Like

If you make this funscript 2.0 spec compatible that would be crazy. But that might be difficult since stash itself isn’t.

1 Like

Oh? I didnt know there was a v2 If there is documentation ill take a look at it but im mostly piggybacking on Stash interactive tools to show what scripts are available if it shows up on there then I should be golden

1 Like
1 Like

Ohhhhh the single file funscript! yes that’s supported, I thought that was called 1.1 not 2, my bad! ill update the post.

the script automatically attempts to parse the single file and generates a local copy of each axis and then sends the commands to the connected device

2 Likes

Awesome! I’ll be testing this out sometime soon. I got a lot on my plate for the next few days so it may be a while.

2 Likes

This is amazing and seems like it could solve so many of the issues I run across with stash and multi-axis usage. I’ll for sure try it out and see if I can get it working with my setup.

Is there an invert function built in for specific axes like MFP? I use that to fix the direction of my roll and pitch.

I’m going to see if it’s possible to do the browser scripts via heresphere built in browser as well for stashVR support.

1 Like

I think there should be no issues with MFP+Stash given the new single file formats. If you have separate files per axis then MFP will also be able to load those using script libraries.
Only situation where MFP will not work if you have stash running on separate machine and MFP can’t access the scripts. That would require support for stash-interactive-tools in MFP which I guess I could add since stash does not seem to be keen on adding multi file funscript support any time soon.

1 Like

Yeah i’m able to get it working with stash serving single merged 1.1 or 2.0 funscripts to MFP, my issue is the latency takes around 20-30 seconds to initialize a scene when loading.

I was going to attempt to modify stash to serve instant directory locations to MFP so it can read via local script repository instead of stash integration but I hadn’t gotten around to it yet. This tool seemed as though it could solve my latency issues, which is what I was referring to.

here is an updated version with inverting added!

I just overwrote the original code in the file so you can use the original link

1 Like

Appreciate it! I’ll come back to provide feedback once I get it all set up.

1 Like

no prob! im currently working on trying to fix the multi axis side of things as they work but are ‘out of phase?’ not sure but they do work

if you try out multi axis let me know how it works on your device as I am wondering if it’s just my firmware or something

1 Like

This is great, dude. One question: If we enable random movement on an axis, does that override the script? If a script has the twist axis programmed and we click the option for random movement, which has precedence? What if the script only has movement on that axis for part of the script? Does it fill the rest w/ random movement?

The random motion function creates random motion by copying the selected existing axis’s timing and adding a random time offset [about 250-1750ms]. It doesn’t create truly random patterns it just mirrors another axis’s movement at slightly different times. so if you have a script on stroke then pick random on Twist [and pick stroke as the source] it will randomly offset timings based on the script. The script will have precedence over random gen.

I am new to stash and want to get it working with my SR6, so please bear with me if I seem ignorant.

Why is the stash media server required to run on port 9999? Are you referring to the DLNA server port? Is DLNA required for this to work? Or is this in reference to the “9999” I see after “localhost” in the stash webapp URL?

With regards to browser support, I assume Firefox will not work? I have not been able to connect to my SR6 via Firefox with other websites (Like Ayva Stroker Lite for instance). Tampermonkey says it supports Firefox, but I assume the issue is more specific to connecting to USB devices?

so if your running the server, it usually starts on 9999 unless you change it

its not you can run it on any port in the settings, dlna is not required.

If firefox supports Tampermonkey or any of the other ones like it then the script should work altho I am not sure if firefox supports device connections to com ports which is required

BETA-5.6: tcode-usb-v5.6 ← Updated with possible 5.6 Multi Axis Fix by buffering the tcodes sent and sending them as a single packet verses streaming them.

Im currently away from my home so no physical tests have been done on this version yet

1 Like

Nice work!

Thanks for taking the time to add that stuff. I use Firefox, so don’t really ever use WebSerial, so it kind of got kicked to the backburner on my priority list.

If you’re interested, you can submit it as a pull request back to the main version and we can have it support either in one code base.