A Python desktop app that sends random shock commands to your OpenShock shockers when your Mayu's* tail is grabbed and pulled.
Warning
This project is not currently PiShock compatible.
* Works with any avatar that has a PhysBone which can be grabbed and stretched — some extra setup on your avatar and in this program's config may be required.
Pre-built versions of the desktop app and the Unity prefab for in-game control are on the releases page.
- Python 3.x
- Python packages:
python-osc,requests
- An OpenShock API Token
- The Shocker IDs for the shockers you want to control
- OSC enabled (Options → OSC → Enabled)
- An avatar with a tail PhysBone that can be grabbed and stretched, exposing
_IsGrabbedand_Stretchparameters
With uv (handles the virtual environment for you):
uv run python tail_shocker.pyWith pip:
- Install dependencies:
pip install -r requirements.txt
- Run the app:
python tail_shocker.py
Tip
If using pip, a virtual environment (venv) is recommended when running from source.
Run build.bat in the project directory to compile a standalone executable.
The tests/ folder contains a unit test suite covering config loading/saving, the OpenShock API client, session/shock-log persistence, and the OSC bridge. It only uses the standard library, so no extra install is needed:
python -m unittest discover -v
# or, with uv:
uv run python -m unittest discover -v- Download the latest Mayu Tail Shocker prefab from the releases page.
- Make sure your project has VRCFury installed.
- Import the Mayu Tail Shocker Unity package.
- Drag the prefab onto your avatar's root in the hierarchy.
The prefab adds a submenu to the VRC radial menu (named "Mayu Tail Shocker" by default) with these options:
| Option | Description |
|---|---|
| Enable | Turns the application on or off. No shocks occur while disabled. |
| Vibrate Only | When enabled, the shocker vibrates instead of shocking. |
| Dynamic Mode | Sets shock intensity and duration automatically from the tail's grab state and stretch amount. |
| Max Intensity | Maximum shock intensity, 0–100%. |
| Max Duration | Maximum length of a single shock. Not used in Dynamic Mode. Range is 0–10s, where each 1% = 100ms (10% = 1s). OpenShock's minimum shock duration is 300ms, so 1–3% all trigger a 300ms shock. |
| Cooldown | Time after a shock before another can occur. Not used in Dynamic Mode. Same 1% = 100ms scale as Max Duration. |
AI was used to create some parts of this project; everything has been personally tested and edge cases have been addressed. Please don't contact me about this.


