Features:
- Vibrator speed control
- Stroker/penetration toy metronome (with visualisation)
- Stroker/penetration toy funscript playback (with visualisation)
- A userscript manager such as Violentmonkey or Tampermonkey (newer versions of Greasemonkey will not work!)
- A remote control toy which is compatible with buttplug.io, see https://iostindex.com/?filter0ButtplugSupport=4 for a complete list
To get started, play the demo tease: https://milovana.com/webteases/showteas ... 9d045089a9
EOS Users
The following configurations have been tested:
- Firefox - Windows 10 - Violentmonkey
- Google Chrome - Windows 10 - Violentmonkey
EOS Creators
ButtEOS does not require any modifications to the EOS editor, any tease can be made compatible by displaying the requisite notifications.
Vibrator module
Create a notification displaying "Vibrator: " followed by a number between 0 and 100, the vibrator will remain at that level as long as the notification is visible.
Metronome module
Create a notification displaying "BPM: " followed by a number indicating the desired BPM, a bar indicating the movement of the toy will be displayed on the left hand side.
Funscript module
Funscript must first be loaded using a "Say" command. The first line of the command must contain the text "Load pattern: " followed by the pattern name (used to play it back later). The second line is a description of the pattern which will appear below the visualisation bar when the pattern is active. The third and any subsequent lines should contain the raw JSON text of the funscript file. Patterns may be loaded at the start or at any time during the tease. Pattern names must be unique throughout the entire tease, it is not possible to redefine a pattern at a later time. The "Say" command can be instant but the text must be visible on screen or in the scrollback log for ButtEOS to load the pattern. Wait atleast 0.5 seconds before switching to a different page to ensure that the script has time to load your patterns.
To play a previously loaded pattern, create a notification displaying "Pattern: " followed by the pattern name, a bar indicating the movement of the toy will be displayed on the left hand side. Patterns will repeat for as long as the notification is visible.
Example tease JSON
Code: Select all
{
"pages": {
"start": [
{
"say": {
"label": "<p>This is a demo tease for ButtEOS,</p><p>a userscript which allows you to integrate EOS teases</p><p>with the buttplug.io library for controlling sex toys</p>"
}
},
{
"say": {
"label": "<p>You will need to have a userscript manager installed</p><p>such as Violentmonkey or Tampermonkey.</p><p>Newer versions of Greasemonkey will not work.</p>"
}
},
{
"say": {
"label": "<p>In Violentmonkey, select "Find scripts for this site"</p><p>Or navigate to "greasyfork.org/en/scripts/by-site/milovana.com"</p><p>Select the ButtEOS script and press "Install this script"</p><p>Then reload the page</p>"
}
},
{
"say": {
"label": "<p>The buttplug.io logo should appear in the lower</p><p>right corner, this indicates that the script is running.</p>"
}
},
{
"goto": {
"target": "setup"
}
}
],
"setup": [
{
"image": {
"locator": "file:caught-in-the-moment-001.jpg"
}
},
{
"say": {
"label": "<p>Let's get started, shall we</p>"
}
},
{
"say": {
"label": "<p>You will need a toy which is supported by buttplug.io</p>"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-002.jpg"
}
},
{
"say": {
"label": "<p>A vibrator, stroker or penetrating toy will work</p>"
}
},
{
"say": {
"label": "<p>First, let's make sure your toy is connected</p>"
}
},
{
"say": {
"label": "<p>Click on the buttplug.io icon in the lower right-hand corner,</p><p>you won't be able to interact with the tease while the buttplug.io window</p><p>is open, so go ahead and close it by pressing the "V" button or</p><p>clicking anywhere outside the buttplug.io window</p>",
"mode": "pause"
}
},
{
"say": {
"label": "<p>You can open and close this window at any time to </p><p>change or confirm your settings</p>"
}
},
{
"say": {
"label": "<p>If you have Intiface running on your computer, select the</p><p>"Connect to Intiface Desktop" option,</p><p>otherwise pick the "Connect in Browser" option.</p><p>Connecting directly from the browser is only supported on Google Chrome</p>",
"mode": "pause"
}
},
{
"say": {
"label": "<p>Now that you are connected to buttplug.io, you will have the</p><p> option to start scanning for devices. Make sure your device</p><p>is turned on and discoverable, then press the "Start Scanning" button</p>",
"mode": "pause"
}
},
{
"say": {
"label": "<p>Your device should appear in the list of Devices,</p><p>click on the checkbox next to the name of your</p><p>device to connect it to ButtEOS</p>",
"mode": "pause"
}
},
{
"goto": {
"target": "select"
}
}
],
"vibrator": [
{
"image": {
"locator": "file:caught-in-the-moment-023.jpg"
}
},
{
"say": {
"label": "<p>You have selected "vibrator"</p>"
}
},
{
"say": {
"label": "<p>I'll get that set up for you straight away</p>"
}
},
{
"say": {
"label": "<p>Whenever you're ready, click to begin the test</p>",
"mode": "pause"
}
},
{
"notification.create": {
"title": "Vibrator: 20%",
"id": "vib20"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-027.jpg"
}
},
{
"say": {
"label": "<p>Your device should now be on, we'll start at a low intensity</p><p>and work our way up</p>"
}
},
{
"notification.remove": {
"id": "vib20"
}
},
{
"notification.create": {
"title": "Vibrator: 50%",
"id": "vib50"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-026.jpg"
}
},
{
"say": {
"label": "<p>Your device is now at half intensity, let's turn it up some more!</p>"
}
},
{
"notification.remove": {
"id": "vib50"
}
},
{
"notification.create": {
"title": "Vibrator: 100%",
"id": "vib100"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-029.jpg"
}
},
{
"say": {
"label": "<p>It's really going now, huh</p>"
}
},
{
"notification.remove": {
"id": "vib100"
}
},
{
"goto": {
"target": "end"
}
}
],
"select": [
{
"image": {
"locator": "file:caught-in-the-moment-007.jpg"
}
},
{
"say": {
"label": "<p>We are now ready to begin controlling your device.</p><p>Please select the option which most accurately describes your device:</p>"
}
},
{
"choice": {
"options": [
{
"label": "Vibrator",
"commands": [
{
"goto": {
"target": "vibrator"
}
}
]
},
{
"label": "Stroker/Penetration",
"commands": [
{
"goto": {
"target": "pattern"
}
}
]
}
]
}
}
],
"pattern": [
{
"image": {
"locator": "file:caught-in-the-moment-058.jpg"
}
},
{
"say": {
"label": "<p>This is the "stroker/penetration" module</p>"
}
},
{
"say": {
"label": "<p>Any toy which supports linear motion in buttplug.io</p><p>can be used with this module</p>"
}
},
{
"say": {
"label": "<p>We'll start with the metronome function</p>"
}
},
{
"say": {
"label": "<p>Whenever you're ready, click to begin the test</p>"
}
},
{
"notification.create": {
"title": "BPM: 30",
"id": "bpm30"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-059.jpg"
}
},
{
"say": {
"label": "<p>Your device should now be moving at a slow, comfortable pace</p>"
}
},
{
"notification.remove": {
"id": "bpm30"
}
},
{
"notification.create": {
"title": "BPM: 60",
"id": "bpm60"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-062.jpg"
}
},
{
"say": {
"label": "<p>Let's speed up a bit</p>"
}
},
{
"notification.remove": {
"id": "bpm60"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-060.jpg"
}
},
{
"say": {
"label": "<p>You get the idea, now let's try something a little more interesting</p>"
}
},
{
"say": {
"label": "<p>We'll need to do some additional setup for this part</p>"
}
},
{
"say": {
"label": "<p>Don't worry, I'll take care of it so just sit back and relax</p>"
}
},
{
"say": {
"label": "<p>Load pattern: Simple</p><p>This is a simple pattern</p><p>{"actions":[{"at":2000,"pos":100},{"at":2500,"pos":0}]}</p>",
"mode": "instant"
}
},
{
"say": {
"label": "<p>Load pattern: Complex</p><p>This is a complex pattern</p><p>{"actions":[{"at":310,"pos":30},{"at":543,"pos":0},{"at":777,"pos":20},{"at":977,"pos":40},{"at":1177,"pos":10},{"at":1410,"pos":60},{"at":1644,"pos":0},{"at":1858,"pos":80},{"at":2078,"pos":0},{"at":2302,"pos":100},{"at":2527,"pos":0},{"at":3145,"pos":100},{"at":3595,"pos":0},{"at":3823,"pos":40},{"at":4051,"pos":0},{"at":4308,"pos":40},{"at":4566,"pos":0},{"at":4807,"pos":50},{"at":5048,"pos":10},{"at":5281,"pos":60},{"at":5515,"pos":20},{"at":5749,"pos":70},{"at":5949,"pos":30},{"at":6182,"pos":80},{"at":6416,"pos":40},{"at":6633,"pos":90},{"at":6883,"pos":50},{"at":7100,"pos":100},{"at":7317,"pos":40},{"at":7550,"pos":100},{"at":7784,"pos":50}]}</p>",
"mode": "instant"
}
},
{
"say": {
"label": "<p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>",
"mode": "instant"
}
},
{
"say": {
"label": "<p>The left hand side of your screen should show a message</p><p>indicating that we've loaded 2 different patterns,</p><p>ready to play the first pattern?</p>"
}
},
{
"notification.create": {
"title": "Pattern: Simple",
"id": "simple"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-064.jpg"
}
},
{
"say": {
"label": "<p>A simple pattern should be playing for you now</p>"
}
},
{
"notification.remove": {
"id": "simple"
}
},
{
"notification.create": {
"title": "Pattern: Complex",
"id": "complex"
}
},
{
"image": {
"locator": "file:caught-in-the-moment-069.jpg"
}
},
{
"say": {
"label": "<p>Longer and more complex patterns are also possible, enjoy!</p>"
}
},
{
"notification.remove": {
"id": "complex"
}
},
{
"goto": {
"target": "end"
}
}
],
"end": [
{
"image": {
"locator": "file:caught-in-the-moment-003.jpg"
}
},
{
"say": {
"label": "<p>That's the end of our test</p>"
}
},
{
"say": {
"label": "<p>You may go back to the device selection screen if you'd</p><p>like to try a different device</p>"
}
},
{
"choice": {
"options": [
{
"label": "Test another device",
"commands": [
{
"goto": {
"target": "select"
}
}
]
},
{
"label": "End tease",
"commands": [
{
"end": {}
}
]
}
]
}
}
]
},
"files": {
"caught-in-the-moment-001.jpg": {
"id": 1747919,
"hash": "d3325997af2385384e46394892bcc8ee5fdc17b7",
"size": 5198167,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-002.jpg": {
"id": 1747920,
"hash": "9a6bb5ed9d9c0f0464f8d7dc33900c95de20f305",
"size": 5085468,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-007.jpg": {
"id": 1747922,
"hash": "2c53f605b9826c6c149e173875fe7d274aa277f0",
"size": 5430332,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-023.jpg": {
"id": 1747923,
"hash": "0970a4d775816e6136652173b6d8ee15822b411a",
"size": 6254226,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-026.jpg": {
"id": 1747925,
"hash": "16289df5212110bd2bcc4580526304e264847a7e",
"size": 5879315,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-027.jpg": {
"id": 1747926,
"hash": "163639f667ec2e497cea0dec574edacf7eedd926",
"size": 6399968,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-029.jpg": {
"id": 1747928,
"hash": "1303eecf1c07755bbe73e835c3e8b520fe2a8ead",
"size": 6157250,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-058.jpg": {
"id": 1747934,
"hash": "f41b77561c035ac1dd67029866d70af3c47330ee",
"size": 5908721,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-059.jpg": {
"id": 1747935,
"hash": "e0ce5dc422349d383949040ff81c045f2841d822",
"size": 5703920,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-060.jpg": {
"id": 1747936,
"hash": "9764a4d354ca7adea7763ae2eb46ba3ab6766869",
"size": 5597541,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-062.jpg": {
"id": 1747938,
"hash": "01e72a0d4b3fb1915eb576512743e1f2783a1972",
"size": 5560613,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-064.jpg": {
"id": 1747940,
"hash": "5537b338d78b143849b94775185fed613d08a252",
"size": 6012313,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-069.jpg": {
"id": 1747946,
"hash": "f3facaca72596bf6ff5bbe797a77d493a00ed59c",
"size": 6153941,
"type": "image/jpeg",
"width": 6720,
"height": 4480
},
"caught-in-the-moment-003.jpg": {
"id": 1749866,
"hash": "18f07f0fb0f1188cf10e7cfab638bbd3aa056104",
"size": 5595723,
"type": "image/jpeg",
"width": 6720,
"height": 4480
}
},
"modules": {
"notification": {}
},
"init": "",
"galleries": {},
"editor": {
"recentImages": []
}
}
The buttplug.io library makes all of this possible
UI elements shamelessly stolen from https://github.com/buttplugio/buttplug-tampermonkey
Inspired by EOS creators pushing the envelope to create ever more interactive webteases