# Buttplug > Spec and developer guide for Buttplug.io This file contains all documentation content in a single document following the llmstxt.org standard. ## Architecture ## Goals The goals of the Buttplug Protocol are fairly simple: - Relay information about device connections and disconnects from the Buttplug server to client applications. - Allow developers to know what features a device presents. - Allow developers to access those features in a uniform manner. This goals guide how new messages are added to the protocol, and established messages are changed between versions as developers give us feedback on their specific usages. ## Structures Buttplug define systems it is used in via a few different structures: - _Device_ - In Buttplug terms, a _Device_ is a set of _Features_. Each feature can have the following attributes: - _Outputs_: Device outputs like vibration, stroking, etc... - _Inputs_: Device inputs like buttons, pressure gauges, accelerometers/IMUs, etc... - There can be multiple outputs within the same feature, representing different ways to addressing the output context. For instance, a stroker may take commands that specify moving to a position over time, or moving to a position immediately (servoing). Both of these contexts would act on the same feature, so they are listed as different `OutputType`s on the same feature. - A device may not always directly represent a piece of hardware. For instance, a device may be simulated as part of a developer tool, or act as an intermediary for network access to a remote controller. This distinction matters at the server level, but is usually hidden from clients. - _Server_ - The portion of the system that handles direct device communication. The Buttplug Server handles connections from clients, as well as translating messages from the client into corresponding proprietary commands for devices. - Servers are by far the most complicated portion of a Buttplug system, and are not expected to be implemented by others unless those people really hate their free time and/or lives. Seriously, just use the Intiface - _Client_ - An application that integrates a Buttplug Client library or API. These applications (which can be games, music players, movie players, other development tools, etc) use a Buttplug Client library written in a matching programming language/environment to connect to the Buttplug _Server_ and allows developers to gather information about toys and control them in a way that *should* abstract them from the raw Buttplug Protocol that is presented in this document. - Clients will need to be implemented for various programming languages and environments like game engines. A list of those currently available can be found as part of the [Buttplug Awesome List](https://github.com/buttplugio/awesome-buttplug?tab=readme-ov-file#development-and-libraries). - If you are writing a Buttplug implementation library and expecting your user to create Buttplug Messages themselves, you are _most likely making life more difficult on your users_. If that is your goal, then that is fine, but otherwise more guidance on client creation is given in the [Buttplug Developer Guide](/docs/dev-guide/). Note that the use of _Client_ and _Server_ here does not explicitly denote network connection. These terms are used as a generic way to denote different communication endpoints. Clients and Servers may both be embedded in the same process, or may talk over methods such as network or some form of IPC. ## Protocol The Buttplug Protocol defines a message based protocol between a _Client_ and a _Server_. This document is the explanation of that protocol. Client are expected to request information from the server about devices that are connected, and to send information to those devices via the server. Servers will handle device enumeration, connection management to hardware, and failure recoveries (for instance, stopping all connected devices on client disconnect). Buttplug uses JSON for serialization in most situations, but this is not a hard rule. Any serialization standard could work depending on context. ## Session Lifetime Buttplug sessions between the _Client_ and _Server_ consist of 3 stages. While these stages need not be discrete, due to the way Buttplug will likely be used, they will usually end up being so. _Client_ implementations may hide or combine some of the stages depending on requirements. ### Identification During the identification stage, a _Client_ will establish connection with the _Server_, and send over identifying information. The _Server_ may trigger some sort of UI event at this point to ask if the user will allow the client to connect and interact. ### Enumeration After the _Client_/_Server_ connection is set up, device enumeration can begin. The _Client_ can ask the _Server_ for a list of currently connected devices. It can also request the server scan for devices on various busses or media (serial, usb, bluetooth, network, etc), and return a list of devices it has found. ### Consummation Once devices are found and selected, we can assume the user will begin interacting with connected devices via the _Client_. At this point, the _Client_ will mostly be sending and receiving device commands. There may also be more enumeration during usage, as devices can disconnect and will need to reconnect. ### Example lifecycle The following lifecycle covers the general message flow expected between a Buttplug _Client_ and a Buttplug _Server_. ```mermaid sequenceDiagram Participant Client Participant Server Note over Client,Server: Once a connection is established, perform the protocol handshake,which exchanges informationabout identification, versions,ping times, etc... Client->>+Server: RequestServerInfo Id=1 Server->>-Client: ServerInfo Id=1 Note over Client,Server: If the server has a non-zeroPingTimeout, the client must senda ping message to theserverbefore the specified timeout.A common strategy is to setthe client Ping time to 1/2 therequested server ping time. loop [PingTime/2] Client->>+Server: Ping ID=N++ Server->>-Client: Ok ID=N++ end Note over Client,Server: The client calls RequestDeviceListto get a list of already connecteddevices. Client->>+Server: RequestDeviceList Id=2 Server->>-Client: DeviceList Id=2 Note over Client,Server: To discover new devices, the clientinstructs the server to startscanning. Client->>+Server: StartScanning Id=3 Server->>-Client: Ok Id=3 Note over Client,Server: While the server is scanning, theserver will notify the client of newdevices. Server->>Client: DeviceList Id=0 Server->>Client: DeviceList Id=0 Note over Client,Server: Once devices have been discovered, the client instruct the server to stop scanning. Client->>+Server: StopScanning Id=4 Server->>-Client: Ok Id=4 Note over Client,Server: Devices may disconnect at any time.The server will notify the clientwhen this happens. Server->>Client: DeviceList Id=0 Note over Client,Server: The client may instruct devices toperform actions. Actions vary perdevice. Device capabilities arerelayed as part of DeviceList messages. Client->>+Server: OutputCmd Id=5 Server->>-Client: Ok Id=5 Note over Client,Server: The client may instruct the server tostop a device from whatever itmay be doing. Client->>+Server: StopCmd DeviceIndex=0 Id=6 Server->>-Client: Ok Id=6 Note over Client,Server: The client may instruct the server tostop all devices. This is considered good form for a client that isshutting down. Client->>+Server: StopCmd Id=7 Server->>-Client: Ok Id=7 ``` --- ## Spec Changelog ## Version 4 (2026-01-24) - Nomenclature change: Standard -> API - Gonna stop calling this a standard. it's not. There's nothing to standardize here. No one wants to work together in this field. This library is glue between a bunch of devices and manufacturers that either don't recognize or actively hate each other, and trying to pass ourselves off as some unifying piece between these entities has been a fine branding move, but ultimately futile in terms of actually setting anything usable in stone. - On top of that, Buttplug as a project is operating without a plan. There's no real direction, we're mostly pulling stuff out of our butt, seeing what works, then reorienting around that. Not a particularly good way to standardize anything. The rest of this changelog will bear out that fact in excrusiating detail. - Also, we're 8 years into this project now and not a single person has tried building a server themselves. Which is good, because doing so requires a level of mental instability that would make quality of life questionable for anyone who tried. The ecosystem exists on top of us, but it is not us. I don't think it's ever going to be, and that's fine. - From here on out, this will now just be referred to as the Buttplug Protocol Spec. - Change from Message Attributes to Device Features - In message specs v0-3, we'd enumerated devices in terms of the messages they could receive. This had multiple problems, including index collisions, difficult figuring out what a device actually does, and building coherent APIs to form messages. In v4, we switch to a Device Feature system, which presents devices as sets of 2 different types of features: Outputs and Inputs. This allows us to state what a device can do, and then define capabilities within each feature. This solves the issue with index collisions (as we now use feature indexes instead of just message enumeration array indexes), and makes it easier for developers using buttplug to create UI representing the capabilities of a connected device. - This change will be seen in the [DeviceList](device_information.md#devicelist) message, as well as in the new [OutputCmd](output.md#outputcmd)/[InputCmd](input.md#inputcmd) commands. - Define [OutputType](output.md#outputtype) and [InputType](input.md#inputtype) in message spec and require spec point updates to add new features - As part of the introduction of [ScalarCmd](deprecated.md#scalarcmd) in spec v3, we introduced an `ActuatorType` value, to let developers know what type of value they were setting, as well as `SensorType` for sensors. The values of `ActuatorType`/`SensorType` were never set in the message spec, only in the reference implementations of the Buttplug server. These values should be defined within the message spec to let Client writers know exactly what to expect, and how to handle types they may not know (i.e. a client built for message spec v4.1 receives an [OutputType](output.md#outputtype)/[InputType](input.md#inputtype) defined in v4.2 should not completely break, but should complain). - Remove ability to send multiple commands ("subcommands") in device command messages - In past versions of Buttplug, we allowed multiple commands to be sent within a command package. For instance, if a device had multiple vibrators, a single v3 [ScalarCmd](deprecated.md#scalarcmd) could contain commands for both of these devices. Creating a usable API to form these messages was damn near impossible, and just ended up in implementation complexity on the server side that was never really exposed to developers well. From v4 on, command packets take one command for one output, and the server can handle that as it will. - Add `FeatureIndex` to commands - As we now refer to features instead of message attribute array positions, we're updating the `Index` field of commands with corresponding commands (what would've been subcommands in [ScalarCmd](deprecated.md#scalarcmd)/[RotateCmd](deprecated.md#rotatecmd)/[LinearCmd](deprecated.md#linearcmd) in v3) to take `FeatureIndex` in v4's [OutputCmd](output.md#outputcmd)/[InputCmd](input.md#inputcmd) instead. - [DeviceList](device_information.md#devicelist) now contains range information about all fields of a feature - In v2/v3, we introduced the idea of `StepCount` to communicate actuator range. For instance, if a device had 20 speeds of vibration, it'd have `StepCount` of 20. Some actuators (like [Rotate](output.md#rotate) and [Temperature](output.md#temperature)) can now have negative values, so we now send a definition of the range with the name of the field it represents. Instead of `StepCount: 20`, we send `Value: [-20, 20]`. We have also extended to fields we didn't define limits on before, like the `Duration` portion of [HwPositionWithDuration](output.md#hwpositionwithduration) (aka [LinearCmd](deprecated.md#linearcmd)), as some devices have upper limits on how slowly they can move. - Remove [DeviceAdded](deprecated.md#deviceadded) and [DeviceRemoved](deprecated.md#deviceremoved) - We will now just send [DeviceList](device_information.md#devicelist) when a client connects (post handshake), and on any device connection changes. It will be up to the client to implement logic to handle additions/deletions from the device list, but this allows us to simplify protocol implementations. - Remove `Raw*Cmd` - [RawReadCmd](deprecated.md#rawreadcmd)/[RawWriteCmd](deprecated.md#rawwritecmd)/[RawSubscribeCmd](deprecated.md#rawsubscribecmd)/[RawUnsubscribeCmd](deprecated.md#rawunsubscribecmd) were introduced in the v2 spec to aid development, allowing developers to bypass the protocol system in Buttplug and directly write byte buffers to devices. This was a bad idea, as Buttplug is built to be a protocol translation system, and this routed around the main point of the library. It ended up being about 2000 extra lines of code around the library to support, with almost no use, and the possibility of users turning it on and exposing their devices to bricking. - Remove [ScalarCmd](deprecated.md#scalarcmd)/[RotateCmd](deprecated.md#rotatecmd)/[LinearCmd](deprecated.md#linearcmd), replace with [OutputCmd](output.md#outputcmd) and [OutputType](output.md#outputtype) variations - We have flipped the context of device command messages. Instead of stating intention by action, we now simply state that we are addressing the output of a device, and give more context with the message. This allows us to only update possible field values within a message versus having to add new messages any time we want to address a new context. - In ELI5 terms: If a new device comes out that moves or does something in a new way, we don't have to do a major revision to the message spec to add support. - Remove `Sensor*Cmd`, replace with [InputCmd](input.md#inputcmd) and [InputType](input.md#inputtype) variations - Due to index collision issues, `Sensor*Cmd` was never really directly supported or used in Buttplug outside of getting Battery values. These issues have now been fixed, and the same context flip as [OutputCmd](output.md#outputcmd) has been applied to provide us with [InputCmd](input.md#inputcmd). - Why are they named [OutputCmd](output.md#outputcmd) and [InputCmd](input.md#inputcmd) instead of following the nomenclature of v3 and using `ActuatorCmd` and `SensorCmd`? Because our domain is buttplug.io and now we have io commands. You can never say we do not commit to the bit fully on this project. - Change device commands to use integers instead of floats for control values - When Buttplug started we decided to use floats instead of integers for command values. This meant that clients had to calculate steps to a value between 0.0-1.0. However, this was also usually exposed to application developers in this way, meaning they had to consider the step difference amounts in order to make device actuators actually do something different (i.e. if a device had 5 steps, the application dev would have to know to round between values of x * 0.2). Moving to integers that are limited by the amount of available steps on a device makes life easier for everyone, as well as optimizing our line protocol as it's one less float to try to translate. - Rename `MessageVersion` to `ProtocolVersionMajor` and add `ProtocolVersionMinor` in [RequestServerInfo](identification.md#requestserverinfo)/[ServerInfo](identification.md#serverinfo) messages. - This allows us to add features to message versions without having to bump major versions every time. - Servers return `ProtocolVersionMajor` and `ProtocolVersionMinor` for connections on >= v4, just `MessageMajorVersion` for < v4 - Add [Disconnect](identification.md#disconnect) message for graceful client disconnection - Allows clients to explicitly signal intent to disconnect from the server, which triggers device cleanup and subscription removal. Useful for stateless transports (like UDP) where there is no inherent connection state, and for explicit shutdown rather than relying on ping timeout. - [StopAllDevices](deprecated.md#stopalldevices---spec-v0) and [StopDeviceCmd](deprecated.md#stopdevicecmd-version---spec-v0) now [StopCmd](stop.md#stopcmd) with optional fields. - Simplifies stopping to work at multiple levels, by taking optional device and features IDs. - [StopCmd](stop.md#stopcmd) no longer sent as a possible message on a device description - We now let developers assume all devices can take [StopCmd](stop.md#stopcmd), so there is no need to attach it to device descriptors. - [StopCmd](stop.md#stopcmd) will be valid for both actuators (i.e. make a vibrator stop vibrating) and sensors (i.e. cause an unsubscribe from a subscribed endpoint). It also has Inputs and Outputs modifiers for the client/device level. - Added [Position](output.md#position) and [HwPositionWithDuration](output.md#hwpositionwithduration) OutputTypes - These replace [LinearCmd](deprecated.md#linearcmd) functionality from previous spec versions. - [Position](output.md#position) commands a device to move to a position as quickly as possible (servoing). - [HwPositionWithDuration](output.md#hwpositionwithduration) commands a device to move to a position over a specified duration (the "Hw" prefix indicates this is handled by device hardware, not Buttplug). - Updated [Rotate](output.md#rotate) to support bidirectional control with signed values - Devices with bidirectional rotation advertise a _Value_ range that includes negative values, with positive values being clockwise and negative values being counterclockwise. - Devices with single-direction rotation continue to advertise a _Value_ range of `[0, x]`. - Added [Temperature](output.md#temperature), [Led](output.md#led-encoded-as-led), [Spray](output.md#spray) OutputTypes - [Temperature](output.md#temperature) refers to devices with cooling/heating units. This will be communicated as negative/positive values, similar to [Rotate](output.md#rotate). - [Led](output.md#led-encoded-as-led) is light levels for devices with controllable lights, most likely used just to turn them off. - [Spray](output.md#spray) is for lubrication injection. ## Version 3 Patch 3 (2022-12-30) - Message Definitions Fixed: - The `SensorType` and `SensorRange` message attributes are valid for SensorSubscribeCmd as well as SensorReadCmd. ## Version 3 Patch 2 (2022-12-27) - Message Definitions Fixed: - DeviceAdded/DeviceList use `DeviceMessageTimingGap`, not `DeviceMessageGap`. - LinearCmd/RotateCmd information in the message attributes of DeviceAdded/DeviceList will have an ActuatorType (Previously stated that only ScalarCmd has an actuator type). ## Version 3 Patch 1 (2022-10-14) - Message Descriptions Changed: - ServerInfo - The original idea behind ServerInfo's message spec version output was to notify clients if a new, higher version of the message spec might be available, prompting for upgrade. Unfortunately, a long running programming error in multiple official reference libraries will cause connections to fail if the server lists its maximum available spec version and that version is higher than the client's spec version. Therefore, ServerInfo cannot return a version that is higher than the client's spec verison. ServerInfo should return either a version that matches the clients, or throw an error if it cannot match the client's version. This does not change the structure of the message, just the expectations of how it should function. ## Version 3 (2022-08-29) - Messages Added: - ScalarCmd - Replaces VibrateCmd and adds ability to easily extend with new actuator types that take a single value. - SensorReadCmd - Replaces Battery/RSSI messages and adds ability to easily extend with new sensor types. - SensorSubscribeCmd - Allows users to receive realtime updates from devices (pressure sensors kegelcizers, accelerometers in toys that have them, etc...) - SensorUnsubscribeCmd - SensorReading - Data returned from either sensor being read, or a subscription event. - Messages Changed: - DeviceList/DeviceAdded - Remove _FeatureCount_, Message Attributes are now an array of attribute objects instead of many fields of arrays that had to be reconstructed. Should reduce bookkeeping. - Added Message Attributes _FeatureDescriptor_, _ActuatorType_, _SensorType_ - Added Device Attributes _DisplayName_, _DeviceMessageGap_ - For messages that have matching "undo" types, like RawSubscribe/RawUnsubscribe or SensorSubscribe/SensorUnsubscribe, only the initial command is relayed in the message attributes of _DeviceAdded_ or _DeviceList_. The arguments for these commands are the same, and it's assumed that if you can do something that has a matching undo, you'll only need to know about one. - Messages Deprecated: - VibrateCmd - Superceded by ScalarCmd. Will still be available via API calls in client APIs, just no longer needs to be a specific message in the protocol. - BatteryLevelCmd - Superceded by SensorReadCmd - RSSILevelCmd - Superceded by SensorReadCmd - BatteryLevelReading - Superceded by SensorReading - RSSILevelReading - Superceded by SensorReading ## Version 2 (2020-09-28) - Messages Added: - RawWriteCmd - RawReadCmd - RawReading - RawSubscribeCmd - RawUnsubscribeCmd - BatteryLevelCmd - BatteryLevelReading - RSSILevelCmd - RSSILevelReading - Messages Changed: - DeviceList/DeviceAdded - Adding StepCount to Message Attributes, to let users know how many steps a feature can use (i.e. how many vibration levels a piece of hardware might have) - ServerInfo - Remove Version fields - Messages Deprecated: - LovenseCmd - Superceded by VibrateCmd/RotateCmd/Raw\*Cmd. The protocol messages were originally meant to map generic -> protocol -> raw, but the protocols change quickly enough that it's not worth it to encode that at the protocol level. From v2 of the spec on, we will try to encode as many actions as possible in generic messages. For anything we haven't mapped yet, Raw\*Cmd can be used, though it's not a great idea due to security concerns. - LovenseCmd was never implemented in any of the Buttplug reference libraries, so removal shouldn't affect anything. - KiirooCmd - Superceded by VibrateCmd/LinearCmd/Raw*Cmd. See above for more explanation. - Only implemented by the Kiiroo Pearl 1 and Onyx 1 in Buttplug C#. Not sure it was ever used anywhere. - VorzeA10CycloneCmd - Superceded by RotateCmd/PatternCmd. See above for more explanation. - Implemented for the Vorze A10 Cyclone in C# and JS, but translates directly to rotation messages. - FleshlightLaunchFW12Cmd - Superceded by LinearCmd/Raw\*Cmd. See LovenseCmd reason for more explanation. - Implemented for the Fleshlight Launch, and will be problematic to switch out. We should still support it on the server side for v0/v1 for compat. - Test - Violates assumptions that client/server sends different message types. Also, not particularly useful. - RequestLog/Log - Allows too much information leakage across the protocol in situations we may not want, and also has nothing to do with sex toy control. Logging is an application level function, not really required in the protocol itself. ## Version 1 (2017-12-11) - Messages Added: - VibrateCmd - LinearCmd - RotateCmd - Messages Changed: - DeviceList/DeviceAdded - Added Message Attributes blocks to device info, with FeatureCount attribute - RequestServerInfo - Added Spec Version Field - Messages Deprecated: - SingleMotorVibrateCmd - Superceded by VibrateCmd ## Version 0 (2017-08-24) - First version of spec - Messages Added: - Ok - Error - Log - RequestLog - Ping - Test - RequestServerInfo - ServerInfo - RequestDeviceList - DeviceList - DeviceAdded - DeviceRemoved - StartScanning - StopScanning - ScanningFinished - SingleMotorVibrateCmd - FleshlightLaunchFW12Cmd - LovenseCmd - KiirooCmd - VorzeA10CycloneCmd - StopDeviceCmd - StopAllDevices --- ## Development History The following sections document intermediate design ideas that were explored during the development of V4. These versions never shipped but are preserved here to show how the spec evolved. They may be useful for understanding the rationale behind certain V4 decisions. ### Imaginary Version ~4 Beta 1 (2025-03-??) THEN IT HAPPENED AGAIN. - Rename `LinearCmd` and `RotateCmd` to `ValueWithParameterCmd` - Linear and Rotate were both messages that could be described in an "x with y" way, i.e. `RotationWithDirection`, `PositionWithDuration`, etc... This condensing and renaming of commands will hopefully make this idea easier to convey while giving us the extensibility of using ActuatorTypes (and therefore not having to add new messages whenever we want to update). - Renamed `Sensor*` fields to `Feature*` in `Sensor*Cmd` Messages - Aligns with new feature system - Add `EventCmd` _(Ed. Note: or maybe BangCmd, not sure yet)_ - We're seeing devices that require a one-off command to cause an event to happen. For instance, the Hismith lubrication injector, lube injectors for the SR-6/OSR-2, etc... We needed a command that denote that an event will happen, but will not be continuously happening, like StaticCmd. ### Imaginary Version ~4 Beta 0 (2024-09-??) This version never actually existed. I'm just leaving it here to show how things change if I let the project sit for months at a time. - Rename `LinearCmd` to `GoalWithDurationCmd` _(Ed. Note: This is still a maybe)_ - Much like the move to `ScalarCmd` in v3, `LinearCmd` is now being generalized to "movement toward a goal value with a duration". Added to the definition will be a curve type for the movement, though at the moment the only supported curve will be of "Linear" type (later versions may include different curves or the ability to define a curve function over time). For now, this means we can handle both stroker style movement as well as things like angular rotation in TCode v3, denoting the movement type via feature types. - Rename `ScalarCmd` to `StaticCmd` _(Ed. Note: I'm not sure about this name yet :| )_ - `ScalarCmd` is being renamed to `StaticCmd` to denote that sending the command is expected to set a value and leave it set until another `StaticCmd` or `StopDeviceCmd` call is sent. `ScalarCmd` didn't properly relay this meaning. - Remove `RotateCmd`, use `StaticCmd` - See note on last bullet for more info. - Remove `ActuatorType` from `StaticCmd` _(Ed Note: This is still a maybe)_ - This was initially added as a safety check on `ScalarCmd`, to make sure that the developer was actually triggering the type of actuator they meant to be. However, as clients usually (or at least should) hide this detail from end users, it's not useful to anyone but client developers. - Change `StaticCmd` to take signed double instead of unsigned double - The unsigned value given to v3 `ScalarCmd` made it difficult to define messages that might actually be 2d instead of 1d (i.e. embedding rotation direction with a -1 \<= x \<= 1 value, letting us remove `RotateCmd`). Change `StaticCmd` in v4 to take signed values, so we can condense methods. --- ## Deprecated Messages The following messages are considered deprecated, either because they've been duplicated by new messages, or because their message version has changed and they represent an old version of a message. While some older versions of messages are not required to be implemented unless a server wants to support version fallback, other messages, such as deprecated device commands, should most likely be implemented in all servers. Any reference servers provided by the Buttplug Core Team will support all messages, even those that have been deprecated. --- ## DeviceList - Spec V0 **Reason for Deprecation:** Superceded by [DeviceList Version 1](#devicelist---spec-v1), which provides more information about feature limits of generic messages. **Description:** Server reply to a client request for a device list. **Introduced In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _Devices_ (array): Array of device objects * _DeviceName_ (string): Descriptive name of the device * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * _DeviceMessages_ (array of strings): Type names of Device Messages that the device will accept. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestDeviceList Id=1 Server->>-Client: DeviceList Id=1 ``` **Serialization Example:** ```json [ { "DeviceList": { "Id": 1, "Devices": [ { "DeviceName": "TestDevice 1", "DeviceIndex": 0, "DeviceMessages": ["SingleMotorVibrateCmd", "RawCmd", "KiirooCmd", "StopDeviceCmd"] }, { "DeviceName": "TestDevice 2", "DeviceIndex": 1, "DeviceMessages": ["SingleMotorVibrateCmd", "LovenseCmd", "StopDeviceCmd"] } ] } } ] ``` --- ## DeviceAdded - Spec V0 **Reason for Deprecation:** Superceded by [DeviceList Version 1](device_information#devicelist), which provides more information about feature limits of generic messages. **Introduced In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceName_ (string): Descriptive name of the device * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * _DeviceMessages_ (array of strings): Type names of Device Messages that the device will accept. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram participant Client participant Server Server->>Client: DeviceAdded Id=0 ``` **Serialization Example:** ```json [ { "DeviceAdded": { "Id": 0, "DeviceName": "TestDevice 1", "DeviceIndex": 0, "DeviceMessages": ["SingleMotorVibrateCmd", "RawCmd", "KiirooCmd", "StopDeviceCmd"] } } ] ``` --- ## DeviceList - Spec V1 **Reason for Deprecation:** Superceded by [DeviceList Version 3](device_information.md#devicelist), which provides optional display name and message timing information, as well as simplifies the format of message attributes. **Description:** Server reply to a client request for a device list. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 1 (See [Deprecated Messages](#devicelist---spec-v0) for older versions.) **Fields:** * _Id_ (unsigned int): Message Id * _Devices_ (array): Array of device objects * _DeviceName_ (string): Descriptive name of the device * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * _DeviceMessages_ (dictionary): Accepted Device Messages * Keys (string): Type names of Device Messages that the device will accept * Values ([Message Attributes](#message-attributes-for-deviceaddeddevicelist---spec-v3)): Attributes for the Device Messages. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestDeviceList Id=1 Server->>-Client: DeviceList Id=1 ``` **Serialization Example:** ```json [ { "DeviceList": { "Id": 1, "Devices": [ { "DeviceName": "TestDevice 1", "DeviceIndex": 0, "DeviceMessages": { "VibrateCmd": { "FeatureCount": 2 }, "StopDeviceCmd": {} } }, { "DeviceName": "TestDevice 2", "DeviceIndex": 1, "DeviceMessages": { "LinearCmd": { "FeatureCount": 1 }, "StopDeviceCmd": {} } } ] } } ] ``` --- ## DeviceAdded - Spec V1 **Reason for Deprecation:** Superceded by [DeviceAdded Version 3](#deviceadded), which provides more information about feature limits of generic messages, as well as simplifies the format of message attributes. **Description:** Sent by the server whenever a device is added to the system. Can happen at any time after identification, as it is assumed many server implementations will support devices with hotplugging capabilities that do not require specific scanning/discovery sessions. **Introduced In Spec Version:** 0 **Last Updated In Spec Version**: 1 (See [Deprecated Messages](#deviceadded---spec-v0) for older versions.) **Fields:** * _Id_ (unsigned int): Message Id * _DeviceName_ (string): Descriptive name of the device * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * _DeviceMessages_ (dictionary): Accepted Device Messages * Keys (string): Type names of Device Messages that the device will accept * Values ([Message Attributes](#deviceadded)): Attributes for the Device Messages. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram participant Client participant Server Server->>Client: DeviceAdded Id=0 ``` **Serialization Example:** ```json [ { "DeviceAdded": { "Id": 0, "DeviceName": "TestDevice 1", "DeviceIndex": 0, "DeviceMessages": { "VibrateCmd": { "FeatureCount": 2 }, "StopDeviceCmd": {} } } } ] ``` --- ## Message Attributes - Spec V2 **Reason for Deprecation:** Superceded by Message Attributes Version 3, changing format to be one message attributes object per device feature, and adding sensor/actuator types, feature descriptors, etc... **Introduced In Spec Version:** 1 **Last Updated In Spec Version**: 2 **Description:** A collection of message attributes. This object is always the child of a Device Message type name within a [DeviceList](#devicelist---spec-v1) or [DeviceAdded](#deviceadded---spec-v1) message. Not all attributes are relevant for all Device Messages on all Devices; in these cases the attributes will not be included. **Attributes:** * _FeatureCount_ (unsigned int): Number of features the Device Message may address. This attribute is used to define the capabilities of generic device control messages. The meaning of "feature" is specific to the context of the message the attribute is attached to. For instance, the FeatureCount attribute of a VibrateCmd message will refer to the number of vibration motors that can be controlled on a device advertising the VibrateCmd message. * _StepCount_ (array of unsigned int, minimum value: 1): For each feature, lists the number of discrete steps the feature can use. Returning to the VibrateCmd example from the above _FeatureCount_ specification, if a device had 2 motors, and each motor has 20 steps of vibration speeds from 0%-100% (this is exactly what the Lovense Edge is), the _StepCount_ attribute would be [20, 20]. Having the array allows use to specify different amounts of steps for multiple vibrators on the device. --- ## Message Attributes - Spec V1 **Reason for Deprecation:** Superceded by Message Attributes Version 2, adding step count. **Introduced In Spec Version:** 0 **Last Updated In Spec Version**: 2 **Description:** A collection of message attributes. This object is always the child of a Device Message type name within a [DeviceList](#devicelist---spec-v1) or [DeviceAdded](#deviceadded---spec-v1) message. Not all attributes are relevant for all Device Messages on all Devices; in these cases the attributes will not be included. **Attributes:** * _FeatureCount_ (unsigned int): Number of features the Device Message may address. This attribute is used to define the capabilities of generic device control messages. The meaning of "feature" is specific to the context of the message the attribute is attached to. For instance, the FeatureCount attribute of a VibrateCmd message will refer to the number of vibration motors that can be controlled on a device advertising the VibrateCmd message. --- ## RequestServerInfo - Spec V0 **Reason for Deprecation:** Superceded by [RequestServerInfo Version 1](identification.md#requestserverinfo), adding message version check. **Description:** Sent by the client to register itself with the server, and request info from the server. **Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _ClientName_ (string): Name of the client, for the server to use for UI if needed. Cannot be null. **Expected Response:** * ServerInfo message on success * Error message on malformed message, null client name, or other error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RequestServerInfo Id=0 Server->>Client: ServerInfo Id=0 ``` **Serialization Example:** ```json [ { "RequestServerInfo": { "Id": 1, "ClientName": "Test Client" } } ] ``` --- ## ServerInfo - Spec V0 **Reason for Deprecation:** Superceded by [ServerInfo Version 1](identification.md#serverinfo), removing unused version info. **Description:** Send by server to client, contains information about the server name \(optional\), template version, and ping time expectations. **Introduced In Spec Version:** 0 **Fields:** * _Id_ \(unsigned int\): Message Id * _ServerName_ \(string\): Name of the server. Can be null \(0-length\). * _MajorVersion_ \(uint\): Major version of the server software. * _MinorVersion_ \(uint\): Minor version of the server software. * _BuildVersion_ \(uint\): Build version of the server software. * _MessageVersion_ \(uint\): Message template version of the server software. * _MaxPingTime_ \(uint\): Maximum internal for pings from the client, in milliseconds. If a client takes to longer than this time between sending Ping messages, the server is expected to disconnect. **Expected Response:** None. Server-To-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RequestServerInfo Id=0 Server->>Client: ServerInfo Id=0 ``` **Serialization Example:** ```json [ { "ServerInfo": { "Id": 1, "ServerName": "Test Server", "MajorVersion": 1, "MinorVersion": 0, "BuildVersion": 0, "MessageVersion": 1, "MaxPingTime": 100 } } ] ``` --- ## RawCmd **Reason for Deprecation:** Message is ill-defined (doesn't specify where the data should go, assumes all devices have one endpoint which is very not true), was never actually implemented in any reference implemenation. Being superceded by Raw\*Cmd. As the message was never in any protocol implementation, it can safely be ignored when implementing new servers, but should also not be used to name new messages. **Description:** Used to send a raw byte string to a device. Should only be used for development, and should not be exposed to untrusted clients. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Command_ (Array of bytes): Command to send, array of ints with a range of [0-255]. Minimum length is 1. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RawCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "RawCmd": { "Id": 1, "DeviceIndex": 0, "Command": [0, 2, 4] } } ] ``` --- ## SingleMotorVibrateCmd **Reason for Deprecation:** Superceded by [VibrateCmd](#vibratecmd), which provided granular control of an unlimited number of motors. Should most likely still be implemented in servers, in order to support older applications, but is not recommended for use in new client applications. **Description:** Causes a device that supports vibration to run all vibration motors at a certain speed. **Introduced In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Speed_ (double): Vibration speed with a range of [0.0-1.0] **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: SingleMotorVibrateCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "SingleMotorVibrateCmd": { "Id": 1, "DeviceIndex": 0, "Speed": 0.5 } } ] ``` --- ## KiirooCmd **Reason for Deprecation:** Only implemented in early versions of the C# library, did not cover nearly enough of the vast spectrum of possible commands for Kiiroo devices. Replaced by... pretty much everything generic. **Description:** Causes a device that supports Kiiroo style commands to run whatever event may be related. More information on Kiiroo commands can be found in STPIHKAL. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Command_ (string): Parsed into an unsigned integer in range [0-4] for position/speed. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: KiirooCmd Id=1 Server->>Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "KiirooCmd": { "Id": 1, "DeviceIndex": 0, "Command": "4" } } ] ``` --- ## FleshlightLaunchFW12Cmd **Reason for Deprecation:** Superceded by [LinearCmd](#linearcmd), which provided an easier way to reason about movement time and position. **Description:** Causes a device that supports Fleshlight Launch (Firmware Version 1.2) style commands to run whatever event may be related. More information on Fleshlight Launch commands can be found in STPIHKAL. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Position_ (unsigned int): Unsigned integer in range [0-99], denoting position to move to. * _Speed_ (unsigned int): Unsigned integer in range [0-99], denoting speed to requested position at. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: FleshlightLaunchFW12Cmd Id=1 Server->>Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "FleshlightLaunchFW12Cmd": { "Id": 1, "DeviceIndex": 0, "Position": 95, "Speed": 90 } } ] ``` --- ## LovenseCmd **Reason for Deprecation:** Never implemented in any reference version of the library. Superceded by a combination of [ScalarCmd](#scalarcmd), [RotateCmd](#rotatecmd), [BatteryCmd](#batterylevelcmd), and the [Raw*Cmd](#rawreadcmd) commands. **Description:** Causes a device that supports Lovense style commands to run whatever event may be related. More information on Lovense commands can be found in STPIHKAL. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Command_ (string): String command for Lovense devices. Must be a valid Lovense command accessible on most of their devices. See STPIHKAL for more info. Implementations should check this for validity. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: LovenseCmd Id=1 Server->>Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "LovenseCmd": { "Id": 1, "DeviceIndex": 0, "Command": "Vibrate:20;" } } ] ``` --- ## VorzeA10CycloneCmd **Reason for Deprecation:** Superceded by a combination of [VibrateCmd](#linearcmd) and [RotateCmd](#rotatecmd). **Description:** Causes a device that supports Vorze A10 Cyclone style commands to run whatever event may be related. More information on Vorze commands can be found in STPIHKAL. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Speed_ (unsigned int): Unsigned integer in range [0-100], denoting speed to rotate at. * _Clockwise_ (boolean): Rotation direction **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: VorzeA10CycloneCmd Id=1 Server->>Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "VorzeA10CycloneCmd": { "Id": 1, "DeviceIndex": 0, "Speed": 50, "Clockwise": true } } ] ``` --- ## Test **Reason for Deprecation:** Violates the assumption that server and client should not be able to send the same message type. Not particularly useful either, since the whole protocol is made up of messages, so if you've send/received one, you're... pretty much good. **Description:** The Test message is used for development and testing purposes. Sending a Test message with a string to the server will cause the server to return a Test message. If the string is "Error", the server will return an error message instead. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _TestString_ (string): String to echo back from server. **Expected Response:** * Test message with matching Id and TestString on successful request. * Error message on value or message error, or TestString being 'Error'. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: Test Id=5 TestString=X Server->>-Client: Test Id=5 TestString=X ``` **Serialization Example:** ```json [ { "Test": { "Id": 5, "TestString": "Moo" } } ] ``` --- ## RequestLog **Reason for Deprecation:** Requesting logging means that the client, whoever that may be, can request dumps of information from the server. When the client/server are in the same process, that's fine. However, when the client may be remote to the server (for instance, a web app accessing intiface desktop), this allows WAY too much information leakage, as the logging messages may be quite verbose, unless the server is setup to ignore it. Also, this has nothing to do with controlling sex toys. It was more for debugging situations that have never really arisen. If we need logs, we can get them from servers, and we don't really need to fly them over the line. **Description:** Requests that the server send all internal log messages to the client. Useful for debugging. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _LogLevel_ (string): The highest level of message to receive. Sending "Off" turns off messages, while sending "Trace" denotes that all log messages should be sent to the client. Valid LogLevel values: * Off * Fatal * Error * Warn * Info * Debug * Trace **Expected Response:** * Ok message with matching Id on successful logging request. Assuming the LogLevel was not "Off", Log type messages will be received after this. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestLog Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "RequestLog": { "Id": 1, "LogLevel": "Warn" } } ] ``` --- ## Log **Reason for Deprecation:** See RequestLog reason. **Description:** Log message from the server. Only sent after the client has sent a RequestLog message with a level other than "Off". **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _LogLevel_ (string): The level of the log message. * Off * Fatal * Error * Warn * Info * Debug * Trace * _LogMessage_ (string): Log message. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestLog Id=1 Server->>-Client: Ok Id=1 Server->>Client: Log Id=0 LogLevel=Warn Server->>Client: Log Id=0 LogLevel=Trace ``` **Serialization Example:** ```json [ { "Log": { "Id": 0, "LogLevel": "Trace", "LogMessage": "This is a Log Message." } } ] ``` --- ## VibrateCmd **Reason for Deprecation:** Superceded by ScalarCmd. **Description:** Causes a device that supports vibration to run specific vibration motors at a certain speeds. Devices with multiple vibrator features may take multiple values. The [FeatureCount](deprecated#message-attributes-for-deviceaddeddevicelist---spec-v3) attribute for the message in the [DeviceList](deprecated#devicelist---spec-v1)/[DeviceAdded](deprecated#deviceadded---spec-v1) message will contain that information. **Introduced In Spec Version:** 1 **Last Updated In Spec Version:** 1 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Speeds_ (array): Vibration speeds * _Index_ (unsigned int): Index of vibration motor * _Speed_ (double): Vibration speed with a range of [0.0-1.0] **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: VibrateCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "VibrateCmd": { "Id": 1, "DeviceIndex": 0, "Speeds": [ { "Index": 0, "Speed": 0.5 }, { "Index": 1, "Speed": 1.0 } ] } } ] ``` --- ## BatteryLevelCmd **Reason for Deprecation:** Superceded by SensorReadCmd. **Description:** Requests that a device send its battery level. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to query for battery reading. **Expected Response:** * [BatteryLevelReading](#batterylevelreading) message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: BatteryLevelCmd Id=1 DeviceIndex=0 Server->>Client: BatteryLevelReading Id=1 DeviceIndex=0 BatteryLevel=0.5 ``` **Serialization Example:** ```json [ { "BatteryLevelCmd": { "Id": 1, "DeviceIndex": 0 } } ] ``` --- ## BatteryLevelReading **Reason for Deprecation:** Superceded by SensorReading. **Description:** Message containing a battery level reading from a device, as requested by [BatteryLevelCmd](#batterylevelcmd). **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device battery reading is from. * _BatteryLevel_ (double): Battery Level with a range of [0.0-1.0] **Expected Response:** * None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: BatteryLevelCmd Id=1 DeviceIndex=0 Server->>Client: BatteryLevelReading Id=1 DeviceIndex=0 BatteryLevel=0.5 ``` **Serialization Example:** ```json [ { "BatteryLevelReading": { "Id": 1, "DeviceIndex": 0, "BatteryLevel": 0.5 } } ] ``` --- ## RSSILevelCmd **Reason for Deprecation:** Superceded by SensorReadCmd. Also never implemented in any official reference implementation of Buttplug. **Description:** Requests that a device send its RSSI level. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to query for RSSI level. **Expected Response:** * [RSSILevelReading](#rssilevelreading) message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RSSILevelCmd Id=1 DeviceIndex=0 Server->>Client: RSSILevelReading Id=1 DeviceIndex=0 RSSILevel=-40 ``` **Serialization Example:** ```json [ { "RSSILevelCmd": { "Id": 1, "DeviceIndex": 0 } } ] ``` --- ## RSSILevelReading **Reason for Deprecation:** Superceded by SensorReading. Also never implemented in any official reference implementation of Buttplug. **Description:** Message containing a RSSI level reading from a device, as requested by [RSSILevelCmd](#rssilevelcmd). **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device the reading is from. * _RSSILevel_ (int): RSSI Level, usually expressed as db gain, usually [-100:0] **Expected Response:** * None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RSSILevelCmd Id=1 DeviceIndex=0 Server->>Client: RSSILevelReading Id=1 DeviceIndex=0 RSSILevel=-40 ``` **Serialization Example:** ```json [ { "RSSILevelReading": { "Id": 1, "DeviceIndex": 0, "RSSILevel": -40 } } ] ``` --- ## ScalarCmd **Reason for Deprecation:** Superceded by ValueCmd. **Description:** Sets the static level for a feature. For instance, the vibration speed of a vibrator, the oscillating speed of a fucking machine, etc... The [Message Attributes](#message-attributes-for-deviceaddeddevicelist---spec-v3) for the ScalarCmd message in the [DeviceList](#devicelist---spec-v3)/[DeviceAdded](#deviceadded) message contain information on the actuator type and description, number of actuators, level ranges, and more. Due to the amount of different controls that are scalars within haptics (vibration speed, oscillation speed, inflate/constrict pressures, etc), this message provides flexibility to add new acutuation types without having to introduce new messages into the protocol. The values accepted as actuator types can be extended as needed. In practice, ScalarCmd is meants to be exposed to developers via crafted APIs, i.e. having vibrate()/rotate()/oscillate() etc functions available on a data structure that represents a device, with the actuator types denoting which of those methods may be allowed. The ScalarCmd itself can be exposed via API also, but this may lead to a lack of attention to context that could cause issues (i.e. someone driving a vibrator and a fucking machine with the same power signals). Mitigation for that type of issue may be UX related versus system/protocol related, by letting users set speed limits and ranges for devices. **Introduced In Spec Version:** 3 **Last Updated In Spec Version:** 3 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Scalars_ (array): Scalar values to set actuators * _Index_ (unsigned int): Index of actuator * _Scalar_ (double): Actuator level with a range of [0.0-1.0] * _ActuatorType_ (string): Type of actuator that the user expects to control with this command. This is to make sure that context is correct between the client and server. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: ScalarCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "ScalarCmd": { "Id": 1, "DeviceIndex": 0, "Scalars": [ { "Index": 0, "Scalar": 0.5, "ActuatorType": "Vibrate" }, { "Index": 1, "Scalar": 1.0, "ActuatorType": "Inflate" } ] } } ] ``` --- ## LinearCmd **Reason for Deprecation:** Superceded by ValueWithParameterCmd. **Description:** Causes a device that supports linear movement to move to a position over a certain amount of time. Devices with multiple linear actuator features may take multiple values. **Introduced In Spec Version:** 1 **Last Updated In Spec Version:** 1 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Vectors_ (array): Linear actuator speeds and positions * _Index_ (unsigned int): Index of linear actuator * _Duration_ (unsigned int): Movement time in milliseconds * _Position_ (double): Target position with a range of [0.0-1.0] **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: LinearCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "LinearCmd": { "Id": 1, "DeviceIndex": 0, "Vectors": [ { "Index": 0, "Duration": 500, "Position": 0.3 }, { "Index": 1, "Duration": 1000, "Position": 0.8 } ] } } ] ``` --- ## RotateCmd **Reason for Deprecation:** Superceded by ValueWithParameterCmd. **Description:** Causes a device that supports rotation to rotate at a certain speeds in specified directions. Devices with multiple rotating features may have multiple values. **Introduced In Spec Version:** 1 **Last Updated In Spec Version:** 1 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _Rotations_ (array): Rotation speeds * _Index_ (unsigned int): Index of rotation motor * _Speed_ (double): Rotation speed with a range of [0.0-1.0] * _Clockwise_ (boolean): Direction of rotation (clockwise may be subjective) **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RotateCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "RotateCmd": { "Id": 1, "DeviceIndex": 0, "Rotations": [ { "Index": 0, "Speed": 0.5, "Clockwise": true }, { "Index": 1, "Speed": 1.0, "Clockwise": false } ] } } ] ``` --- ## DeviceAdded **Reason for Deprecation:** Removed in Spec v4, simplified protocol to only send DeviceList. **Description:** Sent by the server whenever a device is added to the system. Can happen at any time after identification stage (i.e. after client is connected), as it is assumed many server implementations will support devices with hotplugging capabilities that do not require specific scanning/discovery sessions. **Introduced In Spec Version:** 0 **Last Updated In Spec Version**: 3 (See [Deprecated Messages](#deviceadded---spec-v1) for older versions.) **Fields:** * _Id_ (unsigned int): Message Id * _DeviceName_ (string): Descriptive name of the device, as taken from the base device configuration file. * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * _DeviceMessageTimingGap_ (_optional_, unsigned integer): Recommended minimum gap between device commands, in milliseconds. This is only a recommendation, and will not be enforced on the server, as most times the server does not actually know the exact message gap timing required (hence this being recommended). Enforcement on the client (with developer option to disable) is encouraged. Optional field, not required to be included in message. Missing value should be assumed that server does not know recommended message gap. * _DeviceDisplayName_ (_optional_, string): User provided display name for a device. Useful for cases where a users may have multiple of the same device connected. Optional field, not required to be included in message. Missing value means that no device display name is set, and device name should be used. * _DeviceMessages_ (dictionary): Accepted Device Messages * Keys (string): Type names of Device Messages that the device will accept * Values (Array of [Message Attributes](#message-attributes-for-deviceaddeddevicelist---spec-v3)): Attributes for the Device Messages. Each feature is a seperate array element, and its index in the array matches how it should be addressed in generic command messages. For instance, in the example below, the Clitoral Stimulator would be Actuator Index 0 in ScalarCmd. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram participant Client participant Server Server->>Client: DeviceAdded Id=0 ``` **Serialization Example:** ```json [ { "DeviceAdded": { "Id": 0, "DeviceName": "Test Vibrator", "DeviceIndex": 0, "DeviceMessageTimingGap": 100, "DeviceDisplayName": "Rabbit Vibrator", "DeviceMessages": { "ScalarCmd": [ { "StepCount": 20, "FeatureDescriptor": "Clitoral Stimulator", "ActuatorType": "Vibrate" }, { "StepCount": 20, "FeatureDescriptor": "Insertable Vibrator", "ActuatorType": "Vibrate" } ], "StopDeviceCmd": {} } } } ] ``` --- ## DeviceRemoved **Reason for Deprecation:** Removed in Spec v4, simplified protocol to only send DeviceList. **Description:** Sent by the server whenever a device is removed from the system. Can happen at any time after identification. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram participant Client participant Server Server->>Client: DeviceRemoved Id=0 ``` **Serialization Example:** ```json [ { "DeviceRemoved": { "Id": 0, "DeviceIndex": 0 } } ] ``` --- ## DeviceList - Spec v3 **Reason for Deprecation:** Updated in Spec v4 for new features system **Description:** Server reply to a client request for a device list. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 3 (See [Deprecated Messages](#devicelist---spec-v1) for older versions.) **Fields:** * _Id_ (unsigned int): Message Id * _Devices_ (array): Array of device objects * _DeviceName_ (string): Descriptive name of the device, as taken from the base device configuration file. * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * _DeviceMessageTimingGap_ (_optional_, unsigned integer): Recommended minimum gap between device commands, in milliseconds. This is only a recommendation, and will not be enforced on the server, as most times the server does not actually know the exact message gap timing required (hence this being recommended). Enforcement on the client (with developer option to disable) is encouraged. Optional field, not required to be included in message. Missing value should be assumed that server does not know recommended message gap. * _DeviceDisplayName_ (_optional_, string): User provided display name for a device. Useful for cases where a users may have multiple of the same device connected. Optional field, not required to be included in message. Missing value means that no device display name is set, and device name should be used. * _DeviceMessages_ (dictionary): Accepted Device Messages * Keys (string): Type names of Device Messages that the device will accept * Values (Array of [Message Attributes](#message-attributes-for-deviceaddeddevicelist---spec-v3)): Attributes for the Device Messages. Each feature is a seperate array element, and its index in the array matches how it should be addressed in generic command messages. For instance, in the example below, the Clitoral Stimulator would be Actuator Index 0 in ScalarCmd. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestDeviceList Id=1 Server->>-Client: DeviceList Id=1 ``` **Serialization Example:** ```json [ { "DeviceList": { "Id": 1, "Devices": [ { "DeviceName": "Test Vibrator", "DeviceIndex": 0, "DeviceMessages": { "ScalarCmd": [ { "StepCount": 20, "FeatureDescriptor": "Clitoral Stimulator", "ActuatorType": "Vibrate" }, { "StepCount": 20, "FeatureDescriptor": "Insertable Vibrator", "ActuatorType": "Vibrate" } ], "StopDeviceCmd": {} } }, { "DeviceName": "Test Stroker", "DeviceIndex": 1, "DeviceMessageTimingGap": 100, "DeviceDisplayName": "User set name", "DeviceMessages": { "LinearCmd": [ { "StepCount": 100, "FeatureDescriptor": "Stroker", "ActuatorType": "Linear" } ], "StopDeviceCmd": {} } } ] } } ] ``` --- ## Message Attributes for DeviceAdded/DeviceList - Spec v3 **Reason for Deprecation:** Removed in Spec v4, simplified protocol to only send DeviceList, so folding section in there and updating for features. **Description:** A collection of message attributes. This object is always an array element of a Device Message key/value pair within a [DeviceList](#devicelist---spec-v3) or [DeviceAdded](#deviceadded) message. Not all attributes are relevant for all Device Messages on all Devices; in these cases the attributes will not be included. **Introduced In Spec Version:** 1 **Last Updated In Spec Version**: 3 **Attributes:** * _FeatureDescriptor_ * Valid for Messages: ScalarCmd, RotateCmd, LinearCmd, SensorReadCmd * Type: String * Description: Text descriptor for a feature. * _StepCount_ * Valid for Messages: ScalarCmd, RotateCmd, LinearCmd * Type: unsigned int * Description: For each feature, lists the number of discrete steps the feature can use. This value can be used in calculating the 0.0-1.0 range required for ScalarCmd and other messages. * _ActuatorType_ * Valid for Messages: ScalarCmd, RotateCmd, LinearCmd * Type: String * Description: Type of actuator this feature represents. * _SensorType_ * Valid for Messages: SensorReadCmd, SensorSubscribeCmd * Type: String * Description: Sensor types that can be read by Sensor. * _SensorRange_ * Valid for Messages: SensorReadCmd, SensorSubscribeCmd (but applies to values returned by SensorReading) * Type: array of arrays of 2 integers * Description: Range of values a sensor can return. As sensors can possibly return multiple values in the same SensorReading message (i.e. an 3-axis accelerometer may return all 3 axes in one read), this is sent as an array of ranges. The length of this array will always match the number of readings that will be returned from a sensor, and can be used to find the reading count for a sensor. * _Endpoints_ * Valid for Messages: RawReadCmd, RawWriteCmd, RawSubscribeCmd * Type: array of strings * Description: Endpoints that can be used by Raw commands. --- ## RequestServerInfo - Spec v1 **Reason for Deprecation:** Added Major/Minor versions back in with spec v4. **Description:** Sent by the client to register itself with the server, and request info from the server. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 1 **Fields:** * _Id_ \(unsigned int\): Message Id * _ClientName_ \(string\): Name of the client, for the server to use for UI if needed. Cannot be null. * _MessageVersion_ \(uint\): Message spec version of the client software. **Expected Response:** * ServerInfo message on success * Error message on malformed message, null client name, server not able to use requested message spec version, or other error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RequestServerInfo Id=0 Server->>Client: ServerInfo Id=0 ``` **Serialization Example:** ```json [ { "RequestServerInfo": { "Id": 1, "ClientName": "Test Client", "MessageVersion": 1 } } ] ``` --- ## ServerInfo - Spec v2 **Reason for Deprecation:** Added Major/Minor versions back in with spec v4. **Description:** Send by server to client, contains information about the server name \(optional\), template version, and ping time expectations. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ \(unsigned int\): Message Id * _ServerName_ \(string\): Name of the server. Can be null \(0-length\). * _MessageVersion_ \(uint\): Message template version of the server software. Should equal the version that the client sent in RequestServerInfo. * _MaxPingTime_ \(uint\): Maximum internal for pings from the client, in milliseconds. If a client takes to longer than this time between sending Ping messages, the server is expected to disconnect. **Expected Response:** None. Server-To-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RequestServerInfo Id=0 Server->>Client: ServerInfo Id=0 ``` **Serialization Example:** ```json [ { "ServerInfo": { "Id": 1, "ServerName": "Test Server", "MessageVersion": 1, "MaxPingTime": 100 } } ] ``` --- ## RawWriteCmd **Reason for Deprecation:** Raw commands removed completely in spec v4. **Description:** Client request to have the server write a byte array to a device endpoint. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to write to. * _Endpoint_ (string): Name of endpoint to write data to. * _Data_ (array of unsigned 8-bit int): Raw data to write to endpoint. * _WriteWithResponse_ (boolean): True if BLE WriteWithResponse required, False otherwise. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RawWriteCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "RawWriteCmd": { "Id": 1, "DeviceIndex": 0, "Endpoint": "tx", "Data": [0, 1, 0], "WriteWithResponse": false } } ] ``` --- ## RawReadCmd **Reason for Deprecation:** Raw commands removed completely in spec v4. **Description:** Client request to have the server read a byte array from a device endpoint. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to read data from. * _Endpoint_ (string): Name of endpoint to read data from. * _ExpectedLength_ (unsigned int): Amount of data to read, 0 if "Read all currently available". * _WaitForData_ (boolean): True if return should only be sent when there is data available, or until expected length is met. **Expected Response:** * RawReading message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RawReadCmd Id=1 Server->>-Client: RawReading Id=1 ``` **Serialization Example:** ```json [ { "RawReadCmd": { "Id": 1, "DeviceIndex": 0, "Endpoint": "tx", "ExpectedLength": 0, "WaitForData": false } } ] ``` --- ## RawReading **Reason for Deprecation:** Raw commands removed completely in spec v4. **Description:** Server response when data is read (in response to RawReadCmd) or received (after RawSubscribe) from a device endpoint. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id. Can be 0 in cases of subscription data. * _DeviceIndex_ (unsigned int): Index of device to data was read from. * _Endpoint_ (string): Name of endpoint to data was read from. * _Data_ (array of unsigned 8-bit int): Raw data read from endpoint. **Serialization Example:** ```json [ { "RawReading": { "Id": 1, "DeviceIndex": 0, "Endpoint": "rx", "Data": [0, 1, 0] } } ] ``` --- ## RawSubscribeCmd **Reason for Deprecation:** Raw commands removed completely in spec v4. **Description:** Client request to have the server subscribe and send all data that comes in from an endpoint that is not explicitly read. Usually useful for Bluetooth notify endpoints, or other streaming data endpoints. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to subscribe to. * _Endpoint_ (string): Name of endpoint to subscribe to. **Expected Response:** * Ok if subscription is successful, followed by RawReading messages on all new readings. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RawSubscribeCmd Id=1 Server->>-Client: Ok Id=1 Server->>+Client: RawReading Id=0 Server->>+Client: RawReading Id=0 ``` **Serialization Example:** ```json [ { "RawSubscribeCmd": { "Id": 1, "DeviceIndex": 0, "Endpoint": "tx" } } ] ``` --- ## RawUnsubscribeCmd **Reason for Deprecation:** Raw commands removed completely in spec v4. **Description:** Client request to have the server unsubscribe from an endpoint to which it had previously subscribed. **Introduced In Spec Version:** 2 **Last Updated In Spec Version:** 2 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to subscribe to. * _Endpoint_ (string): Name of endpoint to subscribe to. **Expected Response:** * Ok if unsubscription is successful. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RawUnsubscribeCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "RawUnsubscribeCmd": { "Id": 1, "DeviceIndex": 0, "Endpoint": "tx" } } ] ``` --- ## StopDeviceCmd Version - Spec v0 **Reason for Deprecation:** Replaced with StopCmd in v4 **Description:** Client request to have the server stop a device from whatever actions it may be taking. This message should be supported by all devices, and the server should know how to stop any device it supports. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device to stop. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StopDeviceCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "StopDeviceCmd": { "Id": 1, "DeviceIndex": 0 } } ] ``` --- ## StopAllDevices - Spec v0 **Reason for Deprecation:** Replaced with StopCmd in v4 **Description:** Sent by the client to tell the server to stop all devices. Can be used for emergency situations, on client shutdown for cleanup, etc… While this is considered a Device Message, since it pertains to all currently connected devices, it does not specify a device index (and does not end with 'Cmd'). While it is polite to do so, the client is not _required_ to send StopAllDevices on disconnect. The server will normally stop devices on disconnect no matter what. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StopAllDevices Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "StopAllDevices": { "Id": 1 } } ] ``` --- --- ## Device Discovery Messages Messages relating to finding and getting information about devices connected to the system. --- ## StartScanning **Description:** Client request to have the server start scanning for devices on all busses that it knows about. Useful for protocols like Bluetooth, which require an explicit discovery phase. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StartScanning Id=1 Server->>-Client: Ok Id=1 Server->>Client: DeviceList Id=0 Server->>Client: DeviceList Id=0 ``` **Serialization Example:** ```json [ { "StartScanning": { "Id": 1 } } ] ``` --- ## StopScanning **Description:** Client request to have the server stop scanning for devices. Useful for protocols like Bluetooth, which may not timeout otherwise. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StartScanning Id=1 Server->>-Client: Ok Id=1 Server->>Client: DeviceList Id=0 Server->>Client: DeviceList Id=0 Client->>+Server: StopScanning Id=2 Server->>-Client: Ok Id=2 ``` **Serialization Example:** ```json [ { "StopScanning": { "Id": 1 } } ] ``` --- ## ScanningFinished **Description:** Sent by the server once it has stopped scanning on all busses. Since systems may have timeouts that are not controlled by the server, this is a separate message from the StopScanning flow. ScanningFinished can happen without a StopScanning call. In reality, this event is usually only useful when working with systems that can only scan for a single device at a time, like WebBluetooth. When on normal desktop/mobile APIs, it should be assumed that running StartScanning/StopScanning will be the main usage. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** None. Server-to-Client only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StartScanning Id=1 Server->>-Client: Ok Id=1 Server->>Client: DeviceList Id=0 Server->>Client: DeviceList Id=0 Server->>Client: ScanningFinished Id=0 ``` **Serialization Example:** ```json [ { "ScanningFinished": { "Id": 0 } } ] ``` --- ## RequestDeviceList **Description:** Client request to have the server send over its known device list, without starting a full scan. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** * DeviceList message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestDeviceList Id=1 Server->>-Client: DeviceList Id=1 ``` **Serialization Example:** ```json [ { "RequestDeviceList": { "Id": 1 } } ] ``` --- ## Device Information Messages Messages that convey information about devices currently connected to the system. All of the following messages are sent Server -> Client, either in response to `RequestDeviceList` or on connection/disconnection of a device. --- ## DeviceList **Description:** Server reply to a client request for a device list, or sent as an event when a device is connected or disconnected. > **Tip: Detecting Device Changes** In Spec V4, the `DeviceAdded` and `DeviceRemoved` messages were removed in favor of always sending the complete `DeviceList`. Clients are expected to maintain their own copy of the device list and diff against incoming `DeviceList` messages to detect which devices were added or removed. This simplifies the protocol while giving clients full flexibility in how they track device state changes. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 4 (See [Deprecated Messages](deprecated.md) for older versions.) **Fields:** * _Id_ (unsigned int): Message Id * _Devices_ (map of indexes to device object, with each object having the following fields): * _DeviceName_ (string): Descriptive name of the device, as taken from the base device configuration file. * _DeviceIndex_ (unsigned integer): Index used to identify the device when sending Device Messages. * This is a repeat of the map key * Device indexes are stable only while the device appears in the latest `DeviceList`. Servers may reuse a removed device's index for a later connection, including a reconnection of the same physical device. Clients should discard cached feature data and subscriptions when an index disappears from `DeviceList`, and treat a later device with that index as a new device. * _DeviceMessageTimingGap_ (unsigned integer): Minimum gap between output command dispatches to this device, in milliseconds, **enforced by the server in Spec V4+**. This applies to `OutputCmd` hardware dispatch only; `InputCmd`, `StopCmd`, and non-device lifecycle messages are not delayed. If multiple `OutputCmd` messages target the same device feature within the timespan defined here, the server may coalesce them and send only the latest command for that feature on the next dispatch trigger. The server still returns an `Ok` or `Error` response for every client message it accepts, even if an earlier output command is superseded before it reaches the device. `StopCmd` bypasses this gap and should clear any pending output command within its selection. This prevents issues with device communication busses with the possibility of buffer backup (like BLE), where devices would stop responding or update with significant delays (e.g., 30+ seconds) when commands were sent faster than the Bluetooth ConnectionInterval allowed. This relieves developers of having to regulate input from users or tune their clients. If this is set to 0, it means there is no maximum update rate imposed by this field. * _DeviceDisplayName_ (_optional_, string): User provided display name for a device. Useful for cases where a users may have multiple of the same device connected. Optional field, not required to be included in message. Missing value means that no device display name is set, and device name should be used. * _DeviceFeatures_ (map of indexes to feature objects, with each object having the following fields) * _FeatureDescription_ (string): Text descriptor for a feature. * _FeatureIndex_ (unsigned 32-bit integer): Index that should be used to refer to the feature in messages like `OutputCmd`, `InputCmd`, etc... * This is a repeat of the map key. * _Output_ (_optional_, Object): Represents outputs that are part of this feature. This field is omitted when a feature has no outputs. A feature must include `Output`, `Input`, or both. A map of OutputType to information objects. If a feature lists multiple output types, this means that the feature can be controlled through different contexts. For instance, a feature having both _Position_ and _HwPositionWithDuration_ output types means that the feature can move instantaneously to a goal position, or can move to the goal position over a certain amount of time. * \[_OutputType_\] (OutputType as String): OutputType is used as a key here, so this would be something like _Vibrate_, _Position_, etc... [Valid types are listed in the OutputCmd page](./output) **IMPORTANT**: Fields for this will change based on the key value. See below for which fields are valid per output type. * _Value_ (Signed 32-bit integer range): Range of the value this output type can be set to. It is assumed that once a value is set, it will not be reset until _OutputCmd_ is called again for the same feature. This can be used as a 2-dimensional value, for instance, a rotation feature that has direction may have a range of _[-x, x]_ to denote that it can rotate in 2 different directions. * Valid for Output Types: All * _Duration_ (Unsigned 32-bit integer range, in milliseconds): Range of duration values, in milliseconds, for output types that use time * Valid for Output Types: _HwPositionWithDuration_ * _Input_ (_optional_, Object): Represents inputs that may be part of this feature. This field is omitted when a feature has no inputs. A map of InputType to information objects. * \[_InputType_\] (InputType as String): InputType is used as a key here, so this field would be something like "Battery", "Pressure", etc... * _Command_ (array of string: \["Read", "Subscribe", "Unsubscribe"\]): Some combination of "Read" and/or "Subscribe". * _Value_ (Range, array of 2 signed 32-bit integer values): Range of values that may be received from the input, if known. > **Tip: Range Semantics** All ranges in Buttplug (for both Output and Input values) are: - **Inclusive on both ends**: A range of `[0, 20]` means values 0 through 20 are all valid - **Contiguous from the API user's perspective**: All integer values within the range are valid; there are no gaps or discrete steps exposed at the protocol level - **Linearly interpolated**: The protocol assumes uniform distribution across the range (though actual device hardware behavior may vary) > **Tip: Why are the DeviceIndex and FeatureIndex repeated as map keys and object fields?** DeviceIndex and FeatureIndex are how client implementations refer to a device in InputCmd and OutputCmd messages. They are the main identifiers for Buttplug. In most client implementations we've built so far, we end up using Map\ types to represent Devices and Features, mapping indexes to the related objects. However, for the objects themselves, it tends be to handy for the object to know its index when forming device control messages. With client ergonomics in mind, we just pack device info this way to begin with, so that serialization can happen from our base storage structures, and deserialization gives us the type of data structures we usually had to build by iterating through object arrays in past versions. This also gives us the added bonus of not being able to somehow pack devices with matching IDs (which would be a massive bug anyways but now it's not even structurally possible.). There is some awkwardness in the JSON implementation of this, as object field names cannot be numeric. These are normally converted to strings when serialized, then back to numeric types automatically when deserialized for whatever language a client may be implemented in, assuming it has a decent serde library. For those screaming "BUT ADDED SIZE AND REDUNDANCY AND YOU COULD STILL SOMEHOW PACK KEYS THAT DON'T MATCH INTERNAL INDEX FIELDS": DeviceList messages are sent a few times a minutes, so size doesn't matter. We could screw up consistency, but once again that'd be a huge bug and there's been one server implementation for 8 years. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: RequestDeviceList Id=1 Server->>-Client: DeviceList Id=1 ``` **Serialization Example:** ```json [ { "DeviceList": { "Id": 1, "Devices": { "0": { "DeviceName": "Test Vibrator", "DeviceIndex": 0, "DeviceMessageTimingGap": 0, "DeviceFeatures": { "0": { "FeatureIndex": 0, "FeatureDescription": "Clitoral Stimulator", "Output": { "Vibrate": { "Value": [0, 20] } } }, "1": { "FeatureIndex": 1, "FeatureDescription": "Insertable Stimulator", "Output": { "Vibrate": { "Value": [0, 20] } } }, "2": { "FeatureIndex": 2, "FeatureDescription": "Rotating Head with Directional Control", "Output": { "Rotate": { "Value": [-20, 20] } } }, "3": { "FeatureIndex": 3, "FeatureDescription": "Battery", "Input": { "Battery": { "Value": [[0, 100]], "Command": ["Read"] } } } } }, "1": { "DeviceName": "Test Stroker", "DeviceIndex": 1, "DeviceMessageTimingGap": 100, "DeviceDisplayName": "User set name", "DeviceFeatures": { "0": { "FeatureIndex": 0, "FeatureDescription": "Stroker", "Output": { "HwPositionWithDuration": { "Value": [0, 100], "Duration": [0, 100000] }, "Position": { "Value": [0, 100] } } }, "2": { "FeatureIndex": 2, "FeatureDescription": "Bluetooth Radio RSSI", "Input": { "Rssi": { "Value": [[-100, -10]], "Command": ["Read"] } } } } } } } } ] ``` --- ## Connection Messages Messages used for client/server connection lifecycle, including handshake and disconnection. --- ## RequestServerInfo **Description:** Sent by the client to register itself with the server, and request info from the server. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 4 (See [Deprecated Messages](deprecated.md#requestserverinfo---spec-v1) for older versions.) **Fields:** * _Id_ \(unsigned int\): Message Id * _ClientName_ \(string\): Name of the client, for the server to use for UI if needed. Cannot be null. * _ProtocolVersionMajor_ \(uint\): Message spec major version of the client software. * _ProtocolVersionMinor_ \(uint\): Message spec minor version of the client software. **Expected Response:** * ServerInfo message on success. * Error message on malformed message, null client name, server not able to use requested message spec version, or other error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RequestServerInfo Id=1 Server->>Client: ServerInfo Id=1 ``` **Serialization Example:** ```json [ { "RequestServerInfo": { "Id": 1, "ClientName": "Test Client", "ProtocolVersionMajor": 4, "ProtocolVersionMinor": 0 } } ] ``` --- ## ServerInfo **Description:** Send by server to client, contains information about the server name \(optional\) and ping time expectations. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ \(unsigned int\): Message Id * _ServerName_ \(string\): Name of the server. Can be an empty string, but the field will still exist. * _MaxPingTime_ \(uint\): Maximum interval for pings from the client, in milliseconds. If a client takes longer than this time between sending Ping messages, the server is expected to disconnect. A value of 0 means the server does not require Ping messages for this connection. * _ProtocolVersionMajor_ \(uint\): Protocol major version selected by the server for this connection. * _ProtocolVersionMinor_ \(uint\): Protocol minor version selected by the server for this connection. **Expected Response:** None. Server-To-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>Server: RequestServerInfo Id=1 Server->>Client: ServerInfo Id=1 ``` **Serialization Example:** ```json [ { "ServerInfo": { "Id": 1, "ServerName": "Test Server", "MaxPingTime": 100, "ProtocolVersionMajor": 4, "ProtocolVersionMinor": 0 } } ] ``` --- ## Disconnect **Description:** Sent by the client to request a graceful disconnection from the server. Upon receiving this message, the server should stop all devices, clean up any subscriptions, and close the connection. While WebSocket and other stateful transports handle disconnection at the transport level, this message is useful for stateless transports (such as UDP) where there is no inherent connection state. It also allows clients to explicitly signal intent to disconnect rather than relying on the ping timeout mechanism. **Introduced In Spec Version:** 4 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** * Ok message with matching Id, followed by server closing the connection. * The server may close the connection without sending Ok if the transport supports it. This is an explicit exception to the normal Client -> Server reply rule. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: Disconnect Id=1 Server->>-Client: Ok Id=1 Server->>Client: [Connection Closed] ``` **Serialization Example:** ```json [ { "Disconnect": { "Id": 1 } } ] ``` --- ## The Buttplug Intimate Device Control Protocol * **Version:** 4 * **Documentation Repo**: [https://github.com/buttplugio/docs.buttplug.io](https://github.com/buttplugio/docs.buttplug.io) Buttplug is a set of technologies and protocols to allow developers to write software that can access an array of computer controlled devices (sex toys, kegelcizers, etc...) in a semi-future-proof way. ## The Need for a Computer Controlled Intimate Device Protocol The list of technological requirements to access a computer controlled sex device in a way not supported by the original manufacturer is quite long. There are some major hurdles between buying a device and having DIY control of it: * Experience in the operating system the user will want to access the device from, including capabilities and programming interfaces to work with the connection medium \(serial/usb/bluetooth/etc\) * Experience using a programming language that allows the user access to hardware via the operating system. * Knowledge of the communications protocol the device uses. This is rarely, if ever, publicly documented information. The Buttplug Sex Device Control Protocol seeks to lower these bars as much as possible. * By creating a system that can be implemented in a cross-platform way, software based on the Buttplug Protocol can reduce the amount of knowledge required to access hardware from a certain operating system or platform. Using web technologies or cross-platform systems like Flutter, Electron, or Tauri to build software that implements Buttplug means that access could happen via desktop or mobile platforms. * By creating simplified the methods to talk to these devices, implementations of the protocol can be written in multiple languages and still interact with each other. This opens development opportunities to multiple communities and ecosystems. * Assuming some sort of widespread adoption happens, this could drive the commercial market to build devices with the Buttplug Protocol in mind, or even to use it directly. Until that point, the portion of the community familiar with reverse engineering can help open device access to those who are interested in controlling the devices. * The prior point was written in 2017. As of 2024, the Buttplug project is now in touch with several manufacturers, working together to implement open support for devices. ## Generalized Control One of the windmills Buttplug tilts at is the idea of "generalized control". Simply put, is it viable to drive completely different devices from the same control signal? In some cases, this is simple. In others, it may be impossible. Starting with the simple case, let's say a user has two devices, called Device A and Device B: * Each device is made by a different manufacturer. * One device uses Bluetooth to talk to the computer, the other uses USB. * Both of these devices have vibration functionality. The user has a particular function they would like to implement in a software application, which would utilize the vibration function of both devices. Without Buttplug, this would require knowing how to talk to both USB and Bluetooth, and also knowing how each of these devices communicates with the computer in order to control vibration levels. They would then have to add both of these to their application. With Buttplug, "Server" implementations are expected to take care of the different manufacturer and hardware communication requirements. However, if the project were restricted to ways to communicate with specific hardware, the application being developed would have to provide separate logic paths to cover all known device instances (the aforementioned bluetooth and USB devices, as well as any others that the developer wanted to support). This is where the idea of "generalized haptics" comes in. Instead of either a "Device A" or "Device B" command to the server, the user can just send a generic vibration speed command, along with the identifier for which device, and which features of which device they wanted to use. This would allow their software would work with any device, including devices they do not own/have tested with, that could translate the generic vibration speed command. Now, the not so simple case. Let's add Device C, a stroker. To use Device C with the same application as Device A and Device B, the generic vibration speed command has to be translated into some facsimile that is valid for a stroker. While this is most likely not tractable for a global solution, the goal of Buttplug is to make explorations of ideas like this accessible and easy to play with. > **Warning: Hardware Limitations** The devices Buttplug supports are consumer-grade products with limited capabilities. The protocol cannot provide certain features because the underlying hardware simply does not support them: - **No timestamps**: At this time of this writing, no supported device reports when sensor readings were captured or when commands complete. Motion synchronization and latency compensation must be handled at the either the library or application level. We shield our users where we can, but it's rough out there. - **No firmware version**: Most devices do not expose their firmware version over their communication protocols. - **No pairing state**: Pairing is handled at the OS/transport level, not by Buttplug. - **No connection quality metrics**: Beyond RSSI (where available), devices do not report connection quality, packet loss, or latency statistics. - **No charging state**: See the Battery input type documentation for details. These limitations reflect the reality of the hardware ecosystem, not design oversights in the protocol. After all, these *are* cheap sex toys made by companies that may not even have engineering departments. ## Comparisons to Existing Software It's somewhat difficult to point to a real world counterpart for the Buttplug Protocol. While brands like [xtoys](http://xtoys.app) and [FeelMe](http://feelme.com) have created systems for controlling different devices, neither of those is open source, so it's hard to point at them as examples. The closest existing projects are those which reinterpret or generalize control schemes. Projects like: * [FreePIE](http://andersmalmgren.github.io/FreePIE/) * [OSCulator](https://osculator.net/) * [VRPN](https://github.com/vrpn/vrpn/wiki) * [vJoy](http://vjoystick.sourceforge.net/site/) All of these programs take input from various devices and translate them as some other kind of input, or aggregate them to make systems easier to use. The Buttplug Protocol aims to define programs which do something similar. Applications referred to as "Buttplug Server" implementations will often look quite similar to these programs. ## Why is it called Buttplug? It probably seems silly to call a generic device control standard "Buttplug". That's because silly is the point. I could probably call this project something neutral like Sex Device Control Protocol (SDCP?), but I've been referring to computer controlled sex devices as "Internet Buttplugs" for years, and that's what influenced the name of this project. It's hard to pick terms for these products. * "Sex toy" is weighed down by the word "toy". This is part of the reason the academic and tech community is flocking toward "sex robot" even when discussing technology that would've been called a sex toy a decade ago. * "Sex robot" has way too many connotations, be it Cherry 2000 or robotics academics writing media-friendly PhD theses. * "Sex device" is used in this document, but feels awkward for reasons I'm still figuring out. * "Adult novelty" just sounds stale and corporate. You buy adult novelties in bulk from warehouses. You go to adult novelty conventions. * "Marital aide" No. I ended up with "Internet Buttplug" because everyone has a butt, and buttplug is a fun word to say. It's inclusive and humorous. I admit that it may confuse people when they're wondering why they're using something called Buttplug to control their fucking machine or robotic onahole or who knows what else. One of the hardest problems in Computer Science is naming things. I just stopped trying to name the thing and selected a name and here we are. Much like the other hard problems in Computer Science, I fully expect this to come back to bite me in the ass at some point. > **Tip: Just to make sure this is clear: THIS WORKS FOR MORE THAN BUTTPLUGS** Even though this project is called Buttplug, it does not mean you have to put something in your butt to develop with it or use applications that integrate it. We are not saying you shouldn't, as we condone butt stuff as performed in a safe and sane manner, but it's not a requirement, either. ## Why have a protocol specification? Why not just write some API docs like a normal developer? When I first started the Buttplug project in 2017, I was working on web browsers. This meant that I was already surrounded by specifications of different types, and therefore it seemed like the best way to define the way my system worked was via (a simplification of) that format. Much like browsers, I want other developers to be able to rebuild the system completely from documentation if at all possible. I don't really expect that anyone will do so, as, much like implementing a browser, the work required to implement the server side of the system is immense. Even so, this document should provide an up-to-date way to reimplement the base system if anyone actually does wish to do so. Most importantly, I just like putting fancy names on things that also include the word Buttplug. > **Tip: 2025 Updates** All that said, I've now taken a step back from calling this a _Standard_ to simply a _Protocol_ or _API_. Unlike a web browser, there hasn't been a lot of interest or need to reimplement the server side of Buttplug. While I do still need to provide documentation at the protocol level so people can create clients, there's not as much of a focus on letting people recreate the whole system. I'll still be providing enough information to do so, but I'm kinda done making it a selling point, especially since it brings expectations that take energy I don't have to maintain. --- ## InputCmd, InputReading, and InputType Getting data from devices is done via InputCmd. Within this message we encode all possible input information, making it simple to add new functionality. --- ## InputCmd **Description:** Sends a command to receive input of some type. For instance, the battery level of a wireless device, pressure readings from a sensor, axes of an accelerometer, etc... The features portion of the [DeviceList](device_information.md#devicelist) message contains information on the input type and description, ranges, and more. Due to the amount of different sensor contexts within toys, the corresponding InputReading message provides flexibility to add new input types without having to introduce new messages into the protocol. The values accepted as input types can be extended as needed. Additions of these types will be considered Minor Version bumps. In practice, InputCmd is meant to be exposed to developers via crafted APIs, i.e. having battery()/rssi()/subscribe(\[type\]) etc functions available on a data structure that represents a device feature, with the input types denoting which of those methods may be allowed. ### Sensor Units Are Not Standardized {#sensor-units-are-not-standardized} > **Warning** Hardware manufacturers do not provide standardized units for sensor readings. The Buttplug protocol cannot define measurement units (such as kPa for pressure, or specific temperature scales) because this information is simply not available from the devices. All sensor values are generic integers within the range specified in DeviceList. **Calibration and unit interpretation must be handled at the application level.** **Introduced In Spec Version:** 4 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _FeatureIndex_ (unsigned int): Index of feature * _Type_ (InputType): The type of input we expect to receive from this feature. Battery, Rssi, etc... * _Command_ (InputCommandType): One of 3 values: `Read`, `Subscribe`, `Unsubscribe`. Which of these types are available to a feature is transmitted as part of the DeviceList info. **Expected Response:** * Read * InputReading with matching Id on successful request * Subscribe/Unsubscribe * Ok message with matching Id on successful request * Error message on value/message/device error. > **Tip: Subscription Lifecycle** - **Unlimited concurrent subscriptions**: A client may have any number of active subscriptions across different devices and features - **Duplicate subscriptions are ignored**: If a client sends a Subscribe command for a feature it is already subscribed to, the request is acknowledged with Ok but no additional subscription is created - **All subscriptions stop on disconnect**: When a client disconnects (gracefully or otherwise), all of its active subscriptions are automatically cleaned up by the server **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: InputCmd (Read) Id=1 Server->>-Client: InputReading Id=1 ``` ```mermaid sequenceDiagram Client->>+Server: InputCmd (Subscribe) Id=1 Server->>-Client: Ok Id=1 Server->>-Client: InputReading Id=0 Server->>-Client: InputReading Id=0 Server->>-Client: InputReading Id=0 Client->>+Server: InputCmd (Unsubscribe) Id=2 Server->>-Client: Ok Id=2 ``` **Serialization Example:** ```json [ { "InputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 1, "Type": "Battery", "Command": "Read" } }, { "InputCmd": { "Id": 2, "DeviceIndex": 1, "FeatureIndex": 0, "Type": "Pressure", "Command": "Subscribe" } } ] ``` --- ## InputReading **Description:** InputReading contains data received from a device input, either after a read request or as part of a stream of readings from a subscription. This can be anything from battery power levels, to radio signal strength, to pressure readings. Expected dimensionality and format is set via the corresponding InputCmd definition in the DeviceList messages. **Introduced In Spec Version:** 4 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _FeatureIndex_ (unsigned int): Index of feature * _Reading_ (InputData): Data from the input, including InputType and the corresponding format. See InputType table below for more information on expected data types. **Expected Response:** * None, message is Server -> Client only **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: InputCmd (Read) Id=1 Server->>-Client: InputReading Id=1 ``` ```mermaid sequenceDiagram Client->>+Server: InputCmd (Subscribe) Id=1 Server->>-Client: Ok Id=1 Server->>-Client: InputReading Id=0 Server->>-Client: InputReading Id=0 Server->>-Client: InputReading Id=0 Client->>+Server: InputCmd (Unsubscribe) Id=2 Server->>-Client: Ok Id=2 ``` **Serialization Example:** ```json [ { "InputReading": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 1, "Reading": { "Battery": { "Value": 50 } } } }, { "InputReading": { "Id": 0, "DeviceIndex": 1, "FeatureIndex": 0, "Reading": { "Pressure": { "Value": 200 } } } } ] ``` --- ## InputType InputType denotes data that a device should provide back to us, via some sort of sensor. It also corresponds to the format of the data we will receive in the InputReading message. > **Tip: Possible Upcoming Input Types** While sensor input has been in Buttplug since the v2 spec in one way or another, it's never been built in an expandable way until now. We're keeping things low key for the first release as we figure out how this is going to work, but future input types may include: - Accelerometer (1-axis and 3-axis) - Gyro - Temperature - Depth/Distance - If you have other ideas, let us know! ### Battery **Introduced In Spec Version:** 4 **Description**: Battery level for a device. A percentage between 0-100. **Device Examples**: Anything with a battery we can read. A fair amount of bluetooth devices support this, as do XBox controllers. > **Tip: No Charging State** The Battery input type reports only the current charge level, not whether the device is currently charging. This is intentional: devices with rechargeable batteries are assumed to be non-functional while charging for safety reasons. If a device is connected and reporting battery level, it is assumed to be running on battery power. **Fields** - Value - **Type**: Unsigned 8-bit integer - **Description**: Percentage, will always be 0-100. **Example**: ```json [{ "InputReading": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 1, "Reading": { "Battery": { "Value": 50 } } } }] ``` ### Rssi **Introduced In Spec Version:** 4 **Description**: RSSI level of a wireless radio device. This is encoded as _Rssi_ to handle the way most implementation languages expect class casing. **Device Examples**: This is a feature of Bluetooth, rather than devices. Should technically work for any bluetooth device. **Fields** - Value - **Type**: Signed 8-bit integer - **Description**: Always a negative, usually somewhere between -10 and -100 **Example**: ```json [{ "InputReading": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 1, "Reading": { "Rssi": { "Value": -53 } } } }] ``` ### Pressure **Introduced In Spec Version:** 4 **Description**: Pressure level from a sensor **Device Examples**: Usually a kegel sensor, like a Kgoal Boost, perifit, Edge-o-matic, etc... Units will differ greatly between devices and will require per-application calibration. See dev guide for more info. **Fields** - Value - **Type**: Unsigned 32-bit integer - **Description**: Pressure level of the sensor. We don't have a standard unit for this, so it will vary from product to product. See dev guide for more info. **Example**: ```json [{ "InputReading": { "Id": 0, "DeviceIndex": 0, "FeatureIndex": 1, "Reading": { "Pressure": { "Value": 1252 } } } }] ``` ### Button **Introduced In Spec Version:** 4 **Description**: A digital button on a device. **Device Examples**: Any device that has buttons we can read. For instance, the Kiiroo Keon has readable buttons. This is NOT MEANT TO BE USED FOR ANYTHING ACCESSIBLE VIA HID, please use HID libraries for that. Please don't route your gamepad through buttplug unless your gamepad also goes on/in genetalia or butts. **Fields** - Value - **Type**: Unsigned 8-bit integer - **Description**: 1 for down, 0 for up **Example**: ```json [{ "InputReading": { "Id": 0, "DeviceIndex": 0, "FeatureIndex": 4, "Reading": { "Button": { "Value": 1 } } } }] ``` --- ## Messages Messages are the core object for Buttplug communication. How messages are represented depends on the implementation in question. For instance, in a C\# library implementation of Buttplug, messages are classes. In Rust, they're structs. This is an implementation detail left up to the client library developer. In a server implementation, messages need to be serialized in some way to be sent between the client and server. In this case, they may exist in some sort of intermediate format, like JSON, ProtoBuf, or CBOR. ## Basic Message Structure Messages are made up of multiple different kinds of fields. As long as the fields can somehow be represented in JSON, we consider them valid. All messages will contain an "Id" field. This field as the range of 0 to 4294967295. A value to 0 denotes a _System_ message, meaning a message that will only ever be sent from a server to a client. All messages coming from a client will have an Id from 1 to 4294967295, as set by the client themselves. When the server replies to the message, it will return a message using the same Id as was sent. This allows developers to synchronize messages over remote systems like networks, or languages that lack async/await capabilities. Other than range, there is no restriction to what values the client can send as an Id. The Id does not need to be sequential, nor does it need to be unique. The client could just send 1 for every message, which would be valid in async/await library situations where the execution flow would handle matching message pairs without the need for the Id. In remote situations, like those over network connections, it is expected that the client will establish a sane usage of the Id field to orchestrate messaging. > **Warning: Message Ordering Is Not Guaranteed** The Buttplug protocol does not guarantee message ordering. Client-generated message IDs are used for matching requests to responses, not for ensuring execution order. If a client sends multiple commands in quick succession, the server will process them in the order received, meaning there could be inconsistencies due to network traffic, etc... As Buttplug is built to be run locally, clients can mostly assume ordering, but some exceptional cases, messages may be not executed in the order they were sent. ## Message Flow There are two types of message flows. * Messages can be sent from the server to a client. Messages like DeviceList, ServerInfo, and certain device specific input messages can happen without the client making a request. The server **will not expect a reply** from the client for these messages. * Messages sent from the client to the server **will receive a reply** from the server, unless a message explicitly documents a transport-level close without a reply, such as [Disconnect](identification.md#disconnect). The message type the client will receive in reply is based on the type of message sent. Some messages may receive a simple "Ok" message in reply in order to denote successful receiving, while others may receive something context specific. Messages reply types are listed in the message descriptions section. ## A Note On Scaling The Buttplug Message System, as described here, was not designed to scale to large multiuser systems \(like cam services\), nor was it designed for being a firmware level protocol to be run on sex toy microcontrollers. It was built with either a single user, peer-to-peer, or small group setting in mind. As the message flow section states, this system resembles a sort of half-assed-TCP mechanism. Using this system to drive large scale device control streaming services may require changes to this system. Reducing and rearchitecting this system for scaling is an exercise left to the developer. Either to implement, or to contract the Buttplug designers to build it for them. ## JSON Message Serialization For reference implementations of the Buttplug protocol, we use JSON for serialization. > **Tip: Why is the JSON format for Buttplug messages so weird?** The format of Buttplug json messages mimics the output from Rust's [serde-json](https://github.com/serde-rs/json) crate. This is due to the first implementation of Buttplug with working serialization being in Rust in 2016. The second, usable implementation of Buttplug happened in C# in 2017. The message structure was inherited from Rust, but the PascalCase named of messages and their fields was taken from C#. That is how we've ended up with the mess we're in now. There is most likely no language that will handle both the structure and capitalization scheme naturally, and the spec has been around for long enough that it is difficult to change. This is now just an accepted point of shared pain for anyone that wants to use this protocol. When sending messages over the line to a server/client, we wrap them in a JSON array, so that multiple messages can be sent and parsed simultaneously. The format is as follows: ```json [ { "MessageType" : { "MessageField1": "MessageValue1", "MessageField2": "MessageValue2" } }, { "MessageType2" : { "Message2Field1": "Message2Value1", "Message2Field2": "Message2Value2" } } ] ``` Message descriptions in this document will reflect this layout. Similarly, some message values will have certain bounds and limitations. These are described in this documentation, and are included in the JSON schema in this repo. ## Adding and Updating Messages The message list as described here is only set in stone for this version of the spec. New messages may be added as new devices with different capabilities are released, or as new generic messages are deemed necessary. The only rule is that once a message is added to this document, it may be deprecated but should never be removed completely from the document (though it may not be available in newer protocol versions), in order for backward compatibility to be implemented in servers. Newer versions of the message may succeed it. This will allow parsing and schema checking to be as strict as possible. If edits to a message need to be made, message names can be reused, as it is assumed the [Message Version](#message-versioning) acts as a namespace for messages. Any changes to the spec will also cause a spec version update (covered in the next section), which will need to be reflected across systems and implementations. So far, these updates have been rare. Requests for new messages can be submitted to [the Buttplug Github Issue Tracker](https://github.com/buttplugio/buttplug/issues). > **Tip: Version 0 Issues** Version 0 of the Message Spec was implemented without much thought for the future development of Buttplug. While very few client applications still exist for use with Version 0, backward compatibility implementation is possible. Spec Version 0 was listed as Spec Version 0.1.0 initially. Version 0 of the [RequestServerInfo](identification.md#requestserverinfo) message does not have a parameter for protocol version. It is assumed that any [RequestServerInfo](identification.md#requestserverinfo) message received without a version number is from a Version 0 client, and should be communicated with at that spec level. ## Message Versioning To cope with protocol version differences between servers and clients, each protocol message type has a version number. The message version number is based on the protocol version the message was introduced in, and is represented as an unsigned integer. To establish protocol versions between clients and servers, the client sends the protocol message version as part of the [RequestServerInfo](identification.md#requestserverinfo) message (as the ProtocolVersionMajor/ProtocolVersionMinor fields), and the server includes its protocol version in the [ServerInfo](identification.md#serverinfo) response (as the same fields). ### Major Version Differences If a server supports a newer major protocol version than a client, any messages that the server attempts to send will be checked against the client protocol version, and either downgraded to a previous version where possible, or simply dropped. Server support for downgrading a message is optional, and it is not expected that all servers will support downgrading through all versions of the protocol. If a server implementation does not have downgrade capabilities, it should disconnect clients with lower schema versions. If a client supports a newer major protocol version than a server, this is considered an invalid connection situation, and a disconnect should ensue. This rule is based on the assumption that the user can most likely update the server version to something newer. The client may not be easily upgraded for many reasons, such as being a proprietary application or source code not being easily accessible, being too complex to work on and upgrade, etc... ### Minor Version Differences As of Spec v4, the Buttplug Protocol now supports Minor Versions. These denote additive differences in `OutputType`/`InputType`, optional fields, and possibly new Client -> Server message capabilities. If a server supports a newer minor protocol version than a client, the connection may continue as long as the major version matches. The client should ignore any `OutputType`/`InputType` features and optional fields it does not understand. Servers must not require clients to use newer-minor messages or fields for behaviour that already existed in the client's minor version. If a client supports a newer minor protocol version than a server, the connection may also continue as long as the major version matches. The client must treat the server's `ProtocolVersionMinor` from `ServerInfo` as the negotiated capability level, and must not send Client -> Server messages, command types, fields, `OutputType`s, or `InputType`s introduced after that minor version unless the server has explicitly advertised support for them. If it does, the server should treat the message as an unsupported or malformed message and return an `Error`. --- ## OutputCmd and OutputType Controlling devices is done via OutputCmd. Within this message we encode all possible output information, making it simple to add new functionality. --- ## OutputCmd **Description:** Sends a command to an output of some type. For instance, the vibration speed of a vibrator, the oscillating speed of a non-position-based fucking machine, positions with durations to strokers, etc... The features portion of the [DeviceList](device_information.md#devicelist) message contains information on the output type, feature description, value ranges, and more. Due to the amount of different value contexts within haptics (vibration speed, oscillation speed, inflate/constrict pressures, etc), this message provides flexibility to add new actuation types without having to introduce new messages into the protocol. The values accepted as output types can be extended as needed. Additions of these types will be considered Minor Version bumps. In practice, OutputCmd is meant to be exposed to developers via crafted APIs, i.e. having vibrate()/rotate()/oscillate() etc functions available on a data structure that represents a device feature, with the output types denoting which of those methods may be allowed. OutputCmd itself can be exposed via API also, but this may lead to a lack of attention to context that could cause issues (i.e. someone driving a vibrator and a fucking machine with the same power signals). Mitigation for that type of issue may be UX related versus system/protocol related, by letting users set speed limits and ranges for devices. > **Tip: What happened to Subcommands?** In Buttplug Spec v1-v3, our generic commands took multiple "subcommands", allowing developers to send updates to multiple features in the same message, possibly for update at the same time. Building APIs for messages in this format was a nightmare, so the feature was either ignored or turned libraries into a complete mess of multiple call types per output type (depending on if all features should be set to the same value, or different values, etc...). Also, developers were never actually aware if devices _needed_ multiple features updated at the same time, or if they'd send one message per device update. This information is in the protocol, which is hidden from the Client level. Subcommands added complexity without any benefit. As of v4, we move to 1 command per message. This will now require extra logic in the server, in order to bundle commands that come in quick succession if a protocol allows it so we can reduce messages. The removed complexity for client/app developers easily provides return on investment for the added server side logic though. **Introduced In Spec Version:** 4 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int): Index of device * _FeatureIndex_ (unsigned int): Index of feature * _Command_ (OutputCommand): An object representing the output command. This denotes both the context of the command as well as the value. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value/message/device error. > **Tip: Device Disconnect During Command** If a device disconnects while a command is being processed, the server will return an Error message. The exact error depends on the connection system the device uses (Bluetooth, USB, etc.), but will typically be an ERROR_DEVICE with a message indicating the disconnect. Clients should handle this gracefully and update their device state based on the subsequent DeviceList update from the server. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: OutputCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Vibrate": { "Value": 10 } } } }, { "OutputCmd": { "Id": 2, "DeviceIndex": 1, "FeatureIndex": 0, "Command": { "HwPositionWithDuration": { "Value": 91, "Duration": 150 } } } } ] ``` --- ## OutputType OutputType denotes a thing that a device feature does to a user. Think of it like a verb, possibly with an added bit of context. Output command values are integers. Unless an OutputType says otherwise, a command value is valid if it falls within the inclusive _Value_ range advertised for that OutputType in DeviceList. ### Vibrate **Introduced In Spec Version:** 4 **Description**: Sets a vibrator speed to a certain amount. 0 always denotes stop. Valid speeds are within the _Value_ range advertised in DeviceList, usually `[0, x]`. **Device Examples**: It's... vibrators. Just vibrators. If you're using this library you are probably familiar with Vibrators. Buttplug's device support is probably 90% vibrators, so this will be used more than any other OutputType. The one thing to note here is that this is mostly assuming Off-axis/Eccentric Rotation Motor (ERM) vibrators. LRA/Voice Coil based vibrating sex toys do exist, but are rare, and can still usually be controlled with this command. **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Vibrator speed **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Vibrate": { "Value": 10 } } } }] ``` ### Rotate **Introduced In Spec Version:** 4 **Description**: Sets a rotator speed to a certain amount. 0 always denotes stop. If the advertised _Value_ range is `[0, x]`, positive values rotate in the device's default direction. If the advertised _Value_ range includes negative values, positive values denote clockwise rotation and negative values denote counterclockwise rotation. **Device Examples**: Lovense Flexer, several Joyhub devices, Lovense Nora, Motorbunny Classic, Nexus Revo, Vorze UFO SA, Cyclone SA **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Rotation speed and direction **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Rotate": { "Value": 10 } } } }] ``` ### Oscillate **Introduced In Spec Version:** 4 **Description**: Sets an oscillator speed to a certain amount. It is assumed we cannot control the start/end oscillation points for this feature, and that we are just controlling the speed between those two points. 0 always denotes stop. Valid speeds are within the _Value_ range advertised in DeviceList, usually `[0, x]`. **Device Examples**: Hismith Fucking Machines, Lovense Fucking Machine, Lovense Gravity, etc... **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Oscillation speed **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Oscillate": { "Value": 10 } } } }] ``` ### Constrict **Introduced In Spec Version:** 4 **Description**: Used for pumps and squeezing devices. Usually sets a constriction to a level, though whether or not that level is held until next setting can vary per device. 0 always denotes full release. Valid levels are within the _Value_ range advertised in DeviceList, usually `[0, x]`. **Device Examples**: Lovense Max, Svakom Sam Neo 2 **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Constriction level **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Constrict": { "Value": 10 } } } }] ``` ### Spray **Introduced In Spec Version:** 4 **Description**: Controls spray/ejaculation mechanisms on devices that support this feature. 0 always denotes off/no spray. Valid levels are within the _Value_ range advertised in DeviceList, usually `[0, x]`. For the moment, this is expected to be an instantaneous command; value is in relation to power, not timing. **Device Examples**: Hismith Lube Injector, Joyhub toys with squirting mechanisms, Bluetooth-Capable Glade Plugins **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Spray intensity **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Spray": { "Value": 5 } } } }] ``` ### Temperature **Introduced In Spec Version:** 4 **Description**: Controls temperature for devices with heating or cooling elements. The value range is signed to support both heating (positive values) and cooling (negative values), with 0 denoting neutral/off. It will be vanishingly rare that we have information about the exact temperature a device can reach, so this will normally be some number of "temperature steps" rather than degrees (see [note on sensor units](./input#sensor-units-are-not-standardized)). Valid commands are within the _Value_ range advertised in DeviceList, which may be `[-x, x]` for devices supporting both heating and cooling, or `[0, x]` for heating-only devices. **Device Examples**: N/A **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Temperature level. 0 is neutral/off, positive values indicate heating, negative values indicate cooling. **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Temperature": { "Value": 2 } } } }] ``` ### LED (Encoded as Led) **Introduced In Spec Version:** 4 **Description**: Sets the brightness value of an LED. If Value maximum is 1, can be considered to simply be an off/on switch. Different color LED control (for RGB devices) will show up as multiple LED features, with color in the feature description. 0 always denotes turning off the LED. Valid brightness values are within the _Value_ range advertised in DeviceList, usually `[0, x]`. This is encoded as _Led_ to handle the way most implementation languages expect class casing. > **Tip: Why is this Led and not LED?** Because a LOT of programming languages hate multiple capital letters next to each other in container names, so we just call it Led. Remember, this is just the line protocol, you can call it whatever you want in your client API methods. **Device Examples**: Lovense Domi **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Brightness **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Led": { "Value": 10 } } } }] ``` ### Position **Introduced In Spec Version:** 4 **Description**: Command device to move to a certain position as quickly as possible, aka servoing. Should only be used for very small movements at a time, and in most cases is expected to run at a maximum update rate for the device. There is no _Stop_ handling for a position movement, as it is expected to move then stop quickly. **Device Examples**: Various axes of the OSR-2/SR-6/SR-1 systems, including the stroker as well as twist/pressure cap/etc mechanisms, possibly other strokers like the Kiiroo Keon or Lovense Solace Pro but with less accuracy than wired devices. Not sure if there's a way to do this with The Handy. **Fields** - Value - **Type**: Signed 32-bit integer - **Description**: Position to servo to **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "Position": { "Value": 10 } } } }] ``` ### HwPositionWithDuration **Introduced In Spec Version:** 4 **Description**: Command device to move in a linear ramp to a goal position over time. There is no _Stop_ handling for position with duration movement, as it is expected to move to its end and stop, usually within a few seconds. The "Hw" (meaning "hardware") prefix denotes that, in almost all cases, processing of this command is handled by the hardware itself, and Buttplug has little-to-no say in the control loop involved in moving the device outside of sending the command to do so. **Device Examples**: Various axes of the OSR-2/SR-6/SR-1 systems, including the stroker as well as twist/pressure cap/etc mechanisms, other strokers like the Kiiroo Keon, Lovense Solace Pro, or The Handy. **Fields** - Value - **Type**: Unsigned 32-bit integer - **Description**: Position to move to over \[duration\] time, valid settings are within the advertised _Value_ range - Duration - **Type**: Unsigned 32-bit integer - **Description**: Duration in milliseconds for move to new goal position, valid settings are within the advertised _Duration_ range **Example**: ```json [{ "OutputCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 0, "Command": { "HwPositionWithDuration": { "Value": 85, "Duration": 15 } } } }] ``` --- ## Status Messages Messages relaying different statuses, including communication statuses, connection (ping), log messages, etc... --- ## Ok **Description:** Signifies that the previous message sent by the client was received and processed successfully by the server. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): The Id of the client message that this reply is in response to. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StartScanning Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "Ok": { "Id": 1 } } ] ``` --- ## Error **Description:** Signifies that the previous message sent by the client caused some sort of parsing or processing error on the server. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): The Id of the client message that this reply is in response to, assuming the Id could be parsed. Id will be 0 if message could not be parsed (due to issues like invalid JSON). * _ErrorMessage_ (string): Message describing the error that happened on the server. * _ErrorCode_ (int): Integer describing the error. * 0: ERROR\_UNKNOWN - An unknown error occurred. * 1: ERROR\_INIT - Handshake did not succeed. * 2: ERROR\_PING - A ping was not sent in the expected time. * 3: ERROR\_MSG - A message parsing or permission error occurred. * 4: ERROR\_DEVICE - A command sent to a device returned an error. > **Tip: Error Codes Are For Logging, Not Recovery** Most Buttplug errors are unrecoverable at the protocol level. Error codes are primarily intended for logging and user notification, not for programmatic recovery. For example, ERROR\_DEVICE may indicate a device disconnected, a command was invalid, or the device itself returned an error - all of which typically denote an issue with the client or application, or require user intervention, rather than automatic retry logic. **Expected Response:** None. Server-to-Client message only. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: InvalidMsgName Id=2 Server->>-Client: Error Id=2 ``` ```mermaid sequenceDiagram Client->>+Server: InvalidMsgId Id=Wat Server->>-Client: Error Id=0 ``` **Serialization Example:** ```json [ { "Error": { "Id": 0, "ErrorMessage": "Server received invalid JSON.", "ErrorCode": 3 } } ] ``` --- ## Ping **Description:** Ping acts a watchdog between the client and the server. The server will expect the client to send a ping message at a certain interval (interval will be sent to the client as part of the identification step). If the client fails to ping within the specified time, the server will disconnect and stop all currently connected devices. If the server reports `MaxPingTime` as 0 in `ServerInfo`, the server does not require Ping messages. This will handle cases like the client crashing without a proper disconnect. This is not a guaranteed global failsafe, since it will not guard against problems like a client UI thread locking up while a client communication thread continues to work. **Introduced In Spec Version:** 0 **Last Updated In Spec Version:** 0 **Fields:** * _Id_ (unsigned int): Message Id **Expected Response:** * Ok message with matching Id on successful ping. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: Ping Id=5 Server->>-Client: Ok Id=5 ``` **Serialization Example:** ```json [ { "Ping": { "Id": 5 } } ] ``` --- ## Stop Messages Possibly the most important messages in the system, stop messages stop connected devices from doing whatever they are currently doing. **All devices support StopCmd, and this message is not included in device capabilities lists in DeviceList.** --- ## StopCmd **Description:** Client request to have the server stop all devices, a device, or a feature on a device from whatever actions it may be taking. This message should be supported by all devices, and the server should know how to stop any device or feature it supports. Optional index fields allow for stopping all features or devices. **Introduced In Spec Version:** 4 **Last Updated In Spec Version:** 4 **Fields:** * _Id_ (unsigned int): Message Id * _DeviceIndex_ (unsigned int, optional): Index of device to stop. If not included, all devices are stopped. * _FeatureIndex_ (unsigned int, optional): Index of the feature on the device to stop, assuming as device index is specified. If no device index is specified, feature index is ignored (as it does not make sense to stop "all features of index 1 across all devices") * _Inputs_ (boolean, optional, default true): If true, unsubscribe subscribed inputs based on index selection. * _Outputs_ (boolean, optional, default true): If true, stop outputs based on index selection. **Expected Response:** * Ok message with matching Id on successful request. * Error message on value or message error. **Flow Diagram:** ```mermaid sequenceDiagram Client->>+Server: StopCmd Id=1 Server->>-Client: Ok Id=1 ``` **Serialization Example:** ```json [ { "StopCmd": { "Id": 1, "DeviceIndex": 0, "FeatureIndex": 3, "Inputs": true, "Outputs": true } } ] ``` ```json [ { "StopCmd": { "Id": 1, "Inputs": true, "Outputs": true } } ] ``` --- ## Foreword A few words from the author of this guide and architect of Buttplug. ## Wants and Needs Before we jump into all of the descriptions and eccentricities and whatnot that make up Buttplug, let's start with a parable. Have you ever bought a new thing you've been really excited about, but then it turns out that it didn't work as expected for you? Maybe used some software or played a game that almost gets there but doesn't quite work for you? Here's a story from my days as a virtual world developer, about what this situation looks like from the designer's side. ## I Want To Be A Shirt "I want to be a shirt." "A what?" "A shirt." "Like, you want a shirt with a picture of you on it or something? You can already do that you know." "No. I want to *be* a shirt. I want to exist as the piece of clothing. That piece of clothing should be a shirt. I get off on the idea of being a shirt. It has been a dream of mine and we're here for dreams, right?" Having just spend a non-trivial amount of time lovingly crafting a new type of genitals, with all sorts of bits and bobs and extras, the last thing you want to hear is that your creation is not appreciated. Building something like this that does everything it's supposed to AND communicates across multiple dimensions is not easy, and yet, according to this critic, it has completely missed the mark. "Why do you want to be a shirt? How would this be better than having some new genitalia? Look, it even vibrates when you poke it like this!" "Well, yes. That's very good. It even goes all red and bulgy, a nice touch. But… I don't know. It's just always been a thing I've wanted to be. I would much rather fulfill my needs via being a shirt, than to graft on some new body part I'm not even sure I'd be in to." "And you want people to wear you?" "That'd be the idea, yes." Damnit. Damn. It. Everyone was supposed to want one of these new body parts, what with the sounds and the arousals and the thrustings and the juices. Sure the inter-dimensional communication part would be a tough sell due to the learning curve, but once everyone caught on, it'd be a new paradise. That was the plan, and it'd be awesome, and popular, and there would be much rejoicing. Yet, here we are. "But you can't be a shirt." "Why can't I be a shirt?" "Because that would violate laws. A lot of laws." "What? It's not illegal to be a shirt anywhere that I know of." "Not like, legal laws. Physical laws. Laws of existence." "But don't you control those kind of laws? Or don't some of the others like you have that power?" DAMN. IT. Note to self: never create worlds that can contain anything capable of making a good point. "I suppose we kind of do? But if I change those laws for you, I have to change them for everyone, and I don't think everyone wants to be a shirt. Or pants. Or a shoe. Much less to derive gratification from being any of those." "Why wouldn't other people want to be shirts? There's so many possibilities. I would be a continual soft hug. I would adorn the wearer and make them look nice. I would absorb their sweat." "We didn't give you sweat glands. How would you even pull that off?" "I'd find a way. We've got our own tools down here too, you know. They're just not powerful enough to let me be a shirt." "Yeah there's a reason for that. What about if you tried to… Ugh, is there even a verb for this? What if you tried to… shirt someone and they didn't know you were a living shirt or whatever it is you're asking for here. Think about the security issues." "I think it'd be pretty obvious 'cause I'd be talking." "Oh so you want to be a TALKING shirt? Anything else on this list of demands?" "Ability to change cloth type? I'd want to stay current with the trends." "Forget I asked. And besides, not everyon… everyshirt would talk. We already have to deal with enough chaos around here without adding 'Non-consensual shirtings' to our list." "Hey, you're the one building this world. You wanted feedback on how to do that, and I'm giving it to you." "You are the worst focus group." "You randomly asked the first person you saw. Blame fate, not me." A quiet voice pops up from a few yards, or miles, over. Scale is difficult when you're looking down from above. "If they get to be a shirt can I be a cube?" Fuck. ## Ceci n'est pas un Buttplug The preceding story actually happened. Sure, it was in the context of the Second Life virtual world, and the narrator (me) was less god and more employee, but the events happened as stated. Someone really wanted to be a shirt, and due to the constraints of the software, it couldn't happen. This was despite me, as a software engineer (who before being hired, had made real life sex toys work with Second Life) having the ability to control the virtual world, albeit in a manner limited by software development time, project specifications, and other obstacles both gods and engineers have to deal with. There are a lot of people out there that want to be shirts, at least, in the terms of this horribly tortured metaphor. They've bought a sex toy, and the interface provided to them to control it doesn't work for them for some reason, or the content isn't to their liking. Buttplug (the software, not the sex toy genre) was created for that situation. Buttplug is nothing without interface applications. The only real function of Buttplug is make it easy for developers to get computers to talk to sex toys. The software those developers make will use Buttplug to talk to the sex toys. Interface applications are the link between users and Buttplug, establishing the functionality the user was missing. Application developers, those making the interfaces, are the shirt makers (and thus, the metaphor is dead). There are a many considerations, both technical and social, that need to be kept in mind when creating applications that will interact with sex toys. It is assumed that the sex toy will be somehow attached to a person, who will most likely be engaged in the act of sexing. This is not a situation normally covered in user interface design or software/hardware engineering textbooks. It is impossible to outline all of the relevant situational use cases. The goal of this document is to provide a framework by which design decisions about specific application needs can be informed. Building, releasing, and using software with the kinds of contexts that are inherent in Buttplug involves risks. This document is what I've learned so far about sex toy control and interface design, and how to apply that when using or developing for Buttplug. It contains the lessons I've learned over the years so far, and will be the home for lessons learned in the future. ## Why Do I Need You To Tell Me Where My Butt Is But who am I and why does my view on this information matter? Probably should've led with that, huh. Well, um, hi, I'm qDot (aka Kyle Machulis), lead architect of Buttplug. Since 2004, I've been researching and blogging about sex tech (via the now defunct [metafetish.com](https://metafetish.com)). I've followed online communities, talked to hundreds of people involved in many different activities, fetishes, and interests, and built many experiments to try to figure out if/how/why technology will/won't work in situations presented to me. The information presented here comes from over 2 decades of my amateur research on the sex technology field, from the engineering and user interface perspective. While I strive to provide as much help and information as possible, I am an engineer, not a sexologist, psychologist, sociologist, ethicist, or one of those other -ists that deals directly with people and people issues. It is well known that engineers may not be real great at "people" (to put it lightly). With that in mind, I've tried to consult with many people that are those aforementioned -ists while building this software and writing this document. This project was by no means done alone, nor could it have been done alone to a quality I would've been satisfied with. Thanks to everyone who's helped out so far, it's much appreciated. Together we've put together a project that thousands of people mildly tolerate daily because there aren't many other options. When writing sex software, it's rather hard to avoid dealing with people, unless the software is never actually used. While the engineering portions of this document will be as rigorous as possible, many of the observations about users and usage examples will be from my personal experience. These are by no means complete studies. All stories and examples presented are anecdotal at best, and complete fabrications at worst. Building this project has been a weird, great, weird journey. I hope Buttplug helps you with whatever your wants and needs may be. --- ## Quick Start As a potential Buttplug Developer, the first thing you should do is... **BE A BUTTPLUG USER!** This means becoming familiar with [Intiface Central](https://intiface.com/central), the application that the users of your apps and games involving Buttplug will use to manage and connect to their hardware. Before embarking on the developer guide, I highly recommend reading the [Intiface Central Quickstart](https://docs.intiface.com/docs/intiface-central/quickstart) and going through the steps to set up the application. Much of this developer guide assumes you'll be connecting examples (and later, your own apps) to [Intiface Central](https://intiface.com/central), so it's good to be familiar with it up front. After you've done that, continue on to the [Intro](intro/introduction.md) and [Architecture](architecture/intro) sections (or [Sticking Buttplug In](writing-buttplug-applications/intro) if you're really in a hurry). # But where's the code? For anyone expecting a quick code example here: Yeah no this is a guide to working with software that people will use to control hardware they put on or in their own bodies. Take some time to understand how all this works and what you're doing. --- ## Buttplug Developer Guide A design and development guide for the Buttplug Intimate Device Control System. By [qDot (Kyle Machulis)](https://kyle.machul.is/about), Lead Buttplug Architect The Developers Guide Repo is [available on github](https://github.com/buttplugio/docs.buttplug.io/tree/master/docs/dev-guide). --- ## Butts Are Difficult > "… Society has put a lot of evils in our brains that we need to transcend before we make out." > > [Cex - Not Trying](https://youtu.be/ONi7QwYNQz4) No, really. For as much fun as butts and their surrounding body parts can be, applying technology to them is just a nightmare of conflicting issues and requirements and considerations that's absolutely exhausting to think about for too long. So I'll try to keep this short. Before we delve into what Buttplug is from the technical side, I'd like to take a minute to think about it from the social and ethical side. It's impossible to solve everything that may come up when using this library in a single page of a developer guide (it'd still be a tall order at a million pages. Thank Turing and his infernal machines for that), but I can at least go over a few things to think about while developing sex tech apps, other than whether your threads are deadlocking or memory is leaking. ## Empathy for the User Having Sex With Your Software Let's start with the user of the software you're about to create. When working on Buttplug applications, something that should be at the forefront of your design thinking is: > Someone is going to fuck this. The context of this usage should influence all levels of design, from UI/UX to low level code decisions. Assuming the user will approach a piece of software that involves Buttplug in the same way they would, say, a word processor, will end up in a fuckable word processor. If that's what you were aiming for, great, but otherwise this will just end up in a frustrated user and something that looked like a cat walked across the keyboard. As you build projects using Buttplug, ask yourself questions that the user will encounter: - Could I use this while turned on? - If I'm REALLY turned on, how long does it take for me to go from "I wanna use this" to "I am using this"? - What happens if my hardware disconnects? - Do I have a quick way to stop whatever the hardware may be doing? - Can I control this while possibly covered in [lube or other things]? Since Buttplug programs are meant to be sexual, there's a good chance the user *won't* be considering these questions before embarking on whatever technical adventure you've implemented for them. Therefore it's your job to think about these issues first. ## Github After Dark Developing sex software isn't a practice with much best practices or documented history or even a community of developers willing to admit they'd do such a thing. While we hope to change all of those with this library, that's going to take time. In order to gain acceptance in larger software communities, we hope to share our code in public forums, such as GitHub. These hopes have to be tempered by the issues of the general sterility of software, though. GitHub, StackOverflow, Glitch, and other community sites were not really made with NSFW content in mind. While there are certainly "adult" projects on GitHub in the form of porn site scrapers, adult games, and other applications, it's still not the norm by any means. How you present your sex software project as the community grows could end up setting standards for how services deal with NSFW code projects in the future. Most of the code in Buttplug library isn't extremely explicit, but applications implementing Buttplug may be. Be careful with anything involving media assets that may be deemed inappropriate for certain age groups, especially on sites that don't allow search removal or age checking. Self hosting is always an option for projects involving sensitive materials. If you would like to use a project site for Buttplug work, and they don't have an obvious policy stating how they might feel about their site being used with sensitive materials, it may be in your best interest to contact them. If you don't feeling comfortable handling this yourself, feel free to [file an issue on the main Buttplug repo](https://github.com/buttplugio/buttplug/issues) and we'll be happy to reach out and discuss. The Core Buttplug Developer Team has communicated with services in the past to figure out best practices for hosting sensitive code content, and the outcomes are usually positive. Additionally, we highly recommend that any open source or community project using Buttplug should also have a Code of Conduct. While there have been many lively discussions on projects like databases and kernels adopting CoCs, there are some very concrete contextual reasons to have them for sex software projects. This rings especially true if it is a project that may involve some sort of generic, multiple-community/interest use. For instance, let's say someone is writing an audio player/movie player that controls sex toys with Buttplug. A massive variety of media could be fed into this application, and there is a good chance that media used by some users may be found offensive by others. These user groups will still need support, and may possibly be sharing the same issue/bug tracker for their needs. Having a CoC in place guides moderation of situations where interests may conflict. As for which CoC to use (if looking for a prewritten one), you can [check out ours](https://github.com/metafetish/metafetish-project-docs/blob/master/CODE_OF_CONDUCT.md) as an example. It's really just a slightly modified version of the [Contributor's Covenant](https://www.contributor-covenant.org/). Using stock CoC's on sex software projects can prove difficult due to rules about "appropriate wording", due to the sexually explicit context of the project itself. Addendums or rewording may be required, though we do recommend being cautious in how these are presented. We welcome discussion of these issues on [our message boards](https://metafetish.club) or [discord server](https://discord.buttplug.io). Finally, you should consider if and how you'll handle contributions to your project. Regardless of whether you're running the project under your own identity, through a pseudonym, or anonymously, you shouldn't expect your contributors to all make the same choice as you did. Be ready to consider situations where someone wants to contribute but may need to use an anonymous account to do so, or may want to use their real and/or well-known identity, and how that may affect the optics and upkeep of your project. ## Mistakes Will Be Made Now that we've covered users and services, let's focus on you, the developer. The theme here will be as it was in the other sections: Plan ahead. Making a mistake that ends in something like data loss or crashing programs is one thing, but with sex software, there's just as likely to be social/ethical problems around technically competent implementations. How you respond to these problems affects not only your project, but the field of sex tech in general. Isn't responsibility fun? This might seem like putting way too much burden on someone making a tiny vibrator app with a new interface, but context outweights technology here. Technology as applied to sex means people will concentrate on the sex more than the technology when discussing the topic. This is why security breaches in commercial sex tech seem extra bad, even if they may impact far fewer users than a large, non-sex related technical service being hacked. As it goes with larger companies, so it will go with smaller projects. A small project that makes some sort of mistake around sex tech may still see more fire than, say, someone's reimplementation of an algorithm or database or something. Social context matters. Does this means you shouldn't develop for sex tech? Absolutely not. It just means you should treat it with more caution and planning than you might normally for less "interesting" software projects (and for everyone thinking "but most software is devoid of usage context and could be perverted for whatever reason!", yes I get it but I want to keep this section short, remember? So just go with it here.). As you'd think your design through for your users based on the criteria from the first section of this section, think your design through for yourself too. What is it you want to be responsible for with the software you're releasing? What do and don't you want your users to be able to do with it? Note that this list is malleable. You don't have to get it right the first time, and it doesn't need to be formally stated for most smaller projects. It can grow and change as your software grows and changes, but having the stated requirements will help both you and your users in case things ever "blow up". ## The Buttplug Mission Statement Buttplug isn't a "smaller" project though, so we do get to take on the formal statement. For Buttplug as a project, it felt best to sum up all of the information in this section as The Buttplug Mission Statement (written by someone far smarter than me after I said it far more verbosely and with a bunch of handwaving and probably some cursing). > Buttplug is committed to the safety, autonomy, and human rights of people using it as a sex technology standard, and stands in solidarity with the many intersectional rights of all individuals to be sex positive. As such, Buttplug encourages individual empowerment through self-directed education, and responsible behaviors which are also respectful of the needs and the choices available to everyone. Getting the paragraphs in this section (plus a bunch of stuff not covered) squeezed into an almost-tweetable chunk means using dense wording that may sound odd for a project named "Buttplug", but this is a Load Bearing Mission Statement. It has a lot to explain and contextualize in a small space, and it does what the project needs. As your project may be more specific than "abstract hardware controller", odds are you may not need something of this manner, but it's good to at least think about what you'd say to sum up what it is you're doing and why you're doing it, before you actually have to do so. ## Mo' Butts Mo' Problems This section, at best, should provide a framework about how to think about things as you develop your application. Your experience will be unique, and may require you to come up with your own strategies to continue development and distribution in a way that works for you and/or your community. If you have any suggestions, please feel free to reach out via the contact info on the home page of this document! I'd love to hear about how developers create and adapt tech as they need for their users. --- ## Getting Help If you have any questions about Buttplug that aren't answered by this guide, or if there's something you don't understand, please feel free to reach out to the community and library developers! There are multiple ways you can do this. - [Buttplug Discord Server](https://discord.buttplug.io) - This is your best bet for real time help! - [Buttplug Discourse Forums](https://discuss.buttplug.io) - If you prefer forums over discord, we've got those too! - [r/buttplugio subreddit](https://reddit.com/r/buttplugio) - Just in case you've already got a reddit account - Buttplug Social Media - We're on [Bluesky](https://bsky.app/profile/buttplug.io) and [the Fediverse](https://buttplug.zone/@buttplugio)! DMs are open, but replies may be slow. - [Issues on the Github Org](https://github.com/buttplugio) - The org is made up of many repos, so if you're asking about a specific implementation of Buttplug, its best to do so on that repo (but usually [buttplug](https://github.com/buttplugio/buttplug)). File an issue and we'll get things figured out. --- ## About This Guide The Buttplug Developer Guide covers a few different topics. - Architecture choices made in both the protocol and the implementations. - Using the library in applications. - Examples of different usage patterns. This guide should be considered **a way** to do things, but not **the (only) way**. The only invariant portion of Buttplug is the actual low-level protocol, as laid out by [the Buttplug Spec](../../spec). The libraries mentioned in this guide implement APIs on top of that protocol. Other developers are free to implement their own APIs as they see fit that use that protocol, and the system should still work as a whole. Chapters involving code will have interfaces similar to the one shown here. Changing the language choice on any example will change it on all examples in the project, so you can read using whatever language you're comfortable with. **Rust:** ```rust // This is some Rust let a = 1 + 2; ``` **C#:** ```csharp // This is some C# var a = 1 + 2; ``` **Javascript:** ```js // We use javascript for browser/web examples. We don't include the surrounding index/css to handle // UI, so it'll just be the included code file. // This is some Javascript let a = 1 + 2; ``` **Typescript:** ```js // For most of the examples in this guide, Javascript and Typescript will look mostly the // same, but we give typescript examples as our node/cli examples. Typescript typings files are // distributed with the library, so you should still get type completions in your IDE. // This is some Typescript let a = 1 + 2; ``` **Python:** ```python # This is some Python a = 1 + 2 ``` The guide tries to cover examples for implementations in all project maintained langauges. Due to variations in programming language features, there is a good chance that while all of the examples will achieve the same goal, they may do so in very different ways. Notes about language specific requirements and implementations will be included as comments in the examples for that language. > **Tip: What about when you see these blocks though?** When you see callout blocks like this, it usually means there's some additional information or anecdote about the project or current subject. Not required info, so it's not in the normal paragraph flow, but things that might be nice to know. ## What's in the Guide Obviously, reading the whole guide to find out what's in it is best. A lot of work was put into writing this, and the best way to appreciate that work is to read and savor every single word. However, based on feedback, apparently readers have "other things to do". With that severe disrespect in mind, here's a list of what you'll learn from each of the sections in this guide. * **Flared Basics** * Well, you're reading it already, so that's a good start. * Introduction to the library, and also gives a short runthru of the unique development and ethical issues you may run into when developing applications with Buttplug. * **Strategies Against Buttplug Architecture** * Recommended reading before diving into application development, even though you're probably excited and want to get right to it. I can't blame you, really. * Overview of the architecture of the system, including the low level protocol, common structures in the libraries, and a guide to how the implementations are built. * Glossary of terms that will be used in the application building portion of the system. * **Sticking Buttplug In** * If you want to start building software with Buttplug, no matter what the type, *AND YOU ALREADY READ THE ARCHITECTURE CHAPTER*, this is the chapter for you. * All about the Client side of Buttplug. Useful for those wanting to build applications that will connect to Buttplug Servers (which most people will know as Intiface Engine or Intiface Central). * **Winning Ways For Your Buttplug Plays** * After reading both the architecture and application chapters, this chapter presents different recipes for common library scenarios, including: * How to think about controlling different toy types * Building patterns for playback * General design frameworks for common applications (movie players, games, etc) * **Inflating Buttplug** * If there's something that Buttplug doesn't do that you want it to do, this chapter will be for you. * How to add things to the Buttplug Libraries, including: * Writing clients in new programming languages * Extending Buttplug Servers with new device types and communication busses * Implementing Buttplug servers (and mostly trying to convince you that you don't want to do this) * Adding new message to the Protocol Spec (and also trying to convince you that you want to think *really* hard before doing this) ## Other Reference Material Outside of this guide, there are a couple of other documents that may be handy to Buttplug Developers * [Buttplug Protocol Spec](../../spec) * The specification for the core of Buttplug, laying out how different parts of the system should communicate. This allows other developers to build their own version of the library if they so choose. This will be covered more in the architecture section. * [Sex Toy Protocols I Have Known And Loved (STPIHKAL)](../../../stpihkal) * An encyclopedia of different computer controlled sex toy and intimate device communication protocols. If you want to bypass Buttplug completely and just build your own interface, STPIHKAL gives you the low level information you'll need to control toys. --- ## Welcome to the Buttplug Dev Guide! Welcome to the Buttplug Developer Guide, your guide to developing applications with the Buttplug Intimate Hardware Control Library. By the time you finish reading this guide, you will be an expert in using the Buttplug protocol and libraries, and/or you will be very confused. ## What Even Is Buttplug? For the purposes of this guide, "Buttplug" refers to two things: - A system for enumerating, connecting to, and controlling intimate interaction hardware (sex toys, fucking machines, etc...). - Implementations of the aforementioned protocol in a specific programming language/environment, providing an API for developers to build applications on. "Buttplug" used alone usually refers to the system in the abstract, while "Buttplug [language]" (like "Buttplug C#") refers to the implementations of the system in a specific programming language (C#, in this case). Any point where the term "Buttplug" is used to refer to the toy type will be used as a subject without capitalization, i.e. "a buttplug" or "the buttplug". Hopefully that won't happen very often here though. ## So Does It Just Control Buttplugs? This is one of the most asked questions around the Buttplug project. The Buttplug project was built to control all sorts of hardware, not just buttplugs. As of this writing, implementations can control or read data from: - Gamepads - Vibrators (of all sorts, be it rabbit, buttplug, prostate, wand, etc...) - Strokers (single-axis as well as multi-axis) - Fucking Machines - Pressure sensors - The list is actually longer than this and changes constantly but I don't want to update it every time we add something so it's just like, a lot of stuff, ok? For the most up to date version, checkout [IOSTIndex](https://iostindex.com), the most comprehensive list of sex tech devices on the internet. There are filters that will allow you to see which devices are supported by the library. ## Why is the project called Buttplug? Some of the reasons the project is named Buttplug are: - A buttplug (the toy) is a non-gender-specific sex toy. Most everyone has a butt (though a butthole is another question entirely). Butts are inclusive. - Technology and the surrounding culture is far too sterile. Buttplugs, used correctly, are usually not. - It seemed funny at the time when the project was starting, even though no thought was put into how it would sound when being mentioned in press articles, grant applications, etc... - Upon further consideration and with some history behind it, that has made it even funnier. This list will also continue to grow over time, as I try and convince myself this was a good branding choice. --- ## Client Devices When a Client is notified by the server that a device has connected, it will create a Client Device instance. These instances are accessible by developers, and are how developers can control devices from the client. A Client Device contains: - The index of the device, an unsigned 32-bit integer that identifies the device to the server. This index will be unique per device. If a device reconnects it will usually use the same index, so it can be used to save configuration between sessions (though it may change if the user clears their server configuration). - The name of the device as present to the client. This may not always be the exact product name of the device, but acts as an identifier for the application user. - The capabilities of the device (For instance, can the device vibrate? If so, how many vibration motors does it have? How many levels of power do those motors have? Etc...) - An event emitter, for handling device disconnection/reconnection events, as well as emitting any sensor readings the device might receive (accelerometer, pressure, etc... depending on the hardware in question) Client devices are accessible through the client instance, and will generally live through the lifetime of the device connection. Once a device has disconnected, all calls to a client device will return errors. ## Device Features Each device is made of one or more features, which define what the device can do. These can be anything from vibration motors, to stroker axes, to battery level reading access. [Output types](../../spec/output#outputtype) and [Input types](../../spec/input#inputtype) for features are defined in the [Buttplug API Spec](../../spec/). Features contain: - A basic text description of what they do, for display in UI - Dictionaries of OutputTypes to Output Settings, for instance, an entry for the Vibrate OutputType (let's say a lovense device), with a corresponding field that denotes how many steps of vibration the device can handle (which, for a lovense vibrator, will always be a maximum of 20. All lovense vibrators have 20 steps of vibration available. The number presented here might be lower as the user may have set an upper vibration speed limit in the server). - Dictionaries of InputTypes to Input Settings, for instance, an entry for the Pressure InputType, with a corresponding field that denotes how many steps of pressure we can read from the device. Some fields, like Battery, may have no settings fields, as they are assumed to return a set of values (in this case, 0-100 reflecting percentage). Not all devices will have both inputs and outputs, many will just have outputs, and likely a single output at that. > **Tip: What kind of units will Outputs and Inputs take?** This is, unfortunately, one of the hardest parts of dealing with the type of hardware our library provides access to. There are almost never "units", just "steps". Vibrators and fucking machines usually just come with an a number of set speeds they run at with no relation to power or frequency. Strokers may have encoder ticks but usually don't correspond to any sort of actual length measurement. The best we can do is provide the number of steps we know of that the device provides. ## Controlling Devices and Features Controlling a device is usually a matter of controlling its features. How this happens will differ between different client implementations, but will usually take one or more of the following forms, with the example being a device with 2 vibration motors: - The top level _Device_ will have some sort of `run_output()` command, which takes an output type and a value to set it to. If this is used, all features that support the Vibrate OutputType will be set to this value. - There may be two variations of the arguments this command takes, one that takes a value between 0 and the number of steps defined in the feature, as well as one that takes a floating point value between 0.0 and 1.0, which will automatically scale to the range of steps allowed by the feature. - Each feature will also have some sort of `run_output()` command, which will allow setting the value for just that feature. This allows developers to only control one of the two available motors, setting them to different speeds. Depending on language capabilities, there may also be a generic way to put together commands, useful for building complex programmatic structures for control. ## Value Systems At the message level, device features accept commands only in raw steps. Client libraries typically support break these values out into two different types. > **Tip: Objectivity and Pseudocode Ahead** We haven't gotten into examples yet, so all code in this section is just random pseudocode to give you an idea of how things *might* work in the implementation you're using. There's no telling whether the author of the client library you're using actually does things this way, it's just how we as the buttplug core dev team write our clients. ### Percentage-Based Values (Recommended) Values between 0.0 and 1.0 that are automatically scaled to the device's capabilities: ``` device.vibrate.percent(0.5) // 50% power - works on any device ``` This is the recommended approach for most applications because: - It works consistently across all devices regardless of their step counts - It's ideal for normalized input values - The client library handles the conversion to actual device steps ### Step-Based Values Raw integer values within the device's StepCount range: ``` device.vibrate.steps(10) // Exactly step 10, regardless of max steps (errors if over max) ``` Use step-based values when: - You need precise control over exact device behavior - You're working with device-specific patterns or sequences - You want to ensure consistent behavior across sessions ### Checking Device Capabilities Before sending commands, you can query what a device supports: ``` // Check if device has vibration. This may be an enum value in your impl. if (device.hasOutput("Vibrate")) { // Get the value range for the first vibration feature range = device.features[0].outputs["Vibrate"].valueRange // e.g., [0, 20] } ``` The value range tells you the valid step values. A range of `[0, 20]` means steps 0 through 20 are valid (21 total levels including off). ## Command Patterns Client libraries typically provide multiple ways to control devices: ### All-Features Commands Set all features of a given type to the same value: ``` device.vibrate.percent(0.5) // All vibration motors at 50% device.oscillate.percent(0.8) // All oscillation features at 80% ``` ### Per-Feature Commands Control individual features when a device has multiple motors/axes: ``` device.features[0].vibrate.percent(0.8) // First motor at 80% device.features[1].vibrate.percent(0.3) // Second motor at 30% ``` ### Output Types Different output types exist for different device capabilities: | OutputType | Use Case | Example Devices | |------------|----------|-----------------| | Vibrate | Vibration motors | Most toys | | Oscillate | Speed-controlled movement | Fucking machines | | Position | Instant position change | Strokers (servo mode) | | HwPositionWithDuration | Hardware regulated timed position movement | Strokers, linear actuators | | Rotate / RotationWithDirection | Rotating mechanisms | Rotating toys | | Constrict | Pumps and squeezing | Air pumps | | Temperature | Heating/cooling | Warming toys | See the [Output Types in the Spec](../../spec/output#outputtype) for the complete list and details. ## Sensor Input and Subscriptions Devices may have input features for reading sensor data. There are two patterns for accessing this data: ### Single Reads For data that changes slowly, use a one-time read: ``` level = await device.battery() // Returns 0-100 percentage rssi = await device.rssi() // Returns signal strength (negative dBm) ``` Battery and RSSI are the most common single-read inputs. They don't change fast enough to warrant continuous streaming. ### Subscriptions For continuous data like pressure sensors or buttons, subscribe to receive events: ``` // Subscribe to pressure sensor updates device.feature[0].pressure.subscribe((reading) => { console.log("Pressure:", reading.value) }) // Later, when done: device.feature[0].pressure.unsubscribe() ``` Subscription events fire whenever the sensor value changes, which may be many times per second for active sensors. ### Subscription Lifecycle - **Subscriptions persist** until explicitly unsubscribed or the connection ends - **Duplicate subscriptions are ignored** - subscribing twice doesn't create two streams - **Auto-cleanup on disconnect** - all subscriptions are automatically cleaned up when the client disconnects - **No subscription limit** - you can have any number of concurrent subscriptions across devices ### Input Types | InputType | Description | Typical Use | |-----------|-------------|-------------| | Battery | Charge level (0-100%) | Single read | | RSSI | Bluetooth signal strength | Single read | | Pressure | Squeeze/kegel sensors | Subscription | | Button | Physical device buttons | Subscription | See the [Input Types in the Spec](../../spec/input#inputtype) for the complete list. > **Warning: Sensor Values Are Not Standardized** Sensor readings (especially pressure) are **not in standardized units**. A pressure reading of "200" on one device has no relation to "200" on another device. If your application requires meaningful values (like actual pressure in kPa), you must implement per-device calibration at the application level. --- ## Client Architecture ![Buttplug Client Architecture Diagram](/img/dev-guide/architecture/client.png) Applications use clients to talk to Buttplug Servers. Let's go over what each part of clients and connectors do. ## Clients The client is the name for the publically exposed API that an application uses to access Buttplug, and acts as a bookkeeper for system state. Instead of writing raw protocol messages, you call methods on the client, and it turns them into messages for you, while also managing replies from messages it has generated from earlier calls. The client's main functions are: - Manage connecting/disconnecting with the server, via Connectors - Starts/stops device enumeration, while also keeping track of all devices the server claims to have added/removed and emitting updates for these events. The devices are exposed as Client Devices. ## Connectors Connectors are how clients and servers talk to each other. There are two classes of connectors: - *Remote Connectors*, which means the client is using some mechanism (TCP, Websockets, IPC, etc...) to talk to a server in another process. - *Embedded Connectors*, which contains the client and its connected server instance. This means that the whole Buttplug system is running in the same process as the application. As a Buttplug developer, you'll usually only have a couple of interactions with connectors. - Setting up them up, adding things like the name of your client, and maybe a network address or some other identifying information if needed. - Passing them to the client when calling the Connect method. That's it. After that, outside of very special circumstances that we'll cover in the Winning Ways chapter, you'll rarely deal with your connector again. You set it up, connect with it, then the Client manages it for the life of your Buttplug session. ## Client Lifetime After handling connections, clients mainly exist as a frontend for event emitting and device discovery. Devices can be discovered using something like `StartScanning()` and `StopScanning()` methods. Changes in device connectivity and asynchronous server errors (i.e. errors not caused by commands from the client) will be relayed through whatever event system is provided by the language/runtime currently being used. ## Client Events Clients emit events for asynchronous notifications from the server. The exact API varies by language (callbacks, event emitters, streams, etc.), but the reference implementations we provide expose these core events. Other implementations may vary in naming or structure, but should provide equivalent functionality. ### Device Events | Event | When It Fires | What You Receive | |-------|---------------|------------------| | DeviceAdded | A new device connects | The new device object | | DeviceRemoved | A device disconnects | The removed device (or its index) | In protocol V4, the server sends the complete device list on any change. Client libraries typically diff this list and emit individual add/remove events for convenience, though implementations may handle this differently. ### Scanning Events | Event | When It Fires | |-------|---------------| | ScanningFinished | Server completes a scan cycle | Note that ScanningFinished does **not** mean no devices were found. Scanning may complete successfully with or without discovering devices. Some connection types (like Bluetooth) may continue finding devices after the initial scan completes. > **Tip: Scanning Finished is Weird** The problem with ScanningFinished is that it's really only used in a couple of situations. Buttplug will happily scan forever, but also runs in contexts where that's not possible. For instance, when scanning for Bluetooth in a WASM context, there's a time limit on scanning, and scans are *required* to be kicked off by the user via UI interaction. For 99% of use cases, ScanningFinished can be ignored. Just present capabilities to call StartScanning/StopScanning to users, or even just tell them to use Intiface Central's devices tab for making sure devices are connected. ### Connection Events | Event | When It Fires | |-------|---------------| | ServerDisconnect | Connection to server lost | | PingTimeout | Client missed ping deadline (if ping enabled) | After a disconnect event, all device references should be considered invalid. You'll need to reconnect and request a new device list. ### Sensor Events | Event | When It Fires | What You Receive | |-------|---------------|------------------| | InputReading | Subscribed sensor sends data | Device index, feature index, reading | Sensor readings arrive as events when you've subscribed to a sensor input. See the [Client Devices](./client-device-in-depth) section for subscription details. ## Message ID Tracking Every message sent to the server includes an `Id` field. Client libraries typically handle this automatically: 1. Client generates a unique ID for each outgoing message (often an incrementing counter) 2. Client stores a reference to the pending request, keyed by ID 3. When a response arrives, the client matches it to the pending request by ID 4. The original caller receives the response (or error) This enables **out-of-order responses** - if you send commands to devices A and B, B might respond before A. The ID tracking ensures each response reaches the correct caller. > **Tip: You Likely Won't Need to Manage IDs** In the reference implementations, this is handled internally by the client library. You won't see message IDs when using the client API - they're mentioned here to help you understand how the system works if you're debugging connection issues or building your own client. ## Handling Errors ### Error Types When commands fail, the server returns an error with a code indicating the category. These codes are defined in the [protocol spec](/docs/spec/status#error): | Error Code | Name | Meaning | |------------|------|---------| | 0 | ERROR_UNKNOWN | Unexpected/uncategorized error | | 1 | ERROR_INIT | Handshake failed (version mismatch, invalid client name) | | 2 | ERROR_PING | Ping timeout occurred | | 3 | ERROR_MSG | Message parsing failed or invalid message | | 4 | ERROR_DEVICE | Device command failed | ### Common Failure Scenarios **Device Disconnects Mid-Command** - The command returns ERROR_DEVICE - A DeviceRemoved event should fire - All subsequent commands to that device will fail - The device may reconnect later (watch for DeviceAdded) **Invalid Feature or Value** - Sending a command to a non-existent feature index returns ERROR_DEVICE - Sending a step value outside the valid range returns ERROR_DEVICE - Checking device capabilities before sending commands can help avoid these errors **Connection Lost** - A disconnect event should fire - All pending commands fail - All device references become invalid - You must create a new client connection to continue ### Error Recovery Most Buttplug errors require user intervention (reconnect the device, restart the server, etc.). In general: - **Log errors** for debugging - **Update UI** to reflect device/connection state - **Avoid aggressive retry logic** - if a device command fails, the device likely disconnected ## Connector Types in Practice > **Tip: Objectivity and Pseudocode Ahead** The examples in this section are pseudocode to illustrate concepts. Check your specific client library's documentation for actual API usage. ### Remote Connectors The most common setup uses a remote WebSocket connector to talk to Intiface Central: ``` connector = WebSocketConnector("ws://127.0.0.1:12345") client.connect(connector) ``` The default Intiface Central address is `ws://127.0.0.1:12345`. Users can change this port in Intiface Central's settings. Remote connectors are generally recommended because: - Users can update Intiface Central independently of your application - Device support improvements don't require app updates - Intiface Central handles all the hardware complexity ### Embedded Connectors For advanced use cases, you can embed the server directly in your application: ``` server = ButtplugServer("My App Server") connector = EmbeddedConnector(server) client.connect(connector) ``` Embedded connectors mean: - Your application is fully self-contained (no external dependencies at runtime) - You're responsible for updating the library to get new device support - You take on the complexity of hardware manager configuration See the Embedding section in the cookbook for detailed guidance on embedded setups. --- ## The Intiface Ecosystem Intiface® is the official name for the application system built on top of Buttplug by Nonpolynomial Labs, LLC (the company behind Buttplug, though it's just one person). Where Buttplug is for developers, Intiface is made to either help users actually use what those developers made, or else make our own apps. When Buttplug is referred to in this document, it's in relation to the library. When Intiface is referred to, it's usually in relation to applications implementing Buttplug, and always by Nonpolynomial Labs. For the rest of this document, you'll need to be familiar with Intiface Engine and Intiface Central, which we'll cover below. > **Tip: Wait, Intiface®? As in Registered Trademark?** Yes, Intiface® is actually a registered trademark of Nonpolynomial Labs, LLC. This workmark was registered to protect the app on app stores, since we're an open source app. It's not meant to be predatory. Also, I just wanted to learn what getting a trademark was like. I got a really shiny piece of paper. It was very expensive. ## Intiface Engine Intiface Engine is a barebones CLI wrapper around the Buttplug Server and the various options to build it. All capabilities of the engine, including adding/removing device configurations, user configurations (like special device names, DIY devices, etc), hardware communication managers (bluetooth, USB, etc...) can be configured via arguments to Intiface Engine. Intiface Engine is implemented in Rust and distributed as both an executable, and a library (for reasons covered in the [embedding section](../cookbook/connections/embedding.mdx) later.) ## Intiface Central Because most users don't want to interact with a terminal or console, Intiface Central provides a GUI for setup and engine control. ![Intiface Central GUI Example](/img/dev-guide/architecture/intifacecentral.png) This is the hub program that it is expected most users will have an use. It's updated frequently by us with the latest version of Buttplug, as well as extra features like device testing for users, and device simulation for developers. [Intiface Central](https://intiface.com/central) is implemented in a combination of Flutter and Rust, and is available on desktop and mobile platforms. ## Other Intiface Applications * [Intiface Game Haptics Router](https://intiface.com/ghr) - A program that reroutes gamepad rumble signals from games to Sex Toys. * Intiface Desktop (Deprecated) - The original version of what became Intiface Central, retired in late 2022. It was an electron based app that managed updates and execution of the Intiface Engine. --- ## Introduction In this section, we'll cover Buttplug's core protocol and architectures. Getting familiar with the terms here is important, as they will be used throughout the rest of this guide, as well as in identifiers (variable/method names, etc) in Buttplug itself. None of this chapter is programming language specific. While how these structures are implemented across programming languages may differ, the general idea will be the same across most systems. Any stark differences should be called out in documentation for the specific language implementations. > **Tip: If you don't understand this section on first read, THAT'S OK!** This guide is written in "theory then application" order. If you're more of an application than theory learner, that's fine! Just take a quick read through here, see what you pick up, then move on to the "Writing Applications" chapter and come back to this once you've gotten your hands (or other bits) dirty. The information here is important, but if you don't get it on your first shot, that shouldn't stop you from reading the rest of the dev guide. Go play with the rest of the system and see if that helps. :D --- ## Buttplug Protocol At the core of Buttplug is the Buttplug Protocol. This protocol is defined in the [Buttplug API Spec](https://buttplug-spec.docs.buttplug.io). > **Tip: Why is there a protocol specification?** We used to call this a "standard" but have backed off to calling it an API, as we've found that the extra formality and pomp/circumstance around calling it a "standard" just makes life difficult. We still keep a protocol spec, which serves a couple of functions: - It allows developers to build their own implementations of Buttplug if they so choose, and know that they should be compatible with applications using Buttplug as long as the spec is followed. - Mostly it's assumed that developers will use the spec to implement clients in other programming languages. - As of this writing, we're now 8 years into this and no one has been dumb enough to implement another server. Which is good, because implementing servers is a nightmare and we never recommend anyone do it. - One of the goals of Buttplug is forward-compatibility. If an app implements Buttplug but then doesn't continue development, Buttplug Servers should be able to adapt the older protocol version to new messages and hardware. The spec creates a record to work with for these conversions, so we can understand what was happening when the app was originally developed, and what has changed since. Forward compatibility is important here because when people find sex software they like, they will use it *forever*. There are VB6 and Java sex apps from the late 90's/early 00's out there still seeing use these days! ## Messages The Buttplug Protocol is made up of messages. 99.999% of the time, unless you're actually developing a Buttplug Client or Server, you will never see a raw Buttplug Message. The Client API takes care of forming them for you, and the Server is usually only accessed via the Client. However, for sake of knowledge, Buttplug Messages look like this (at least, in its serialized JSON format, which is the only format we've used so far): ```json { "Ok": { "Id": 1 } } ``` This is an "Ok" message, which the server sends to the client to signify that a message was received and processed successfully. It, and every other Buttplug Protocol Message, has an "Id" field, which is used to give messages context. The Client will choose an Id for a message, then when the server replies to it, it will use the same Id, so the Client knows which message the Server is replying to. As Buttplug deals with hardware that communicates at vastly different speeds, messages may be replied to out of order, so there's nothing saying that a message that's send first will get its reply first. **All of this is taken care of for you in a properly written Client API**, so you don't really have to worry about making any of this happen yourself. :) ## Client/Server Interaction There are two types of communication between the client and the server: - Symmetric (Client :arrow_right: Server :arrow_right: Client) - Client sends a message, server replies. For instance, when a device command is sent from the client, the server will return information afterward saying whether or not that command succeeded (in the form of the "Ok" message shown above.). - Asymmetric (Server :arrow_right: Client) - Server sends a message to the client with no expectation of response. For instance, when a new device connects to the server, the server will tell the client the device has been added, but the server doesn't expect the client to ask for the message, or to acknowledge that it received it. These messages are considered fire and forget. Symmetric interaction between the client and the server may be a very, very long process. Sometimes 100s of milliseconds, sometimes possibly even multiple seconds if device connections are poor or requires intensive processing. How asymmetric message are dealt with depends on the capabilities of the programming language implementing the library. There may be callbacks, event handlers, streams, or something else entirely. We'll cover this more in the Writing Applications section. ## Message classes There are multiple classes of Message in the protocol, including: - **Status**: Relaying info about the status of the system, including whether a message was processed ok or errored out, whether the system has timed out and shutdown, etc... - **Handshake**: Used to set up connections between servers and clients. - **Enumeration**: Getting what devices are currently connected, or what is being added/removed. Addition/list messages also contain specific information about device capabilities. - **Device**: Messages going to/from specific devices. These include commands, or reading from sensors on the device. ## Spec Versions and Message Additions When reading Buttplug bugs or development posts, you may here that some functionality is in development and "messages will be added in the next version". Each version of the Buttplug API has a version number, and as of Version 4, there are now both a major and minor version number. Once that version is set, the only way to change the spec is to increase the version number. This is what allows us to handle backward compatibility, since we know exactly what messages and types to expect when a client connects to a server (as the client will declare the spec version it's using as part of one of its handshake messages). In the past, adding new functionality to Buttplug meant adding new messages, so when Buttplug didn't do something that developers are looking for, it means we had to add a full new message to the protocol, and revise the spec major version. As of API v4, we have built the protocol to be more generic, meaning new types of outputs (things a device does) and inputs (data a device can give us) can be added without adding full new messages. These types of changes only require bumping the minor version. Clients that cannot handle these types but still use the same major version will still function. Once the spec changes, we then modify the Client API and release a new major version of the libraries (spec changes always trigger major version revisions), so that developers can use the new message. Message and type additions are rather complicated processes. Addition procedure is outlined in the Inflating Buttplug section, but for now, just knowing these terms is enough so you can translate what project contributors are talking about when they discuss the spec and new messages. > **Tip: Can Clients and Servers of different spec versions talk to each other?** Yes, in some cases. This is how backward compatibility in Buttplug systems works. If a client has an older message spec version than a server, the server should be able to accommodate the client by translating messages from/to the older version. This is also why you may want to think twice before developing your own server implementation, as trying to get these translations right is quite complicated. If the client has a newer major API version than the server, then the connection will fail on handshake. This is because the server has no idea what the client may send it, and it's assumed that if its a remote server, then the user can probably update it to the latest version and fix this issue. If the client has the same major version but higher minor API version than the server (which we expect to be rare, as updated servers will always be released with new client library versions but users may not upgrade quickly), things should work as normal, as the server will never present the client with control options it cannot support. ## For More Info, Visit Your Local Spec The above summary is all you really need to know about messages if you're going to build a Buttplug application. You can assume that most of the methods you'll use in the Client API for your chosen programming language are working behind the scenes to form a Buttplug message of some type and send it on to the server, then receiving messages from the server and turning them into either return values for methods, or events. But you shouldn't have to worry about the low level, and if you do, it's probably a bug. However, if you want to work Buttplug libraries, it's definitely worth becoming more familiar with this part of the system. In that case, it's best to read the [Buttplug Protocol Spec](https://docs.buttplug.io/docs/spec) in order to understand message functions and flows. --- ## Server Architecture ![Buttplug Server Architecture Diagram](/img/dev-guide/architecture/server.png) As a developer using the Buttplug library for applications, your access to Buttplug Servers is limited to some setup methods. Otherwise, most of your interaction with a server will be via the Client API. It's still good to know a bit about what the inside of the server looks like though, if only so you can understand [what's being complained about on social media](../intro/getting-help.md). ## Server and Connections Buttplug Servers themselves don't actually do all that much, as most of the complexity lives in the Device Manager and below. The server portion is mainly concerned with connection management and message routing. When a client connects to the server, the server handles the handshake. This is where the Client and Server trade identifiers and message spec versions to make sure they'll be able to talk to each other. If any of the information exchanged doesn't match what's expected, the server disconnects. If the handshake is successful, depending on configuration values the server may then start up a ping manager, which is covered in detail below. Finally, the server is basically the front door to the rest of the hardware handling system. It receives all messages, and either routes them to its device managers (if they're device related messages) or responds to them itself. The Server rarely has a surface API, and usually just exposes a "ProcessMessage" type method that sends/receives Buttplug Protocol Messages. ## Ping Manager The Ping Manager is an optional mechanism that can help detect unresponsive clients in certain scenarios. ### How It Works 1. During handshake, the server announces `MaxPingTime` in the [ServerInfo](/docs/spec/identification#serverinfo) message (e.g., 20000 for 20 seconds) 2. If `MaxPingTime` > 0, the client must send [Ping](/docs/spec/status#ping) messages within that interval 3. The server resets its timer each time it receives a Ping 4. If the timer expires without a Ping, the server: - Disconnects the client - Stops all devices immediately - Cleans up all sensor subscriptions > **Tip: When Is Ping Useful?** For **stateful transports** like WebSocket or TCP, the ping system is often redundant. If a client crashes, the transport layer detects the connection drop and notifies the server, which then stops devices automatically. The connection state itself provides crash detection. For **stateless transports** (or scenarios where transport-level detection isn't reliable), the ping system provides an application-level heartbeat. If the client stops sending pings, the server knows something is wrong even without a transport disconnect signal. The ping system may also help in edge cases like: - Client process frozen but network connection still open - Mobile apps suspended by the OS without closing connections - Network issues that don't immediately trigger transport-level disconnects **Ping is disabled by default across Buttplug Core Team maintained server applications like Intiface Central and Intiface Engine.** Since we've defaulted to Websocket control for the past 8 years, we had the functionality for basically free. The system continues to exist in the library to leave room for extensibility. ### Client Implementation Reference client libraries handle ping automatically in a background thread or task. You typically don't need to manually send pings - the library does it for you. If you're building your own client implementation, you'll need to implement ping handling when `MaxPingTime` > 0. ### When MaxPingTime is 0 in ServerInfo If the server sends `MaxPingTime: 0`, ping monitoring is disabled. The client can still send Ping messages (the server will respond with Ok), but no timeout enforcement occurs. This is common for embedded server configurations or testing scenarios. ## The Device Manager Each server contains a device manager, which does what it says on the tin. It manages devices (and also device communication managers). The Device Manager holds Device Communication Managers (DCMs), which are responsible for finding and returning devices. It also holds all currently connected devices that have been found and emitted by DCMs. When device messages are forward to the Device Manager from the Server, it parses them to figure out which device should receive the message, and forwards it on. ## Device Communication Managers Device Communication Managers (DCMs) contain the low level implementation of a device enumeration API. These represent different communication busses or management systems, sometimes within an operating system, like Bluetooth, USB HID, Raw USB, Serial, and other messages. They may also implement other communication strategies, network protocols for toys that require network access. A DCM is responsible for making sure its subsystem is usable (for instance, that Bluetooth is turned on and available within the server host system) starting/stopping device scanning when requested, as well as emitting when new devices are found. ## Device Configuration Manager DCMs need to know what devices to look for. They use the Device Configuration Manager to do this. Device Configuration Managers map device identifiers (Bluetooth names, USB VID/PID pairs, etc) to metadata like device names, proprietary protocols, etc... If you're interested in what this data looks like, the latest version is kept as JSON at [https://intiface-engine-device-config.intiface.com/buttplug-device-config-v4.json](https://intiface-engine-device-config.intiface.com/buttplug-device-config-v4.json). Whenever a DCM finds a device, it pulls the identifying data and sends it through the Device Configuration Manager to see if there is matching metadata. If matching metadata exists, the information is returned to the DCM, and the DCM continues with making a connection with the device, returning a Buttplug Device, which consists of an Implementation and a Protocol. ## Device Implementations and Protocols After the connection mating dance is finished, the Device Manager will hold a Buttplug Device. This has two parts: - The Implementation, which is how the library should communicate with the device hardware. This will be things like Bluetooth LE GATT commands, Serial/USB communication commands, etc... These implementations are usually provided as part of a DCM package. - The Protocol, which is what the library should say to the device to make it do things. Brands usually have their own specific protocols, and some brands may have multiple protocols. When a server receives a device command, it takes the following path: - Server receives device command, forward to Device Manager - Let's say it's a device that vibrates, so the server gets a VibrateCmd command with a device index of 1 - Device Manager takes the device identifier from the command to figure out which device should receive the command, looks up that device, forwards the command to the Buttplug Device - We find out device index 1 is a Lovense Hush, so it's a vibrating buttplug with one motor. - The Buttplug Device runs the command through the Protocol it owns, which turns the command from a Buttplug command into a proprietary command. - When we start here, we have a VibrateCmd, which has a single speed between 0.0 and 1.0, for our example here we'll say it's 0.5. Thanks to the Device Configuration Manager, we know that Lovense toys have 20 steps of power, so we need to get the actual vibration speed, which will be 0.5 * 20 = 10. Lovense's protocol expects vibration messages to look like "Vibrate:X;", where X is the value, so we'll get back "Vibrate:10;" - Once the device has the proprietary command, it sends that to the Implementation it owns, which actually sends the bytes to the hardware. - This involves sending the "Vibrate:10;" over the device communication mechanism. The above list of steps is why you're using Buttplug: We handle all of that for you, across multiple platforms, connection strategies, and toys. :) ## Conclusion Servers are where most of the complexity of Buttplug resides. Getting all of the different communication types and protocols to play nicely with each other is a tall order. As an application developer, you'll hopefully rarely have to deal with this part of the system. As a Buttplug Library developer, may god have mercy on your soul. --- ## Buttplug Sessions and Components ![Buttplug Architecture Diagram](/img/dev-guide/architecture/architecture.png) ## Buttplug Sessions Applications using Buttplug will generally follow this set of steps: - The application will call some sort of "connect" method, which may either be an internal setup method or an actual remote network connection call. The lifetime of this connection is called a *Buttplug Session*. - Once the connection is established, the application can request that Buttplug send a list of currently connected devices, and/or request to start scanning for devices. - As devices are found, they are reported back to the application. Similarly, as devices are disconnected, these events are also communicated back to the application. - After devices are connected, the application can send different commands to them, which may succeed or fail. These statuses are relayed via method return values. - Some combination of these last 3 events will happen until the session is terminated, via the application being closed, connection being severed, etc... That's it! This is all Buttplug does. Connects to some devices, controls them, and gives updates on their state. As simple as that sounds, it takes a lot of management under the covers, which is what we'll be talking about for the next few sections. We'll also introduce components to fill out what's responsible for these step descriptions. ## Session States A Buttplug session moves through several states during its lifetime. While client implementations may represent these differently (or not expose them directly), understanding the underlying states helps when debugging connection issues. | State | Description | |-------|-------------| | **Disconnected** | Initial state. No connection to server exists. | | **Connecting** | Connection initiated, handshake in progress. | | **Connected** | Handshake complete. Ready for device operations. | | **Disconnected** | Session ended (graceful disconnect, error, or timeout). | Some implementations may also distinguish: | State | Description | |-------|-------------| | **PingedOut** | Server disconnected the client due to missed ping deadline. | Once a session reaches a disconnected state (for any reason), it generally cannot be resumed. You'll need to create a new connection to continue. ## Connection Handshake When a client connects to a server, they exchange information to establish the session. This handshake is typically handled automatically by client libraries, but understanding it helps when troubleshooting. ### Handshake Steps 1. **Transport Connection** - Client establishes low-level connection (WebSocket, IPC, etc.) - At this point, no Buttplug messages have been exchanged yet 2. **RequestServerInfo** - Client sends [RequestServerInfo](/docs/spec/identification#requestserverinfo) with: - `ClientName`: Your application's identifier (shown in server logs/UI) - `ProtocolVersionMajor` / `ProtocolVersionMinor`: Protocol version the client supports 3. **ServerInfo Response** - Server replies with [ServerInfo](/docs/spec/identification#serverinfo) containing: - `ServerName`: Server identifier - `ProtocolVersionMajor` / `ProtocolVersionMinor`: Protocol version the server will use - `MaxPingTime`: Milliseconds between required pings (0 = no ping required) 4. **Ping Timer (if enabled)** - If `MaxPingTime` > 0, client must send [Ping](/docs/spec/status#ping) messages within that interval - Missing a ping deadline causes the server to disconnect and stop all devices 5. **Device List** - Client typically requests the current device list via [RequestDeviceList](../../spec/device_information#devicelist) - Server responds with any already-connected devices - Client is now ready for normal operation ### Version Negotiation The client and server negotiate which protocol version to use: - Client sends the version it supports - Server responds with the version it will use (may be lower for compatibility) - If the server's maximum major version is *lower* than what the client requests, the handshake fails This allows older clients to work with newer servers (the server downgrades to match), but a newer client cannot connect to an older server that doesn't support its requested version. In practice, the server is assumed to be either [Intiface Engine](https://github.com/buttplugio/buttplug/crates/intiface-engine) or [Intiface Central](https://intiface.com), so a client being newer than the server implies that the user usually needs a new version of one of these applications. ## Components Systems that use Buttplug will generally work with the following 3 components. ### Buttplug Servers A Buttplug Server is the piece that manages communication with hardware. This is usually via Operating System Specific libraries or APIs. It handles coordination of device connections/disconnections, mapping protocol implementations to connected hardware, and maintaining communication with the currently connected client. A few examples of jobs the server has: - The server is in charge of finding devices connected to the computer, via bluetooth, usb, serial, firewire, parallel, barbed wire, or whatever other device communication type is supported by the server implementation in question. - The server contains the knowledge of how to talk to a specific toy in the way that it understands. Toy protocols are rarely shared between different brands, so the server contains many different implementations. - If a client is controlling a device, then for some reason disconnects, it is the server's job to stop the device until the client has reconnected and sends new control commands. The server may be in charge of other tasks, which we'll cover in depth in a later section in this chapter. As a developer using Buttplug for applications, it's rare you'll interact directly with a server via code. You'll usually use a Buttplug Client library that does that for you. Server software, like [Intiface Central](https://intiface.com/central) and Intiface Engine, are maintained and distributed by the Buttplug Core Team. This allows device/feature additions and bug fixes to happen without application developers having to worry about updating their own software. ### Buttplug Clients Buttplug Clients are the usable API surface of Buttplug, what developers use to talk to Buttplug Servers. Clients are responsible for messages staying synced between the developer's code and the servers. They may also expose devices and interfaces in a language specific way that the developer is used to working with. ### Applications This is the part you're most likely going to be building! Applications put some sort of specific UI/UX in front of a Buttplug Client. This could be anything from games to movie players to text/code editor plugins to who knows what. All applications that the Buttplug Core Team are aware of are listed in the [Buttplug Awesome List](https://awesome.buttplug.io). The ideas here really are endless. All of these will use a Buttplug Client to talk to a Buttplug Server. ## Component Configuration Examples There are multiple configurations and possibilities available, depending on the programming language, operating system, and hardware platform the developers and users choose. Once again trying to limit specifics, here's a couple of examples of how these pieces might go together: - A developer builds a web app to control sex toys. The web browser does not support a way to access the sex toy hardware. The web app will contain a Buttplug Client that talks over the network to a native Buttplug Server like [Intiface Central](https://intiface.com/central), which has the ability to talk to the hardware directly. - A developer builds a movie player application that is just one executable, containing both a Buttplug Server and Client. This allows them to use the Client API, which makes accessing the server easy, while also meaning users only have one thing to install and don't have to worry about connecting to outside programs. However, this means the developer is also responsible for updating their application as the library updates, so it is not recommended. The plusses and minuses of these different setups will be covered in the Writing Applications section. ## Protocol Buttplug is both a protocol and a system of components. The Buttplug Protocol is the language that all of the components use to talk to each other. We'll cover it in depth in the next section, then will go into the Client and Server Components. The rest of the developer guide is spent on Applications and Configurations. --- ## Glossary Just in case you don't want to go digging through the architecture section again, here's a quick list of common terms. * **Client** * The part of Buttplug implementations that applications use in order to access servers. Client APIs are what most Buttplug applications developers will see. * **Connector** * Used by a client/server so it can talk to the corresponding pieces in some way. This could be embedded (other side in same program), or via networks (i.e. websockets), ipc (i.e. pipes), or other mechanisms. * **Device** * A device is the general term for anything that buttplug connects to and controls. Sex toys, gamepads, fucking machines, whatever. Inside the library, it refers to either a representation of the hardware (in the client), or the actual code to talk to the hardware (in the server). * **Device Communication Manager (DCM)** * A server component responsible for handling a specific hardware communication bus, such as Bluetooth LE, USB HID, Serial, or network protocols. DCMs enumerate devices on their bus and create connections when devices are found. * **DeviceIndex** * An unsigned 32-bit integer that uniquely identifies a device within a Buttplug session. Used in commands to specify which device should receive the command. The index typically persists across reconnections unless the user clears their server configuration. * **Feature** * A discrete capability of a device, such as a vibration motor, rotation mechanism, stroker axis, or pressure sensor. Each device contains one or more features, and each feature has its own index, supported output/input types, and value ranges. * **FeatureIndex** * An unsigned 32-bit integer identifying a specific feature within a device. Used in commands to target a specific motor, axis, or sensor when a device has multiple features of the same type. * **InputType** * Categories of sensor data that can be read from device features. Examples include Battery (charge level), RSSI (signal strength), Pressure (squeeze sensors), and Button (physical buttons). See the [Input Types](../../spec/input#inputtype) in the spec for the complete list. * **Intiface Central** * GUI interface to configure and start a Buttplug server, distributed by the same team that makes Buttplug. This is what most users of Buttplug will have on their system for your applications to communicate with. * **Intiface Engine** * Command line interface to configure and start a Buttplug server, distributed by the same team that makes Buttplug. * **Message** * Buttplug messages are defined in the [Buttplug Spec](https://buttplug-spec.docs.buttplug.io), and are how Buttplug Clients and Servers communicate with each other. * **OutputType** * Categories of actions that can be sent to device features. Examples include Vibrate, Rotate, Oscillate, Position, and Temperature. Each output type may have different parameters (e.g., Position includes duration). See the [Output Types](../../spec/output#outputtype) in the spec for the complete list. * **Ping Manager** * An optional server safety mechanism that requires clients to send periodic ping messages. If enabled (MaxPingTime > 0 in ServerInfo), clients must ping within the specified interval or the server will disconnect and stop all devices. This protects against client crashes leaving devices running when using stateless connection mechanisms. * **Server** * The part of Buttplug implementations that manages device connections and communication. This may be a standalone server, or may exist inside an application that uses Buttplug. Those wanting to add implementations for new devices will do so in Buttplug Server code. * **StepCount** * The number of discrete levels a device feature supports. For example, a vibrator with 20 speed levels has a StepCount of 20, meaning valid step values are 0-20. This information is provided in the device's feature definitions and is used to convert percentage values (0.0-1.0) to actual device commands. --- ## API Basics Assuming you're using a client written by the Buttplug Core Team, client implementations in Buttplug are built to look as similar as possible no matter what language you're using. However, there may be instances where language options (i.e. existence of things like first-class events) change the API slightly. This section goes over how the client APIs we've provided work in a generic manner. ## Buttplug Session Overview Let's review what a Buttplug Sessions are made up of. Some of this was covered in depth in the [architecture section](/docs/dev-guide/architecture/intro), so this will just be an overview, while also including some example code. Buttplug sessions (the connection lifetime between the client and server) consist of the following steps. - Application sets up a connection via a Connector class/object and creates a Client - Client connects to the Server - Client negotiates Server Handshake and Device List Update - Application uses Client to request Device Scanning - Server communicates Device Connection events to Client/Application. - Application uses Device Instances to control hardware in Server - At some point, Application/Client disconnects from the Server ## Client/Server Interaction There are two types of communication between the client and the server: - Request/Response (Client -> Server -> Client) - Client sends a message, server replies. For instance, when a device command is sent from the client, the server will return information afterward saying whether or not that command succeeded. - Events (Server -> Client) - Server sends a message to the client with no expectation of response. For instance, when a new device connects to the server, the server will tell the client the device has been added, but the server doesn't expect the client to acknowledge this. These messages are considered fire and forget. Request/Response interaction between the client and the server may be a very long process. Sometimes 100s of milliseconds, or even multiple seconds if device connection quality is poor. In languages where it is available, Client APIs try to deal with this via usage of Async/Await. For event messages, first-class events are used, where possible. Otherwise, callbacks, promises, streams, or other methods are used depending on language and library capabilities. **Rust:** ```rust use buttplug_client::{ ButtplugClient, ButtplugClientEvent, connector::ButtplugRemoteClientConnector, serializer::ButtplugClientJSONSerializer, }; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; use futures::StreamExt; #[tokio::main] async fn main() -> anyhow::Result<()> { // In Rust, anything that will block is awaited. For instance, if we're going // to connect to a remote server, that might take some time due to the network // connection quality, or other issues. To deal with that, we use async/await. // // For now, you can ignore the API calls here, since we're just talking about // how our API works in general. Setting up a connection is discussed more in // the Connecting section of this document. let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); // For Request/Response messages, we'll use our Connect API. Connecting to a // server requires the client and server to send information back and forth, // so we'll await that while those (possibly somewhat slow, depending on if // network is being used and other factors) transfers happen. let client = ButtplugClient::new("Example Client"); client .connect(connector) .await .expect("Can't connect to Buttplug Server, exiting!"); let mut event_stream = client.event_stream(); // As an example of event messages, we'll assume the server might // send the client notifications about new devices that it has found. // The client will let us know about this via events. while let Some(event) = event_stream.next().await { if let ButtplugClientEvent::DeviceAdded(device) = event { println!("Device {} connected", device.name()); } } Ok(()) } ``` **C#:** [See it on Github](https://github.com/buttplugio/docs.buttplug.io/tree/master/examples/v4/csharp/AsyncExample) ```csharp // Buttplug C# - Async Patterns Example // // This example demonstrates async/await patterns and event handling // in the Buttplug C# library. The library is fully async - all operations // that might block (network, device communication) use async/await. using Buttplug.Client; var client = new ButtplugClient("Async Example"); // Events in C# use the standard EventHandler pattern. // Handlers receive (object sender, EventArgs args). // DeviceAdded is fired when a new device connects client.DeviceAdded += async (sender, args) => { // Note: Event handlers can be async! // The device is available via args.Device Console.WriteLine($"[Event] Device added: {args.Device.Name}"); // You can interact with the device in the event handler if (args.Device.HasOutput(Buttplug.Core.Messages.OutputType.Vibrate)) { Console.WriteLine($" Sending welcome vibration..."); await args.Device.RunOutputAsync(DeviceOutput.Vibrate.Percent(0.25)); await Task.Delay(200); await args.Device.StopAsync(); } }; // DeviceRemoved is fired when a device disconnects client.DeviceRemoved += (sender, args) => { Console.WriteLine($"[Event] Device removed: {args.Device.Name}"); }; // ScanningFinished is fired when scanning completes // (some protocols scan continuously until stopped) client.ScanningFinished += (sender, args) => { Console.WriteLine("[Event] Scanning finished"); }; // ErrorReceived is fired for asynchronous errors // (errors not directly caused by a method call you awaited) client.ErrorReceived += (sender, args) => { Console.WriteLine($"[Event] Error: {args.Exception.Message}"); }; // ServerDisconnect is fired when the server connection drops client.ServerDisconnect += (sender, args) => { Console.WriteLine("[Event] Server disconnected!"); }; // PingTimeout is fired if the server doesn't respond to keep-alive pings client.PingTimeout += (sender, args) => { Console.WriteLine("[Event] Server ping timeout!"); }; // InputReadingReceived is fired when subscribed sensor data arrives client.InputReadingReceived += (sender, args) => { Console.WriteLine($"[Event] Input reading from device {args.DeviceIndex}: {args.Reading}"); }; // Connect asynchronously - this may take time due to network await client.ConnectAsync("ws://127.0.0.1:12345"); // Scanning is also async - we start it and wait for events Console.WriteLine("Turn on devices now (events will be printed)...\n"); await client.StartScanningAsync(); // Use CancellationToken for timeouts and cancellation using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); try { // Wait for user input or timeout Console.WriteLine("Press Enter to stop scanning (or wait 10 seconds)..."); await Task.Run(() => Console.ReadLine(), cts.Token); } catch (OperationCanceledException) { Console.WriteLine("Scan timeout reached."); } await client.StopScanningAsync(); // Demonstrate concurrent operations var devices = client.Devices; if (devices.Length > 0) { // Send commands to all devices concurrently var tasks = devices .Where(d => d.HasOutput(Buttplug.Core.Messages.OutputType.Vibrate)) .Select(async device => { await device.RunOutputAsync(DeviceOutput.Vibrate.Percent(0.5)); await Task.Delay(500); await device.StopAsync(); }); // Wait for all commands to complete await Task.WhenAll(tasks); } else { Console.WriteLine("No devices connected."); } Console.WriteLine("\nPress Enter to disconnect..."); Console.ReadLine(); await client.DisconnectAsync(); Console.WriteLine("Disconnected."); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Async Patterns Example // // This example demonstrates async/await patterns and event handling // in the Buttplug library. The library is fully async - all operations // that might block (network, device communication) use async/await. // // Include Buttplug via CDN: // async function runAsyncExample() { console.log("Running async example"); const client = new buttplug.ButtplugClient("Async Example"); // Events in buttplug-js use EventEmitter3. // You can use addListener or on to subscribe to events. // 'deviceadded' is fired when a new device connects client.addListener("deviceadded", async (device) => { // Note: Event handlers can be async! console.log(`[Event] Device added: ${device.name}`); // You can interact with the device in the event handler if (device.hasOutput(buttplug.OutputType.Vibrate)) { console.log(" Sending welcome vibration..."); await device.runOutput(buttplug.DeviceOutput.Vibrate.percent(0.25)); await new Promise(r => setTimeout(r, 200)); await device.stop(); } }); // 'deviceremoved' is fired when a device disconnects client.addListener("deviceremoved", (device) => { console.log(`[Event] Device removed: ${device.name}`); }); // 'scanningfinished' is fired when scanning completes // (some protocols scan continuously until stopped) client.addListener("scanningfinished", () => { console.log("[Event] Scanning finished"); }); // 'disconnect' is fired when the server connection drops client.addListener("disconnect", () => { console.log("[Event] Server disconnected!"); }); // 'inputreading' is fired when subscribed sensor data arrives client.addListener("inputreading", (reading) => { console.log(`[Event] ${reading.device.name} ${reading.inputType}: ${reading.value}`); }); // Connect asynchronously - this may take time due to network console.log("Connecting to server..."); const connector = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345"); await client.connect(connector); console.log("Connected!"); // Scanning is also async - we start it and wait for events console.log("Starting scan. Turn on devices now..."); console.log("(Events will be printed as devices connect)"); await client.startScanning(); // Demonstrate concurrent operations after 5 seconds setTimeout(async () => { console.log("\nDemonstrating concurrent device control..."); // Convert devices Map to array const devices = Array.from(client.devices.values()); if (devices.length > 0) { // Send commands to all devices concurrently const tasks = devices .filter((d) => d.hasOutput(buttplug.OutputType.Vibrate)) .map(async (device) => { console.log(` Vibrating ${device.name}...`); await device.runOutput(buttplug.DeviceOutput.Vibrate.percent(0.5)); await new Promise(r => setTimeout(r, 500)); await device.stop(); console.log(` ${device.name} stopped.`); }); // Wait for all commands to complete await Promise.all(tasks); console.log("All devices stopped."); } else { console.log("No devices connected."); } }, 5000); } ``` **TypeScript:** ```typescript // Buttplug TypeScript - Async Patterns Example // // This example demonstrates async/await patterns and event handling // in the Buttplug library. The library is fully async - all operations // that might block (network, device communication) use async/await. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm async-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientDevice, DeviceOutput, OutputType, } from 'buttplug'; import type { ButtplugClientInputReading } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } function delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } async function main(): Promise { const client = new ButtplugClient('Async Example'); // Events in buttplug-js use EventEmitter3. // You can use addListener or on to subscribe to events. // 'deviceadded' is fired when a new device connects client.addListener('deviceadded', async (device: ButtplugClientDevice) => { // Note: Event handlers can be async! console.log(`[Event] Device added: ${device.name}`); // You can interact with the device in the event handler if (device.hasOutput(OutputType.Vibrate)) { console.log(' Sending welcome vibration...'); await device.runOutput(DeviceOutput.Vibrate.percent(0.25)); await delay(200); await device.stop(); } }); // 'deviceremoved' is fired when a device disconnects client.addListener('deviceremoved', (device: ButtplugClientDevice) => { console.log(`[Event] Device removed: ${device.name}`); }); // 'scanningfinished' is fired when scanning completes // (some protocols scan continuously until stopped) client.addListener('scanningfinished', () => { console.log('[Event] Scanning finished'); }); // 'disconnect' is fired when the server connection drops client.addListener('disconnect', () => { console.log('[Event] Server disconnected!'); }); // 'inputreading' is fired when subscribed sensor data arrives client.addListener('inputreading', (reading: ButtplugClientInputReading) => { console.log( `[Event] ${reading.device.name} ${reading.inputType}: ${reading.value}` ); }); // Connect asynchronously - this may take time due to network console.log('Connecting to server...'); const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); await client.connect(connector); console.log('Connected!\n'); // Scanning is also async - we start it and wait for events console.log('Starting scan. Turn on devices now...'); console.log('(Events will be printed as devices connect)\n'); await client.startScanning(); // Wait for user input await waitForEnter('Press Enter to stop scanning...'); await client.stopScanning(); // Demonstrate concurrent operations console.log('\nDemonstrating concurrent device control...'); const devices = Array.from(client.devices.values()); if (devices.length > 0) { // Send commands to all devices concurrently const tasks = devices .filter((d) => d.hasOutput(OutputType.Vibrate)) .map(async (device) => { console.log(` Vibrating ${device.name}...`); await device.runOutput(DeviceOutput.Vibrate.percent(0.5)); await delay(500); await device.stop(); console.log(` ${device.name} stopped.`); }); // Wait for all commands to complete await Promise.all(tasks); console.log('All devices stopped.'); } else { console.log('No devices connected.'); } await waitForEnter('\nPress Enter to disconnect...'); await client.disconnect(); console.log('Disconnected.'); } main().catch(console.error); ``` **Python:** ```python """Connection - Connect to a Buttplug server. This is the simplest possible Buttplug example. It connects to a Buttplug server (like Intiface Central) and shows connection status. Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Start Intiface Central and click "Start Server" 3. Run this script: python connection.py """ import asyncio from buttplug import ButtplugClient, ButtplugError async def main() -> None: # Create a client with your application's name client = ButtplugClient("Connection Example") try: # Connect to the server (Intiface Central default address) print("Connecting to server...") await client.connect("ws://127.0.0.1:12345") print(f"Connected to: {client.server_name}") # Connection is established - you can now scan for devices print("Connection successful!") except ButtplugError as e: # Handle connection errors print(f"Failed to connect: {e}") return finally: # Always disconnect when done if client.connected: await client.disconnect() print("Disconnected.") if __name__ == "__main__": asyncio.run(main()) ``` ## Dealing With Errors As with all technology, things in Buttplug can and often will go wrong. Due to the context of Buttplug, the user may be having sex with/via an application when things go wrong. This means things can go very, very wrong. With that in mind, errors are covered before providing information on how to use things, in the overly optimistic hopes that developers will keep error handling in mind when creating their applications. Errors in Buttplug sessions come in the follow classes: * *Handshake* * Client and Server connected successfully, but something went wrong when they were negotiating the session. This could include naming problems, schema compatibility issues (see next section), or other problems. * *Message* * Something went wrong in relation to message formation or communication. For instance, a message that was only supposed to be sent by a server to a client was sent in the opposite direction. * *Device* * Something went wrong with a device. For instance, the device may no longer be connected, or a message was sent to a device that has no capabilities to handle it. * *Ping* * If the ping system is in use, this means a ping was missed and the connection is no longer valid. * *Unknown* * Reserved for instances where a newer server version is talking to an older client version, and may have error types that would not be recognized by the older client. See next section for more info on this. Custom exceptions or errors may also be thrown by implementations of Buttplug. For instance, a Connector may throw a custom error or exception based on the type of transport it is using. For more information, see the documentation of the specific Buttplug implementation you are using. **Rust:** ```rust use buttplug_client::ButtplugClientError; use buttplug_core::errors::ButtplugError; #[allow(dead_code)] fn handle_error(error: ButtplugClientError) { match error { ButtplugClientError::ButtplugConnectorError(_details) => {} ButtplugClientError::ButtplugError(error) => match error { ButtplugError::ButtplugHandshakeError(_details) => {} ButtplugError::ButtplugDeviceError(_details) => {} ButtplugError::ButtplugMessageError(_details) => {} ButtplugError::ButtplugPingError(_details) => {} ButtplugError::ButtplugUnknownError(_details) => {} }, ButtplugClientError::ButtplugOutputCommandConversionError(_details) => {} ButtplugClientError::ButtplugMultipleInputAvailableError(_details) => {} } } fn main() { // nothing to do here } ``` **C#:** ```csharp // Buttplug C# - Exception Handling Example // // This example demonstrates the different exception types in Buttplug // and how to handle them. This is a reference for error handling patterns. using Buttplug.Client; using Buttplug.Core; // All Buttplug exceptions inherit from ButtplugException. // Here's the hierarchy: // // ButtplugException (base class) // ├── ButtplugClientConnectorException - Connection/transport issues // ├── ButtplugHandshakeException - Client/server version mismatch // ├── ButtplugDeviceException - Device communication errors // ├── ButtplugMessageException - Invalid message format/content // └── ButtplugPingException - Server ping timeout void HandleButtplugException(ButtplugException ex) { // Pattern match on the specific exception type switch (ex) { case ButtplugClientConnectorException connEx: // The connector couldn't establish or maintain connection. // Causes: server not running, wrong address, network issues, // SSL/TLS problems, connection dropped. Console.WriteLine($"[Connector Error] {connEx.Message}"); Console.WriteLine("Check that the server is running and accessible."); break; case ButtplugHandshakeException hsEx: // Client and server couldn't agree on protocol version. // Usually means you need to upgrade client or server. Console.WriteLine($"[Handshake Error] {hsEx.Message}"); Console.WriteLine("Client and server versions may be incompatible."); break; case ButtplugDeviceException devEx: // Something went wrong communicating with a device. // Causes: device disconnected, invalid command for device, // device rejected command, hardware error. Console.WriteLine($"[Device Error] {devEx.Message}"); Console.WriteLine("The device may have disconnected or doesn't support this command."); break; case ButtplugMessageException msgEx: // The message sent was invalid. // Causes: malformed message, missing required fields, // invalid parameter values. Console.WriteLine($"[Message Error] {msgEx.Message}"); Console.WriteLine("This usually indicates a bug in the client library or application."); break; case ButtplugPingException pingEx: // Server didn't receive ping in time, connection terminated. // The ping system ensures dead connections are detected. Console.WriteLine($"[Ping Error] {pingEx.Message}"); Console.WriteLine("Connection was lost due to ping timeout."); break; default: // Unknown or future exception type Console.WriteLine($"[Buttplug Error] {ex.Message}"); break; } } // Demonstrate catching exceptions during connection var client = new ButtplugClient("Exception Example"); Console.WriteLine("Exception Handling Example"); Console.WriteLine("==========================\n"); // Example 1: Connection error (server not running) Console.WriteLine("1. Attempting to connect to non-existent server..."); try { await client.ConnectAsync("ws://127.0.0.1:99999"); } catch (ButtplugException ex) { HandleButtplugException(ex); } // Example 2: Using the ErrorReceived event for async errors Console.WriteLine("\n2. Setting up error event handler..."); client.ErrorReceived += (sender, args) => { Console.WriteLine($"[Async Error Event] {args.Exception.Message}"); HandleButtplugException(args.Exception); }; // Example 3: Handling errors when sending commands after disconnect Console.WriteLine("\n3. Demonstrating error after disconnect..."); try { // Try to connect to actual server this time await client.ConnectAsync("ws://127.0.0.1:12345"); Console.WriteLine("Connected successfully."); // Scan briefly to get a device await client.StartScanningAsync(); await Task.Delay(1000); await client.StopScanningAsync(); if (client.Devices.Length > 0) { var device = client.Devices[0]; Console.WriteLine($"Found device: {device.Name}"); // Disconnect await client.DisconnectAsync(); Console.WriteLine("Disconnected."); // Now try to send a command - this will throw Console.WriteLine("Attempting to send command after disconnect..."); await device.RunOutputAsync(DeviceOutput.Vibrate.Percent(0.5)); } else { Console.WriteLine("No devices found to test with."); await client.DisconnectAsync(); } } catch (ButtplugException ex) { HandleButtplugException(ex); } Console.WriteLine("\nPress Enter to exit..."); Console.ReadLine(); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Error Handling Example // // This example demonstrates the different error types in Buttplug // and how to handle them. This is a reference for error handling patterns. // // Include Buttplug via CDN: // // All Buttplug errors inherit from ButtplugError. // Here's the hierarchy: // // ButtplugError (base class) // +-- ButtplugClientConnectorException - Connection/transport issues // +-- ButtplugInitError - Client/server version mismatch // +-- ButtplugDeviceError - Device communication errors // +-- ButtplugMessageError - Invalid message format/content // +-- ButtplugPingError - Server ping timeout function handleButtplugError(e) { if (e instanceof buttplug.ButtplugClientConnectorException) { // The connector couldn't establish or maintain connection. // Causes: server not running, wrong address, network issues, // SSL/TLS problems, connection dropped. console.log(`[Connector Error] ${e.message}`); console.log("Check that the server is running and accessible."); } else if (e instanceof buttplug.ButtplugInitError) { // Client and server couldn't agree on protocol version. // Usually means you need to upgrade client or server. console.log(`[Init/Handshake Error] ${e.message}`); console.log("Client and server versions may be incompatible."); } else if (e instanceof buttplug.ButtplugDeviceError) { // Something went wrong communicating with a device. // Causes: device disconnected, invalid command for device, // device rejected command, hardware error. console.log(`[Device Error] ${e.message}`); console.log("The device may have disconnected or doesn't support this command."); } else if (e instanceof buttplug.ButtplugMessageError) { // The message sent was invalid. // Causes: malformed message, missing required fields, // invalid parameter values. console.log(`[Message Error] ${e.message}`); console.log("This usually indicates a bug in the client library or application."); } else if (e instanceof buttplug.ButtplugPingError) { // Server didn't receive ping in time, connection terminated. // The ping system ensures dead connections are detected. console.log(`[Ping Error] ${e.message}`); console.log("Connection was lost due to ping timeout."); } else if (e instanceof buttplug.ButtplugError) { // Unknown or future error type console.log(`[Buttplug Error] ${e.message}`); } else if (e instanceof Error) { // Non-Buttplug error console.log(`[System Error] ${e.message}`); } else { console.log(`[Unknown Error] ${e}`); } } async function runErrorExample() { console.log("Error Handling Example"); console.log("======================\n"); // Example 1: Connection error (server not running on wrong port) console.log("1. Attempting to connect to non-existent server..."); const client1 = new buttplug.ButtplugClient("Error Example"); try { const badConnector = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:99999"); await client1.connect(badConnector); } catch (e) { handleButtplugError(e); } // Example 2: Demonstrating promise-based error handling console.log("\n2. Demonstrating promise-based error handling..."); const client2 = new buttplug.ButtplugClient("Promise Error Example"); const badConnector2 = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:99998"); // You can also catch errors using .catch() on promises await client2 .connect(badConnector2) .then(() => { console.log("Connected (unexpected!)"); }) .catch((e) => { console.log("Caught error using .catch():"); handleButtplugError(e); }); // Example 3: Using try/catch with async/await console.log("\n3. Using try/catch with async/await..."); const client3 = new buttplug.ButtplugClient("Async Error Example"); const invalidConnector = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://notadomain.local"); try { await client3.connect(invalidConnector); } catch (e) { // Check for specific Buttplug error types console.log(`Error: ${e}`); if (e instanceof buttplug.ButtplugError) { console.log("This is a Buttplug-specific error."); if (e instanceof buttplug.ButtplugClientConnectorException) { console.log("Specifically, it's a connector error."); } } else { console.log("This is a non-Buttplug error (system/network level)."); } } console.log("\nError handling example complete."); } ``` **TypeScript:** ```typescript // Buttplug TypeScript - Error Handling Example // // This example demonstrates the different error types in Buttplug // and how to handle them. This is a reference for error handling patterns. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm errors-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientConnectorException, ButtplugError, ButtplugDeviceError, ButtplugInitError, ButtplugMessageError, ButtplugPingError, DeviceOutput, } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } function delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } // All Buttplug errors inherit from ButtplugError. // Here's the hierarchy: // // ButtplugError (base class) // +-- ButtplugClientConnectorException - Connection/transport issues // +-- ButtplugInitError - Client/server version mismatch // +-- ButtplugDeviceError - Device communication errors // +-- ButtplugMessageError - Invalid message format/content // +-- ButtplugPingError - Server ping timeout function handleButtplugError(e: unknown): void { if (e instanceof ButtplugClientConnectorException) { // The connector couldn't establish or maintain connection. // Causes: server not running, wrong address, network issues, // SSL/TLS problems, connection dropped. console.log(`[Connector Error] ${e.message}`); console.log('Check that the server is running and accessible.'); } else if (e instanceof ButtplugInitError) { // Client and server couldn't agree on protocol version. // Usually means you need to upgrade client or server. console.log(`[Init/Handshake Error] ${e.message}`); console.log('Client and server versions may be incompatible.'); } else if (e instanceof ButtplugDeviceError) { // Something went wrong communicating with a device. // Causes: device disconnected, invalid command for device, // device rejected command, hardware error. console.log(`[Device Error] ${e.message}`); console.log( "The device may have disconnected or doesn't support this command." ); } else if (e instanceof ButtplugMessageError) { // The message sent was invalid. // Causes: malformed message, missing required fields, // invalid parameter values. console.log(`[Message Error] ${e.message}`); console.log( 'This usually indicates a bug in the client library or application.' ); } else if (e instanceof ButtplugPingError) { // Server didn't receive ping in time, connection terminated. // The ping system ensures dead connections are detected. console.log(`[Ping Error] ${e.message}`); console.log('Connection was lost due to ping timeout.'); } else if (e instanceof ButtplugError) { // Unknown or future error type console.log(`[Buttplug Error] ${e.message}`); } else if (e instanceof Error) { // Non-Buttplug error console.log(`[System Error] ${e.message}`); } else { console.log(`[Unknown Error] ${e}`); } } async function main(): Promise { console.log('Error Handling Example'); console.log('======================\n'); // Example 1: Connection error (server not running) console.log('1. Attempting to connect to non-existent server...'); const client1 = new ButtplugClient('Error Example'); try { const badConnector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:99999' ); await client1.connect(badConnector); } catch (e) { handleButtplugError(e); } // Example 2: Demonstrating promise-based error handling console.log('\n2. Demonstrating promise-based error handling...'); const client2 = new ButtplugClient('Promise Error Example'); const badConnector2 = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:99998' ); // You can also catch errors using .catch() on promises await client2 .connect(badConnector2) .then(() => { console.log('Connected (unexpected!)'); }) .catch((e) => { console.log('Caught error using .catch():'); handleButtplugError(e); }); // Example 3: Handling errors when sending commands after disconnect console.log('\n3. Demonstrating error after disconnect...'); const client3 = new ButtplugClient('Disconnect Error Example'); try { const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); await client3.connect(connector); console.log('Connected successfully.'); // Scan briefly to get a device await client3.startScanning(); await delay(1000); await client3.stopScanning(); if (client3.devices.size > 0) { const device = client3.devices.values().next().value!; console.log(`Found device: ${device.name}`); // Disconnect await client3.disconnect(); console.log('Disconnected.'); // Now try to send a command - this will throw console.log('Attempting to send command after disconnect...'); await device.runOutput(DeviceOutput.Vibrate.percent(0.5)); } else { console.log('No devices found to test with.'); await client3.disconnect(); } } catch (e) { handleButtplugError(e); } await waitForEnter('\nPress Enter to exit...'); } main().catch(console.error); ``` **Python:** ```python """Error Handling - Handle errors gracefully. This example shows how to handle various error conditions: - Connection failures - Device communication errors - Server disconnections Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Run this script (server doesn't need to be running to see error handling) """ import asyncio from buttplug import ( ButtplugClient, ButtplugConnectionError, ButtplugDeviceError, ButtplugError, ButtplugHandshakeError, ButtplugPingError, ) async def main() -> None: client = ButtplugClient("Error Handling Example") # Handle disconnection events def on_disconnect() -> None: print("Server disconnected unexpectedly!") client.on_disconnect = on_disconnect # Try to connect with error handling try: print("Attempting to connect to server...") await client.connect("ws://127.0.0.1:12345") print(f"Connected to: {client.server_name}") except ButtplugConnectionError as e: # Server not running or network issue print(f"Connection failed: {e}") print("Is Intiface Central running?") return except ButtplugHandshakeError as e: # Server rejected the connection (version mismatch, etc.) print(f"Handshake failed: {e}") return except ButtplugError as e: # Catch-all for other Buttplug errors print(f"Unexpected error: {e}") return # Scan and control devices with error handling try: print("\nScanning for devices...") await client.start_scanning() await asyncio.sleep(3) await client.stop_scanning() for device in client.devices.values(): print(f"\nControlling: {device.name}") try: await device.vibrate(0.5) await asyncio.sleep(1) await device.stop() print(" Control successful!") except ButtplugDeviceError as e: # Device-specific error (disconnected, doesn't support command) print(f" Device error: {e}") except ButtplugPingError: # Server stopped responding print("Server ping timeout - connection lost") except ButtplugError as e: print(f"Error during operation: {e}") finally: if client.connected: await client.disconnect() print("\nDisconnected cleanly.") if __name__ == "__main__": asyncio.run(main()) ``` Common errors include: * Commands sent to a disconnected device. These can be avoided by monitoring device events. * Boundary errors, such as trying to send values outside of the range a device accepts (these can be caught in the client before they are sent to the user) There are some errors application developers won't see. This includes: * Device scanning errors, as these are logged and displayed by the server side (normally Intiface Central or Engine) * Device connection issues, as device information will only be sent to the client once it's properly connected. --- ## Example Application Now that we've covered most of the basics of Buttplug, here's an example of a simple application. This application provides a simple interfaces for the following workflow: * Scan for Devices * List connected devices * Allow the user to choose a device * Allow the user to send a generic event to the chosen device While most interaction will Buttplug will usually be more complicated or context specific than this, this example ties together all of the components of the client into a simple program. **Rust:** ```rust // Buttplug Rust - Complete Application Example // // This is a complete, working example that demonstrates the full workflow // of a Buttplug application. If you're new to Buttplug, start here! // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central (click "Start Server") // 3. Run: cargo run --bin application use buttplug_client::{ ButtplugClient, ButtplugClientDevice, ButtplugClientError, ButtplugClientEvent, connector::ButtplugRemoteClientConnector, device::ClientDeviceOutputCommand, serializer::ButtplugClientJSONSerializer, }; use buttplug_core::message::{InputType, OutputType}; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; use futures::StreamExt; use tokio::io::{self, AsyncBufReadExt, BufReader}; async fn read_line() -> String { BufReader::new(io::stdin()) .lines() .next_line() .await .unwrap() .unwrap_or_default() } async fn wait_for_input() { let _ = read_line().await; } fn print_device_capabilities(device: &ButtplugClientDevice) { println!(" {}", device.name()); // Check output capabilities (things we can make the device do) let mut outputs = Vec::new(); if device.output_available(OutputType::Vibrate) { outputs.push("Vibrate"); } /* if !device.rotate_features().is_empty() { outputs.push("Rotate"); } if !device.oscillate_features().is_empty() { outputs.push("Oscillate"); } if !device.position_features().is_empty() { outputs.push("Position"); } */ if !outputs.is_empty() { println!(" Outputs: {}", outputs.join(", ")); } // Check input capabilities (sensors we can read) let mut inputs = Vec::new(); if device.input_available(buttplug_core::message::InputType::Battery) { inputs.push("Battery"); } if device.input_available(buttplug_core::message::InputType::Rssi) { inputs.push("RSSI"); } if !inputs.is_empty() { println!(" Inputs: {}", inputs.join(", ")); } println!(); } #[tokio::main] async fn main() -> anyhow::Result<()> { println!("==========================================="); println!(" Buttplug Rust Application Example"); println!("===========================================\n"); // Step 1: Create a client // The client name identifies your application to the server. let client = ButtplugClient::new("My Buttplug Application"); // Step 2: Set up event handlers // Get the event stream BEFORE connecting to avoid missing events. let mut events = client.event_stream(); tokio::spawn(async move { while let Some(event) = events.next().await { match event { ButtplugClientEvent::DeviceAdded(device) => { println!("[+] Device connected: {}", device.name()); } ButtplugClientEvent::DeviceRemoved(info) => { println!("[-] Device disconnected: {}", info.name()); } ButtplugClientEvent::ServerDisconnect => { println!("[!] Server connection lost!"); } ButtplugClientEvent::Error(err) => { println!("[!] Error: {}", err); } _ => {} } } }); // Step 3: Connect to the server println!("Connecting to Intiface Central..."); let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); if let Err(e) = client.connect(connector).await { match e { ButtplugClientError::ButtplugConnectorError(error) => { println!("ERROR: Could not connect to Intiface Central!"); println!("Make sure Intiface Central is running and the server is started."); println!("Default address: ws://127.0.0.1:12345"); println!("Error: {}", error); return Ok(()); } _ => return Err(e.into()), } } println!("Connected!\n"); // Step 4: Scan for devices println!("Scanning for devices..."); println!("Turn on your Bluetooth/USB devices now.\n"); client.start_scanning().await?; // Wait for devices (in a real app, you might use a UI or timeout) println!("Press Enter when your devices are connected..."); wait_for_input().await; client.stop_scanning().await?; // Step 5: Check what devices we found let devices: Vec = client.devices().into_values().collect(); if devices.is_empty() { println!("No devices found. Make sure your device is:"); println!(" - Turned on"); println!(" - In pairing/discoverable mode"); println!(" - Supported by Buttplug (check https://iostindex.com)"); client.disconnect().await?; return Ok(()); } println!("\nFound {} device(s):\n", devices.len()); // Step 6: Display device capabilities for device in &devices { print_device_capabilities(device); } // Step 7: Interactive device control println!("=== Interactive Control ==="); println!("Commands:"); println!(" v <0-100> - Vibrate all devices at percentage"); println!(" s - Stop all devices"); println!(" b - Read battery levels"); println!(" q - Quit\n"); loop { print!("> "); // Flush stdout to ensure prompt is visible use std::io::Write; std::io::stdout().flush().ok(); let input = read_line().await.trim().to_lowercase(); if input.is_empty() { continue; } if let Some(stripped) = input.strip_prefix("v ") { // Vibrate command if let Ok(percent) = stripped.parse::() { if percent <= 100 { let intensity = percent as f64 / 100.0; for device in &devices { if !device.output_available(OutputType::Vibrate) { match device .run_output(&ClientDeviceOutputCommand::Vibrate(intensity.into())) .await { Ok(_) => println!(" {}: vibrating at {}%", device.name(), percent), Err(e) => println!(" {}: error - {}", device.name(), e), } } } } else { println!(" Usage: v <0-100>"); } } else { println!(" Usage: v <0-100>"); } } else if input == "s" { // Stop all devices client.stop_all_devices().await?; println!(" All devices stopped."); } else if input == "b" { // Read battery levels for device in &devices { if device.input_available(InputType::Battery) { match device.battery().await { Ok(battery) => println!(" {}: {}% battery", device.name(), battery), Err(e) => println!(" {}: could not read battery - {}", device.name(), e), } } else { println!(" {}: no battery sensor", device.name()); } } } else if input == "q" { break; } else { println!(" Unknown command. Use v, s, b, or q."); } } // Step 8: Clean up println!("\nStopping devices and disconnecting..."); client.stop_all_devices().await?; client.disconnect().await?; println!("Goodbye!"); Ok(()) } ``` **C#:** ```csharp // Buttplug C# - Complete Application Example // // This is a complete, working example that demonstrates the full workflow // of a Buttplug application. If you're new to Buttplug, start here! // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central (click "Start Server") // 3. Run this example using Buttplug.Client; using Buttplug.Core; using Buttplug.Core.Messages; Console.WriteLine("==========================================="); Console.WriteLine(" Buttplug C# Application Example"); Console.WriteLine("===========================================\n"); // Step 1: Create a client // The client name identifies your application to the server. var client = new ButtplugClient("My Buttplug Application"); // Step 2: Set up event handlers // Always do this BEFORE connecting to avoid missing events. client.DeviceAdded += (_, args) => Console.WriteLine($"[+] Device connected: {args.Device.Name}"); client.DeviceRemoved += (_, args) => Console.WriteLine($"[-] Device disconnected: {args.Device.Name}"); client.ServerDisconnect += (_, _) => Console.WriteLine("[!] Server connection lost!"); client.ErrorReceived += (_, args) => Console.WriteLine($"[!] Error: {args.Exception.Message}"); // Step 3: Connect to the server Console.WriteLine("Connecting to Intiface Central..."); try { await client.ConnectAsync("ws://127.0.0.1:12345"); } catch (ButtplugClientConnectorException) { Console.WriteLine("ERROR: Could not connect to Intiface Central!"); Console.WriteLine("Make sure Intiface Central is running and the server is started."); Console.WriteLine("Default address: ws://127.0.0.1:12345"); return; } Console.WriteLine("Connected!\n"); // Step 4: Scan for devices Console.WriteLine("Scanning for devices..."); Console.WriteLine("Turn on your Bluetooth/USB devices now.\n"); await client.StartScanningAsync(); // Wait for devices (in a real app, you might use a UI or timeout) Console.WriteLine("Press Enter when your devices are connected..."); Console.ReadLine(); await client.StopScanningAsync(); // Step 5: Check what devices we found var devices = client.Devices; if (devices.Length == 0) { Console.WriteLine("No devices found. Make sure your device is:"); Console.WriteLine(" - Turned on"); Console.WriteLine(" - In pairing/discoverable mode"); Console.WriteLine(" - Supported by Buttplug (check https://iostindex.com)"); await client.DisconnectAsync(); return; } Console.WriteLine($"\nFound {devices.Length} device(s):\n"); // Step 6: Display device capabilities foreach (var device in devices) { Console.WriteLine($" {device.Name}"); // Check output capabilities (things we can make the device do) var outputs = new List(); if (device.HasOutput(OutputType.Vibrate)) outputs.Add("Vibrate"); if (device.HasOutput(OutputType.Rotate)) outputs.Add("Rotate"); if (device.HasOutput(OutputType.Oscillate)) outputs.Add("Oscillate"); if (device.HasOutput(OutputType.Position)) outputs.Add("Position"); if (device.HasOutput(OutputType.Constrict)) outputs.Add("Constrict"); if (outputs.Count > 0) Console.WriteLine($" Outputs: {string.Join(", ", outputs)}"); // Check input capabilities (sensors we can read) var inputs = new List(); if (device.HasInput(InputType.Battery)) inputs.Add("Battery"); if (device.HasInput(InputType.RSSI)) inputs.Add("RSSI"); if (device.HasInput(InputType.Button)) inputs.Add("Button"); if (device.HasInput(InputType.Pressure)) inputs.Add("Pressure"); if (inputs.Count > 0) Console.WriteLine($" Inputs: {string.Join(", ", inputs)}"); Console.WriteLine(); } // Step 7: Interactive device control Console.WriteLine("=== Interactive Control ==="); Console.WriteLine("Commands:"); Console.WriteLine(" v <0-100> - Vibrate all devices at percentage"); Console.WriteLine(" s - Stop all devices"); Console.WriteLine(" b - Read battery levels"); Console.WriteLine(" q - Quit\n"); while (true) { Console.Write("> "); var input = Console.ReadLine()?.Trim().ToLower(); if (string.IsNullOrEmpty(input)) continue; try { if (input.StartsWith("v ")) { // Vibrate command if (int.TryParse(input[2..], out var percent) && percent >= 0 && percent <= 100) { var intensity = percent / 100.0; foreach (var device in devices) { if (device.HasOutput(OutputType.Vibrate)) { await device.RunOutputAsync(DeviceOutput.Vibrate.Percent(intensity)); Console.WriteLine($" {device.Name}: vibrating at {percent}%"); } } } else { Console.WriteLine(" Usage: v <0-100>"); } } else if (input == "s") { // Stop all devices await client.StopAllDevicesAsync(); Console.WriteLine(" All devices stopped."); } else if (input == "b") { // Read battery levels foreach (var device in devices) { if (device.HasInput(InputType.Battery)) { var battery = await device.BatteryAsync(); Console.WriteLine($" {device.Name}: {battery * 100:F0}% battery"); } else { Console.WriteLine($" {device.Name}: no battery sensor"); } } } else if (input == "q") { break; } else { Console.WriteLine(" Unknown command. Use v, s, b, or q."); } } catch (ButtplugDeviceException ex) { Console.WriteLine($" Device error: {ex.Message}"); } catch (ButtplugException ex) { Console.WriteLine($" Error: {ex.Message}"); } } // Step 8: Clean up Console.WriteLine("\nStopping devices and disconnecting..."); await client.StopAllDevicesAsync(); await client.DisconnectAsync(); Console.WriteLine("Goodbye!"); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Complete Application Example // // This is a complete, working example that demonstrates the full workflow // of a Buttplug application in a browser. If you're new to Buttplug, start here! // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central (click "Start Server") // 3. Include Buttplug via CDN in your HTML: // // 4. Call runApplicationExample() from your page async function runApplicationExample() { console.log("==========================================="); console.log(" Buttplug Web Application Example"); console.log("===========================================\n"); // Step 1: Create a client // The client name identifies your application to the server. const client = new buttplug.ButtplugClient("My Buttplug Application"); // Step 2: Set up event handlers // Always do this BEFORE connecting to avoid missing events. client.addListener("deviceadded", (device) => { console.log(`[+] Device connected: ${device.name}`); }); client.addListener("deviceremoved", (device) => { console.log(`[-] Device disconnected: ${device.name}`); }); client.addListener("disconnect", () => { console.log("[!] Server connection lost!"); }); // Step 3: Connect to the server console.log("Connecting to Intiface Central..."); try { const connector = new buttplug.ButtplugBrowserWebsocketClientConnector( "ws://127.0.0.1:12345" ); await client.connect(connector); } catch (e) { if (e instanceof buttplug.ButtplugClientConnectorException) { alert( "Could not connect to Intiface Central!\n\n" + "Make sure Intiface Central is running and the server is started.\n" + "Default address: ws://127.0.0.1:12345" ); console.log("ERROR: Could not connect to Intiface Central!"); return; } throw e; } console.log("Connected!\n"); // Step 4: Scan for devices console.log("Scanning for devices..."); console.log("Turn on your Bluetooth/USB devices now.\n"); await client.startScanning(); // Wait for devices (using alert/confirm for browser interaction) alert("Scanning for devices...\n\nTurn on your devices, then click OK when ready."); await client.stopScanning(); // Step 5: Check what devices we found const devices = Array.from(client.devices.values()); if (devices.length === 0) { alert( "No devices found!\n\n" + "Make sure your device is:\n" + "- Turned on\n" + "- In pairing/discoverable mode\n" + "- Supported by Buttplug (check https://iostindex.com)" ); console.log("No devices found."); await client.disconnect(); return; } console.log(`\nFound ${devices.length} device(s):\n`); // Step 6: Display device capabilities for (const device of devices) { console.log(` ${device.name}`); // Check output capabilities const outputs = []; if (device.hasOutput(buttplug.OutputType.Vibrate)) outputs.push("Vibrate"); if (device.hasOutput(buttplug.OutputType.Rotate)) outputs.push("Rotate"); if (device.hasOutput(buttplug.OutputType.Oscillate)) outputs.push("Oscillate"); if (device.hasOutput(buttplug.OutputType.Position)) outputs.push("Position"); if (device.hasOutput(buttplug.OutputType.Constrict)) outputs.push("Constrict"); if (outputs.length > 0) { console.log(` Outputs: ${outputs.join(", ")}`); } // Check input capabilities const inputs = []; if (device.hasInput(buttplug.InputType.Battery)) inputs.push("Battery"); if (device.hasInput(buttplug.InputType.RSSI)) inputs.push("RSSI"); if (inputs.length > 0) { console.log(` Inputs: ${inputs.join(", ")}`); } } // Step 7: Interactive device control console.log("\n=== Interactive Control ==="); console.log("Use the prompts to control devices."); let running = true; while (running) { const input = prompt( "Commands:\n" + " v <0-100> - Vibrate all devices at percentage\n" + " s - Stop all devices\n" + " b - Read battery levels\n" + " q - Quit\n\n" + "Enter command:" ); if (input === null) { // User clicked Cancel running = false; continue; } const cmd = input.trim().toLowerCase(); if (!cmd) continue; try { if (cmd.startsWith("v ")) { // Vibrate command const percentStr = cmd.slice(2); const percent = parseInt(percentStr, 10); if (!isNaN(percent) && percent >= 0 && percent <= 100) { const intensity = percent / 100.0; for (const device of devices) { if (device.hasOutput(buttplug.OutputType.Vibrate)) { await device.runOutput(buttplug.DeviceOutput.Vibrate.percent(intensity)); console.log(` ${device.name}: vibrating at ${percent}%`); } } } else { alert("Usage: v <0-100>"); } } else if (cmd === "s") { // Stop all devices await client.stopAllDevices(); console.log(" All devices stopped."); } else if (cmd === "b") { // Read battery levels let batteryInfo = "Battery Levels:\n\n"; for (const device of devices) { if (device.hasInput(buttplug.InputType.Battery)) { try { const battery = await device.battery(); const msg = `${device.name}: ${(battery * 100).toFixed(0)}%`; console.log(` ${msg}`); batteryInfo += msg + "\n"; } catch (e) { console.log(` ${device.name}: could not read battery`); batteryInfo += `${device.name}: could not read battery\n`; } } else { console.log(` ${device.name}: no battery sensor`); batteryInfo += `${device.name}: no battery sensor\n`; } } alert(batteryInfo); } else if (cmd === "q") { running = false; } else { alert("Unknown command. Use v, s, b, or q."); } } catch (e) { if (e instanceof buttplug.ButtplugDeviceError) { console.log(` Device error: ${e.message}`); alert(`Device error: ${e.message}`); } else if (e instanceof buttplug.ButtplugError) { console.log(` Error: ${e.message}`); alert(`Error: ${e.message}`); } else { throw e; } } } // Step 8: Clean up console.log("\nStopping devices and disconnecting..."); await client.stopAllDevices(); await client.disconnect(); console.log("Goodbye!"); } ``` **TypeScript:** ```typescript // Buttplug TypeScript - Complete Application Example // // This is a complete, working example that demonstrates the full workflow // of a Buttplug application. If you're new to Buttplug, start here! // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central (click "Start Server") // 3. Run: npx ts-node --esm application-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientDevice, ButtplugClientConnectorException, ButtplugDeviceError, ButtplugError, DeviceOutput, OutputType, InputType, } from 'buttplug'; import * as readline from 'readline'; function createReadlineInterface(): readline.Interface { return readline.createInterface({ input: process.stdin, output: process.stdout, }); } async function waitForEnter(prompt: string): Promise { const rl = createReadlineInterface(); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } async function prompt(question: string): Promise { const rl = createReadlineInterface(); return new Promise((resolve) => { rl.question(question, (answer) => { rl.close(); resolve(answer); }); }); } async function main(): Promise { console.log('==========================================='); console.log(' Buttplug TypeScript Application Example'); console.log('===========================================\n'); // Step 1: Create a client // The client name identifies your application to the server. const client = new ButtplugClient('My Buttplug Application'); // Step 2: Set up event handlers // Always do this BEFORE connecting to avoid missing events. client.addListener('deviceadded', (device: ButtplugClientDevice) => { console.log(`[+] Device connected: ${device.name}`); }); client.addListener('deviceremoved', (device: ButtplugClientDevice) => { console.log(`[-] Device disconnected: ${device.name}`); }); client.addListener('disconnect', () => { console.log('[!] Server connection lost!'); }); // Step 3: Connect to the server console.log('Connecting to Intiface Central...'); try { const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); await client.connect(connector); } catch (e) { if (e instanceof ButtplugClientConnectorException) { console.log('ERROR: Could not connect to Intiface Central!'); console.log( 'Make sure Intiface Central is running and the server is started.' ); console.log('Default address: ws://127.0.0.1:12345'); return; } throw e; } console.log('Connected!\n'); // Step 4: Scan for devices console.log('Scanning for devices...'); console.log('Turn on your Bluetooth/USB devices now.\n'); await client.startScanning(); // Wait for devices await waitForEnter('Press Enter when your devices are connected...'); await client.stopScanning(); // Step 5: Check what devices we found const devices = Array.from(client.devices.values()); if (devices.length === 0) { console.log('No devices found. Make sure your device is:'); console.log(' - Turned on'); console.log(' - In pairing/discoverable mode'); console.log(' - Supported by Buttplug (check https://iostindex.com)'); await client.disconnect(); return; } console.log(`\nFound ${devices.length} device(s):\n`); // Step 6: Display device capabilities for (const device of devices) { console.log(` ${device.name}`); // Check output capabilities (things we can make the device do) const outputs: string[] = []; if (device.hasOutput(OutputType.Vibrate)) outputs.push('Vibrate'); if (device.hasOutput(OutputType.Rotate)) outputs.push('Rotate'); if (device.hasOutput(OutputType.Oscillate)) outputs.push('Oscillate'); if (device.hasOutput(OutputType.Position)) outputs.push('Position'); if (device.hasOutput(OutputType.Constrict)) outputs.push('Constrict'); if (outputs.length > 0) { console.log(` Outputs: ${outputs.join(', ')}`); } // Check input capabilities (sensors we can read) const inputs: string[] = []; if (device.hasInput(InputType.Battery)) inputs.push('Battery'); if (device.hasInput(InputType.RSSI)) inputs.push('RSSI'); if (device.hasInput(InputType.Button)) inputs.push('Button'); if (device.hasInput(InputType.Pressure)) inputs.push('Pressure'); if (inputs.length > 0) { console.log(` Inputs: ${inputs.join(', ')}`); } console.log(); } // Step 7: Interactive device control console.log('=== Interactive Control ==='); console.log('Commands:'); console.log(' v <0-100> - Vibrate all devices at percentage'); console.log(' s - Stop all devices'); console.log(' b - Read battery levels'); console.log(' q - Quit\n'); let running = true; while (running) { const input = (await prompt('> ')).trim().toLowerCase(); if (!input) continue; try { if (input.startsWith('v ')) { // Vibrate command const percentStr = input.slice(2); const percent = parseInt(percentStr, 10); if (!isNaN(percent) && percent >= 0 && percent <= 100) { const intensity = percent / 100.0; for (const device of devices) { if (device.hasOutput(OutputType.Vibrate)) { await device.runOutput(DeviceOutput.Vibrate.percent(intensity)); console.log(` ${device.name}: vibrating at ${percent}%`); } } } else { console.log(' Usage: v <0-100>'); } } else if (input === 's') { // Stop all devices await client.stopAllDevices(); console.log(' All devices stopped.'); } else if (input === 'b') { // Read battery levels for (const device of devices) { if (device.hasInput(InputType.Battery)) { const battery = await device.battery(); console.log(` ${device.name}: ${(battery * 100).toFixed(0)}% battery`); } else { console.log(` ${device.name}: no battery sensor`); } } } else if (input === 'q') { running = false; } else { console.log(' Unknown command. Use v, s, b, or q.'); } } catch (e) { if (e instanceof ButtplugDeviceError) { console.log(` Device error: ${e.message}`); } else if (e instanceof ButtplugError) { console.log(` Error: ${e.message}`); } else { throw e; } } } // Step 8: Clean up console.log('\nStopping devices and disconnecting...'); await client.stopAllDevices(); await client.disconnect(); console.log('Goodbye!'); } main().catch(console.error); ``` **Python:** ```python """Buttplug Python - Complete Application Example This is a complete, working example that demonstrates the full workflow of a Buttplug application. If you're new to Buttplug, start here! Prerequisites: 1. Install Intiface Central: https://intiface.com/central 2. Start the server in Intiface Central (click "Start Server") 3. Run: python application.py """ import asyncio from buttplug import ButtplugClient, DeviceOutputCommand, InputType, OutputType from buttplug.errors import ButtplugDeviceError, ButtplugError def print_device_capabilities(device) -> None: """Print the capabilities of a device.""" print(f" {device.name}") # Check output capabilities (things we can make the device do) outputs = [] if device.has_output(OutputType.VIBRATE): outputs.append("Vibrate") if device.has_output(OutputType.ROTATE): outputs.append("Rotate") if device.has_output(OutputType.OSCILLATE): outputs.append("Oscillate") if device.has_output(OutputType.POSITION) or device.has_output( OutputType.POSITION_WITH_DURATION ): outputs.append("Position") if device.has_output(OutputType.CONSTRICT): outputs.append("Constrict") if outputs: print(f" Outputs: {', '.join(outputs)}") # Check input capabilities (sensors we can read) inputs = [] if device.has_input(InputType.BATTERY): inputs.append("Battery") if device.has_input(InputType.RSSI): inputs.append("RSSI") if inputs: print(f" Inputs: {', '.join(inputs)}") print() async def main() -> None: print("===========================================") print(" Buttplug Python Application Example") print("===========================================\n") # Step 1: Create a client # The client name identifies your application to the server. client = ButtplugClient("My Buttplug Application") # Step 2: Set up event handlers # Always do this BEFORE connecting to avoid missing events. client.on_device_added = lambda d: print(f"[+] Device connected: {d.name}") client.on_device_removed = lambda d: print(f"[-] Device disconnected: {d.name}") client.on_disconnect = lambda: print("[!] Server connection lost!") # Step 3: Connect to the server print("Connecting to Intiface Central...") try: await client.connect("ws://127.0.0.1:12345") except ButtplugError as e: print("ERROR: Could not connect to Intiface Central!") print("Make sure Intiface Central is running and the server is started.") print("Default address: ws://127.0.0.1:12345") print(f"Error: {e}") return print("Connected!\n") # Step 4: Scan for devices print("Scanning for devices...") print("Turn on your Bluetooth/USB devices now.\n") await client.start_scanning() # Wait for devices (in a real app, you might use a UI or timeout) input("Press Enter when your devices are connected...") await client.stop_scanning() # Step 5: Check what devices we found devices = list(client.devices.values()) if not devices: print("No devices found. Make sure your device is:") print(" - Turned on") print(" - In pairing/discoverable mode") print(" - Supported by Buttplug (check https://iostindex.com)") await client.disconnect() return print(f"\nFound {len(devices)} device(s):\n") # Step 6: Display device capabilities for device in devices: print_device_capabilities(device) # Step 7: Interactive device control print("=== Interactive Control ===") print("Commands:") print(" v <0-100> - Vibrate all devices at percentage") print(" s - Stop all devices") print(" b - Read battery levels") print(" q - Quit\n") while True: try: user_input = input("> ").strip().lower() except EOFError: break if not user_input: continue try: if user_input.startswith("v "): # Vibrate command try: percent = int(user_input[2:]) if 0 <= percent <= 100: intensity = percent / 100.0 for device in devices: if device.has_output(OutputType.VIBRATE): await device.run_output( DeviceOutputCommand(OutputType.VIBRATE, intensity) ) print(f" {device.name}: vibrating at {percent}%") else: print(" Usage: v <0-100>") except ValueError: print(" Usage: v <0-100>") elif user_input == "s": # Stop all devices await client.stop_all_devices() print(" All devices stopped.") elif user_input == "b": # Read battery levels for device in devices: if device.has_input(InputType.BATTERY): try: battery = await device.battery() print(f" {device.name}: {battery * 100:.0f}% battery") except ButtplugDeviceError as e: print(f" {device.name}: could not read battery - {e}") else: print(f" {device.name}: no battery sensor") elif user_input == "q": break else: print(" Unknown command. Use v, s, b, or q.") except ButtplugDeviceError as e: print(f" Device error: {e}") except ButtplugError as e: print(f" Error: {e}") # Step 8: Clean up print("\nStopping devices and disconnecting...") await client.stop_all_devices() await client.disconnect() print("Goodbye!") if __name__ == "__main__": asyncio.run(main()) ``` --- ## Connecting to a Buttplug Server Once you've created a connector, it's time to connect to a server! As all connector setup was done via the Connector setup, this is now just down to dealing with whether the connection process actually worked or not. Network connections for websockets can fail due to usual connection issues (wrong address, server not up, network not on, etc...). There is also a chance that the client and server could have a version mismatch. We'll cover this in the next section. **Rust:** ```rust use buttplug_client::{ ButtplugClient, ButtplugClientError, connector::ButtplugRemoteClientConnector, serializer::ButtplugClientJSONSerializer, }; use buttplug_core::errors::ButtplugError; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; use tokio::io::{self, AsyncBufReadExt, BufReader}; async fn wait_for_input() { BufReader::new(io::stdin()) .lines() .next_line() .await .unwrap(); } #[tokio::main] async fn main() -> anyhow::Result<()> { // After you've created a connector, the connection looks the same no // matter what, though the errors thrown may be different. let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); // Now we connect. If anything goes wrong here, we'll get an Err with either // // - A ButtplugClientConnectionError if there's a problem with // the Connector, like the network address being wrong, server not // being up, etc. // - A ButtplugHandshakeError if there is a client/server version // mismatch. let client = ButtplugClient::new("Example Client"); if let Err(e) = client.connect(connector).await { match e { ButtplugClientError::ButtplugConnectorError(error) => { // If our connection failed, because the server wasn't turned on, // SSL/TLS wasn't turned off, etc, we'll just print and exit // here. println!("Can't connect, exiting! Message: {}", error); wait_for_input().await; return Ok(()); } ButtplugClientError::ButtplugError(error) => match error { ButtplugError::ButtplugHandshakeError(error) => { // This means our client is newer than our server, and we need to // upgrade the server we're connecting to. println!("Handshake issue, exiting! Message: {}", error); wait_for_input().await; return Ok(()); } error => { println!("Unexpected error type! {}", error); wait_for_input().await; return Ok(()); } }, _ => { // None of the other errors are valid in this instance. } } }; // We're connected, yay! println!("Connected! Check Server for Client Name."); wait_for_input().await; // And now we disconnect as usual client.disconnect().await?; Ok(()) } ``` **C#:** ```csharp // Buttplug C# - Connection Example // // This example demonstrates how to connect to a Buttplug server // (like Intiface Central) and handle connection errors. using Buttplug.Client; using Buttplug.Core; // Create a client with your application's name. // This name will be shown in Intiface Central. var client = new ButtplugClient("Connection Example"); try { // Connect to the server. The extension method creates a WebSocket connector // automatically from the URI string. Default port for Intiface Central is 12345. await client.ConnectAsync("ws://127.0.0.1:12345"); Console.WriteLine("Connected! Check Intiface Central for the client name."); Console.WriteLine("Press Enter to disconnect..."); Console.ReadLine(); // Disconnect cleanly await client.DisconnectAsync(); } catch (ButtplugClientConnectorException ex) { // Connection failed - server not running, wrong address, network issues, etc. Console.WriteLine($"Can't connect to server: {ex.Message}"); Console.WriteLine("Make sure Intiface Central is running and the server is started."); } catch (ButtplugHandshakeException ex) { // Client/server version mismatch - need to upgrade one or the other Console.WriteLine($"Handshake failed: {ex.Message}"); Console.WriteLine("Client and server versions may be incompatible."); } catch (ButtplugException ex) { // Other Buttplug-specific errors Console.WriteLine($"Buttplug error: {ex.Message}"); } Console.WriteLine("Press Enter to exit..."); Console.ReadLine(); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Remote Websocket Connector Example // // This example demonstrates how to connect to a remote Buttplug server // using the websocket connector. This is the standard way to connect // from a browser to Intiface Central. // // Include Buttplug via CDN: // const runWebsocketConnectionExample = async () => { // This is the default insecure address for Intiface Central (https://intiface.com/central). // You can connect to it via most browsers. const address = "ws://localhost:12345"; // Create the connector with the server address const connector = new buttplug.ButtplugBrowserWebsocketClientConnector(address); const client = new buttplug.ButtplugClient("Websocket Connection Example"); // Set up disconnect handler before connecting client.addListener("disconnect", () => { console.log("Server connection lost!"); }); // Now we connect. If anything goes wrong here, we'll either throw: // // - A ButtplugClientConnectorException if there's a problem with // the connector, like the network address being wrong, server not // being up, etc. // - A ButtplugInitError if there is a client/server version mismatch. try { console.log(`Connecting to ${address}...`); await client.connect(connector); } catch (ex) { // If our connection failed, because the server wasn't turned on, SSL/TLS // wasn't turned off, etc, we'll just print and exit here. // // This could also mean our client is newer than our server, and we need to // upgrade the server we're connecting to. console.log("Connection failed:", ex); return; } // We're connected! console.log("Connected!"); console.log("Connection will disconnect automatically in 3 seconds..."); // Demonstrate we can use the connection await client.startScanning(); console.log("Scanning for devices..."); // Disconnect after a delay setTimeout(async () => { console.log("Stopping scan..."); await client.stopScanning(); // Show any devices that were found if (client.devices.size > 0) { console.log("Devices found:"); for (const [index, device] of client.devices) { console.log(` - ${device.name} (Index: ${index})`); } } console.log("Disconnecting..."); await client.disconnect(); console.log("Disconnected."); }, 3000); }; ``` **TypeScript:** ```typescript // Buttplug TypeScript - Connection Example // // This example demonstrates how to connect to a Buttplug server // (like Intiface Central) and handle connection errors. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm connection-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientConnectorException, ButtplugError, ButtplugInitError, } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } async function main(): Promise { // Create a client with your application's name. // This name will be shown in Intiface Central. const client = new ButtplugClient('Connection Example'); try { // Create a connector to the server. Default port for Intiface Central is 12345. const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); console.log('Connecting to Intiface Central...'); await client.connect(connector); // We're connected! console.log('Connected! Check Intiface Central for the client name.'); await waitForEnter('Press Enter to disconnect...'); // Disconnect cleanly await client.disconnect(); console.log('Disconnected.'); } catch (e) { if (e instanceof ButtplugClientConnectorException) { // Connection failed - server not running, wrong address, network issues, etc. console.log(`Can't connect to server: ${e.message}`); console.log( 'Make sure Intiface Central is running and the server is started.' ); } else if (e instanceof ButtplugInitError) { // Client/server version mismatch - need to upgrade one or the other console.log(`Handshake failed: ${e.message}`); console.log('Client and server versions may be incompatible.'); } else if (e instanceof ButtplugError) { // Other Buttplug-specific errors console.log(`Buttplug error: ${e.message}`); } else { throw e; } } await waitForEnter('Press Enter to exit...'); } main().catch(console.error); ``` **Python:** ```python """Connection - Connect to a Buttplug server. This is the simplest possible Buttplug example. It connects to a Buttplug server (like Intiface Central) and shows connection status. Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Start Intiface Central and click "Start Server" 3. Run this script: python connection.py """ import asyncio from buttplug import ButtplugClient, ButtplugError async def main() -> None: # Create a client with your application's name client = ButtplugClient("Connection Example") try: # Connect to the server (Intiface Central default address) print("Connecting to server...") await client.connect("ws://127.0.0.1:12345") print(f"Connected to: {client.server_name}") # Connection is established - you can now scan for devices print("Connection successful!") except ButtplugError as e: # Handle connection errors print(f"Failed to connect: {e}") return finally: # Always disconnect when done if client.connected: await client.disconnect() print("Disconnected.") if __name__ == "__main__": asyncio.run(main()) ``` ## Client/Server Compatibility tl;dr As long as the server API version is equal to or greater (newer) than the client API version, things should be fine. To see the full explanation and rules on API versioning, see the [protocol portion of the architecture section.](/docs/dev-guide/architecture/protocol-in-depth#spec-versions-and-message-additions) ## What to Expect on Successful Connect In most cases, connectors are only used for the initial connection setup, then you can pretty much forget about them after that. Everything will look the same across all connector types from here on out. Now that you know how to get a Buttplug session running, you're ready to enumerate and control devices! --- ## Connectors The first thing to do when writing a Buttplug application is figuring out how to talk to a Buttplug Server (like [Intiface Central](/docs/dev-guide/architecture/intiface.md)). For sake of simplicity, we'll cover websockets in this part of the manual, as this is by far the most common method of connecting clients and servers. Other connection situations and solutions (WebRTC, iroh, etc...) are covered in the [cookbook](/docs/dev-guide/cookbook/intro.md) section. ## Websocket Connectors Websockets are the default connector transport for Buttplug. They work as both a transport for desktop applications and web browsers, and have implementations available in most programming popular languages. As the library does not send many messages (maybe 50 per second in busy cases), the overhead of websockets isn't really an issue for the library. Client implementations made by the Buttplug Core Team will provide a websocket connector for you. You should be able to create the connector, define the server address, and use that to connect. For using Websocket servers, you'll need to provide the user a way to pass in the server address (as this will not always exist on the same machine your software is running on), then you just create the connector object using that address. > **Tip: The Accidental Standard Port of 12345** When Buttplug's first public server came out in 2017, it used port 12345 as a test value. This stuck with the system, so now most applications that use Intiface or Buttplug use port 12345 for connection by default. Some client applications have gone as far as to hardcore the value, but this is not recommended. This can sometimes be an issue for users running certain software that collides with the port. [We have some recommended fixes in the Intiface Central Documentation.](https://docs.intiface.com/docs/intiface-central/troubleshooting#checking-for-other-programs-that-collide-network-ports) **Rust:** ```rust use buttplug_client::{ ButtplugClient, connector::ButtplugRemoteClientConnector, serializer::ButtplugClientJSONSerializer, }; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; #[tokio::main] async fn main() -> anyhow::Result<()> { // To create a Websocket Connector, you need the websocket address and some generics fuckery. let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); let client = ButtplugClient::new("Example Client"); client.connect(connector).await?; Ok(()) } ``` **C#:** ```csharp // Buttplug C# - Remote Connector Example // // This example demonstrates the explicit WebSocket connector setup. // While the ConnectAsync(string) extension method is convenient, // creating the connector explicitly gives you more control. using Buttplug.Client; // Method 1: Using the convenience extension (recommended for most cases) // This creates a WebSocket connector automatically from a URI string. var client1 = new ButtplugClient("Simple Connection"); // Method 2: Using a Uri object // Still uses the extension method, but allows Uri manipulation first. var client2 = new ButtplugClient("Uri Connection"); var uri = new Uri("ws://127.0.0.1:12345"); // Method 3: Explicit connector creation // Use this when you need custom connector configuration or // when implementing a custom connector. var client3 = new ButtplugClient("Explicit Connector"); var connector = new ButtplugWebsocketConnector(new Uri("ws://127.0.0.1:12345")); // Let's actually connect using the explicit connector method try { await client3.ConnectAsync(connector); Console.WriteLine("Connected!"); Console.WriteLine($" Client name: {client3.Name}"); Console.WriteLine($" Connected: {client3.Connected}"); Console.WriteLine("\nPress Enter to disconnect..."); Console.ReadLine(); await client3.DisconnectAsync(); Console.WriteLine("Disconnected."); } catch (Exception ex) { Console.WriteLine($"Connection failed: {ex.Message}"); Console.WriteLine("\nMake sure Intiface Central is running with the server started."); } Console.WriteLine("\nPress Enter to exit..."); Console.ReadLine(); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Remote Websocket Connector Example // // This example demonstrates how to connect to a remote Buttplug server // using the websocket connector. This is the standard way to connect // from a browser to Intiface Central. // // Include Buttplug via CDN: // const runWebsocketConnectionExample = async () => { // This is the default insecure address for Intiface Central (https://intiface.com/central). // You can connect to it via most browsers. const address = "ws://localhost:12345"; // Create the connector with the server address const connector = new buttplug.ButtplugBrowserWebsocketClientConnector(address); const client = new buttplug.ButtplugClient("Websocket Connection Example"); // Set up disconnect handler before connecting client.addListener("disconnect", () => { console.log("Server connection lost!"); }); // Now we connect. If anything goes wrong here, we'll either throw: // // - A ButtplugClientConnectorException if there's a problem with // the connector, like the network address being wrong, server not // being up, etc. // - A ButtplugInitError if there is a client/server version mismatch. try { console.log(`Connecting to ${address}...`); await client.connect(connector); } catch (ex) { // If our connection failed, because the server wasn't turned on, SSL/TLS // wasn't turned off, etc, we'll just print and exit here. // // This could also mean our client is newer than our server, and we need to // upgrade the server we're connecting to. console.log("Connection failed:", ex); return; } // We're connected! console.log("Connected!"); console.log("Connection will disconnect automatically in 3 seconds..."); // Demonstrate we can use the connection await client.startScanning(); console.log("Scanning for devices..."); // Disconnect after a delay setTimeout(async () => { console.log("Stopping scan..."); await client.stopScanning(); // Show any devices that were found if (client.devices.size > 0) { console.log("Devices found:"); for (const [index, device] of client.devices) { console.log(` - ${device.name} (Index: ${index})`); } } console.log("Disconnecting..."); await client.disconnect(); console.log("Disconnected."); }, 3000); }; ``` **TypeScript:** ```typescript // Buttplug TypeScript - Remote Connector Example // // This example demonstrates the explicit WebSocket connector setup. // While you can create a connector inline, creating it explicitly // gives you more control over the connection parameters. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm remote-connector-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugBrowserWebsocketClientConnector, } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } async function main(): Promise { // Method 1: Inline connector creation (most common) // This is the simplest approach for most applications. console.log('Method 1: Inline connector creation'); console.log(' const connector = new ButtplugNodeWebsocketClientConnector(url);'); console.log(' await client.connect(connector);'); console.log(' (Simple and direct)\n'); // Method 2: Explicit connector creation // Use this when you need to reuse the connector or // configure it before connecting. console.log('Method 2: Explicit connector creation'); console.log(' const connector = new ButtplugNodeWebsocketClientConnector(url);'); console.log(' // ... configure connector if needed ...'); console.log(' await client.connect(connector);'); console.log(' (More control over connector lifecycle)\n'); // Note about environments: // - Node.js: Use ButtplugNodeWebsocketClientConnector (uses 'ws' package) // - Browser: Use ButtplugBrowserWebsocketClientConnector (uses native WebSocket) console.log('Environment-specific connectors:'); console.log(' - Node.js: ButtplugNodeWebsocketClientConnector'); console.log(' - Browser: ButtplugBrowserWebsocketClientConnector\n'); // Let's actually connect using the explicit connector method const client = new ButtplugClient('Remote Connector Example'); const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); console.log('Connecting using explicit connector...'); try { await client.connect(connector); console.log('Connected successfully!'); console.log(` Connected: ${client.connected}`); await waitForEnter('\nPress Enter to disconnect...'); await client.disconnect(); console.log('Disconnected.'); } catch (e) { if (e instanceof Error) { console.log(`Connection failed: ${e.message}`); } console.log( '\nMake sure Intiface Central is running with the server started.' ); } await waitForEnter('\nPress Enter to exit...'); } main().catch(console.error); ``` **Python:** ```python """Connection - Connect to a Buttplug server. This is the simplest possible Buttplug example. It connects to a Buttplug server (like Intiface Central) and shows connection status. Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Start Intiface Central and click "Start Server" 3. Run this script: python connection.py """ import asyncio from buttplug import ButtplugClient, ButtplugError async def main() -> None: # Create a client with your application's name client = ButtplugClient("Connection Example") try: # Connect to the server (Intiface Central default address) print("Connecting to server...") await client.connect("ws://127.0.0.1:12345") print(f"Connected to: {client.server_name}") # Connection is established - you can now scan for devices print("Connection successful!") except ButtplugError as e: # Handle connection errors print(f"Failed to connect: {e}") return finally: # Always disconnect when done if client.connected: await client.disconnect() print("Disconnected.") if __name__ == "__main__": asyncio.run(main()) ``` ### Security Considerations Due to basically being impossible to deal with, [Intiface Engine/Central](/docs/dev-guide/architecture/intiface.md) does not implement SSL websockets (wss). This required self-signed certificates which rarely worked correctly and caused end-user confusion. Non-secured websockets work for Intiface Central instances running on the same host as web apps, due to localhost security exceptions. Remote browser connections (i.e. browser on desktop, intiface central on phone) may fail due to security requirements. Intiface Central provides a [Repeater Mode](https://docs.intiface.com/docs/intiface-central/ui/app-modes-repeater-panel) (basically a proxy) to work with instances where web browsers on a machine other than the Intiface Central is accessing hardware. --- ## Device Control We've connected, we've enumerated, now it's time for the important stuff. Device Control! ## Device Capabilities The devices Buttplug supports can do many different things. They may vibrate, stroke, rotate, some combination of all of these, or possibly something completely different. In order to trigger these different mechanisms, OutputCmd Messages are used. For now we'll just look at vibrating and stopping, but there's descriptions of other messages in the Winning Ways section. When a device is added, it comes with a list of features that OutputCmd can refer to, as well as certain parameters for those features. For instance, if you have a vibrating buttplug (an actual buttplug toy) can be accessed using the following messages: - OutputCmd - This will take a feature index, feature type (for this, Vibrate), and a value in steps/percent, which the client library is expected to turn into a message for you. - StopCmd - This command takes no arguments, and simply stops a feature/device from whatever its doing. The Buttplug Server has enough information to know what actions a device or feature can perform, so it handles making sure all of those actions are stopped. You'll usually interact with devices with Device instances, which will be different than the Buttplug Client. While the Client handles things like scanning and device lists, a Device instance will let you command a specific device. > **Tip: Didn't we used to be able to update multiple features at a time?** Yes! And it was really complicated! And almost no one used that functionality! And something like < 10% of the devices we support even have > 1 output features! In the Buttplug v4 message spec, we now put the burden of messages aggregation on the Server. Users send one command for one feature of one device, and we do the work on the backend to smash all of those commands together into the smallest possible packet to go to the hardware. If you're curious about the way this works, check the [Devices and Commands section of this guide](../cookbook/devices-and-commands/intro.md). ## Sending Device Messages As a user of a Buttplug Client API, you should never be expected to send raw Buttplug Messages. Most Client APIs will provide message sending functions for you, usually attached to device objects or structures. If the device accepts the message type represented by the function you call, it should be sent to the device. Otherwise, you'll receive an error about message compatibility. **Rust:** ```rust use buttplug_client::{ ButtplugClient, ButtplugClientError, connector::ButtplugRemoteClientConnector, device::{ClientDeviceCommandValue, ClientDeviceOutputCommand}, serializer::ButtplugClientJSONSerializer, }; use buttplug_core::message::OutputType; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; use strum::IntoEnumIterator; use tokio::io::{self, AsyncBufReadExt, BufReader}; async fn wait_for_input() { BufReader::new(io::stdin()) .lines() .next_line() .await .unwrap(); } #[tokio::main] async fn main() -> anyhow::Result<()> { let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); let client = ButtplugClient::new("Example Client"); client.connect(connector).await?; println!("Connected!"); // You usually shouldn't run Start/Stop scanning back-to-back like // this, but with TestDevice we know our device will be found when we // call StartScanning, so we can get away with it. client.start_scanning().await?; client.stop_scanning().await?; println!("Client currently knows about these devices:"); let mut device_index: i32 = -1; for (i, device) in client.devices() { device_index = i as i32; println!("- {}", device.name()); } wait_for_input().await; for (_, device) in client.devices() { println!("{} supports these outputs:", device.name()); for output_type in OutputType::iter() { for feature in device.device_features().values() { if feature.feature().contains_output(output_type) { println!("- {}", output_type); } } } } println!("Sending commands"); // Now that we know the message types for our connected device, we // can send a message over! Seeing as we want to stick with the // modern generic messages, we'll go with VibrateCmd. // // There's a couple of ways to send this message. let devices = client.devices(); let test_client_device = devices.get(&(device_index as u32)).unwrap(); // We can use the convenience functions on ButtplugClientDevice to // send the message. This version sets all of the motors on a // vibrating device to the same speed. test_client_device .run_output(&ClientDeviceOutputCommand::Vibrate( ClientDeviceCommandValue::Percent(0.5f64), )) .await?; // If we wanted to just set one motor on and the other off, we could // try this version that uses an array. It'll throw an exception if // the array isn't the same size as the number of motors available as // denoted by FeatureCount, though. // // You can get the vibrator count using the following code, though we // know it's 2 so we don't really have to use it. let vibrator_count = test_client_device.outputs(OutputType::Vibrate).len(); println!( "{} has {} vibrators.", test_client_device.name(), vibrator_count, ); // Just set all of the vibrators to full speed. if vibrator_count > 0 { test_client_device .run_output(&ClientDeviceOutputCommand::Vibrate( ClientDeviceCommandValue::Steps(10), )) .await?; } else { println!("Device does not have > 1 vibrators, not running multiple vibrator test."); } wait_for_input().await; println!("Disconnecting"); // And now we disconnect as usual. client.disconnect().await?; println!("Trying error"); // If we try to send a command to a device after the client has // disconnected, we'll get an exception thrown. let vibrate_result = test_client_device .run_output(&ClientDeviceOutputCommand::Vibrate( ClientDeviceCommandValue::Steps(30), )) .await; if let Err(ButtplugClientError::ButtplugConnectorError(error)) = vibrate_result { println!("Tried to send after disconnection! Error: "); println!("{}", error); } wait_for_input().await; Ok(()) } ``` **C#:** ```csharp // Buttplug C# - Device Control Example // // This example demonstrates how to send commands to devices, // query device capabilities, and use the command builder API. using Buttplug.Client; using Buttplug.Core.Messages; var client = new ButtplugClient("Device Control Example"); // Connect and scan for devices await client.ConnectAsync("ws://127.0.0.1:12345"); await client.StartScanningAsync(); Console.WriteLine("Turn on a device, then press Enter..."); Console.ReadLine(); await client.StopScanningAsync(); // Check if we have any devices if (client.Devices.Length == 0) { Console.WriteLine("No devices found. Exiting."); await client.DisconnectAsync(); return; } // Get the first device var device = client.Devices[0]; Console.WriteLine($"\nUsing device: {device.Name}"); // Show what output types this device supports Console.WriteLine("\nSupported output types:"); foreach (var feature in device.Features.Values) { var outputs = feature.FeatureDefinition.Output; if (outputs != null) { foreach (var outputType in outputs) { Console.WriteLine($" - {outputType} (Feature {feature.FeatureIndex}: {feature.FeatureDescription})"); } } } // Check for vibration support and demonstrate commands if (device.HasOutput(OutputType.Vibrate)) { var vibrateFeatures = device.GetFeaturesWithOutput(OutputType.Vibrate).ToList(); Console.WriteLine($"\nDevice has {vibrateFeatures.Count} vibrator(s)."); // Method 1: Use the convenience extension method await device.RunOutputAsync(DeviceOutput.Vibrate.Percent(0.5)); await Task.Delay(1000); // Method 2: Use the command builder API for more control await device.RunOutputAsync(DeviceOutput.Vibrate.Percent(0.75)); await Task.Delay(1000); // Method 3: Send command to a specific feature if (vibrateFeatures.Count > 0) { var firstVibrator = vibrateFeatures[0]; await device.RunOutputAsync(firstVibrator.FeatureIndex, DeviceOutput.Vibrate.Percent(0.25)); await Task.Delay(1000); } // Stop the device await device.StopAsync(); } else { Console.WriteLine("\nDevice does not support vibration."); } // Demonstrate other output types if available if (device.HasOutput(OutputType.Rotate)) { await device.RunOutputAsync(DeviceOutput.Rotate.Percent(0.5)); await Task.Delay(1000); await device.StopAsync(); } if (device.HasOutput(OutputType.Position)) { await device.RunOutputAsync(DeviceOutput.PositionWithDuration.Percent(1.0, 500)); await Task.Delay(1000); await device.RunOutputAsync(DeviceOutput.PositionWithDuration.Percent(0.0, 500)); } // Read battery level if supported if (device.HasInput(InputType.Battery)) { var battery = await device.BatteryAsync(); Console.WriteLine($"Battery: {battery * 100:F0}%"); } Console.WriteLine("\nPress Enter to disconnect..."); Console.ReadLine(); // Disconnect - this automatically stops all devices await client.DisconnectAsync(); Console.WriteLine("Disconnected."); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Device Control Example // // This example demonstrates how to send commands to devices, // query device capabilities, and use the v4 command builder API. // // Include Buttplug via CDN: // async function runDeviceControlExample() { const connector = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345"); const client = new buttplug.ButtplugClient("Device Control Example"); // Set up event handlers before connecting client.addListener("deviceadded", async (device) => { console.log(`Device connected: ${device.name}`); // Show currently connected devices (client.devices is a Map in v4) console.log("Currently connected devices:"); for (const [index, dev] of client.devices) { console.log(` - ${dev.name} (Index: ${index})`); } // Check if device supports vibration using v4 API if (!device.hasOutput(buttplug.OutputType.Vibrate)) { console.log("Device does not support vibration, skipping control demo."); return; } console.log("Device supports vibration. Sending commands..."); try { // Use the v4 command builder API console.log("Vibrating at 100%..."); await device.runOutput(buttplug.DeviceOutput.Vibrate.percent(1.0)); await new Promise(r => setTimeout(r, 1000)); console.log("Vibrating at 50%..."); await device.runOutput(buttplug.DeviceOutput.Vibrate.percent(0.5)); await new Promise(r => setTimeout(r, 1000)); console.log("Stopping device..."); await device.stop(); } catch (e) { console.log("Error sending command:", e); if (e instanceof buttplug.ButtplugDeviceError) { console.log("This is a device error - device may have disconnected."); } } // Check for battery support using v4 API if (device.hasInput(buttplug.InputType.Battery)) { try { const level = await device.battery(); console.log(`${device.name} Battery Level: ${(level * 100).toFixed(0)}%`); } catch (e) { console.log("Could not read battery level:", e); } } // Demonstrate other output types if available if (device.hasOutput(buttplug.OutputType.Rotate)) { console.log("Device supports rotation. Rotating at 50%..."); await device.runOutput(buttplug.DeviceOutput.Rotate.percent(0.5)); await new Promise(r => setTimeout(r, 1000)); await device.stop(); } if (device.hasOutput(buttplug.OutputType.Position)) { console.log("Device supports position control. Moving..."); await device.runOutput(buttplug.DeviceOutput.PositionWithDuration.percent(1.0, 500)); await new Promise(r => setTimeout(r, 1000)); await device.runOutput(buttplug.DeviceOutput.PositionWithDuration.percent(0.0, 500)); } }); client.addListener("deviceremoved", (device) => { console.log(`Device disconnected: ${device.name}`); }); console.log("Connecting..."); await client.connect(connector); console.log("Connected! Scanning for devices..."); await client.startScanning(); } ``` **TypeScript:** ```typescript // Buttplug TypeScript - Device Control Example // // This example demonstrates how to send commands to devices, // query device capabilities, and use the command builder API. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm device-control-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientDevice, DeviceOutput, OutputType, InputType, } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } function delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } async function main(): Promise { const client = new ButtplugClient('Device Control Example'); // Connect and scan for devices const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); console.log('Connecting...'); await client.connect(connector); console.log('Connected! Scanning for devices...'); await client.startScanning(); await waitForEnter('Turn on a device, then press Enter...'); await client.stopScanning(); // Check if we have any devices if (client.devices.size === 0) { console.log('No devices found. Exiting.'); await client.disconnect(); return; } // Get the first device const device: ButtplugClientDevice = client.devices.values().next().value!; console.log(`\nUsing device: ${device.name}`); // Show what output types this device supports console.log('\nSupported output types:'); for (const [index, feature] of device.features) { for (const output of feature.outputs.values()) { console.log( ` - ${output.type} (Feature ${index}: ${feature.descriptor})` ); } } // Check for vibration support and demonstrate commands if (device.hasOutput(OutputType.Vibrate)) { console.log('\nDevice supports vibration.'); // Use the command builder API console.log('Vibrating at 50% using command builder...'); await device.runOutput(DeviceOutput.Vibrate.percent(0.5)); await delay(1000); console.log('Vibrating at 75%...'); await device.runOutput(DeviceOutput.Vibrate.percent(0.75)); await delay(1000); console.log('Vibrating at 25%...'); await device.runOutput(DeviceOutput.Vibrate.percent(0.25)); await delay(1000); // Stop the device console.log('Stopping device...'); await device.stop(); } else { console.log('\nDevice does not support vibration.'); } // Demonstrate other output types if available if (device.hasOutput(OutputType.Rotate)) { console.log('\nDevice supports rotation. Rotating at 50%...'); await device.runOutput(DeviceOutput.Rotate.percent(0.5)); await delay(1000); await device.stop(); } if (device.hasOutput(OutputType.Position)) { console.log('\nDevice supports position control. Moving to 100% over 500ms...'); await device.runOutput(DeviceOutput.PositionWithDuration.percent(1.0, 500)); await delay(1000); await device.runOutput(DeviceOutput.PositionWithDuration.percent(0.0, 500)); } // Try reading battery level if supported if (device.hasInput(InputType.Battery)) { console.log('\nReading battery level...'); const battery = await device.battery(); console.log(`Battery: ${(battery * 100).toFixed(0)}%`); } await waitForEnter('\nPress Enter to disconnect...'); // Disconnect - this automatically stops all devices await client.disconnect(); console.log('Disconnected.'); } main().catch(console.error); ``` **Python:** ```python """Device Control - Vibrate, rotate, and position commands. This example shows how to control different types of devices: - Vibrators: Set vibration intensity - Rotators: Set rotation speed - Strokers: Move to position over time The example checks what each device supports before sending commands, so it will work with any device type. Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Start Intiface Central and click "Start Server" 3. Have a supported device connected 4. Run this script: python device_control.py """ import asyncio from buttplug import ButtplugClient, DeviceOutputCommand, OutputType async def main() -> None: client = ButtplugClient("Device Control Example") # Set up event handlers to see devices as they connect client.on_device_added = lambda d: print(f"Device connected: {d.name}") client.on_device_removed = lambda d: print(f"Device disconnected: {d.name}") print("Connecting to server...") await client.connect("ws://127.0.0.1:12345") print("Scanning for devices (5 seconds)...") await client.start_scanning() await asyncio.sleep(5) await client.stop_scanning() if not client.devices: print("No devices found!") await client.disconnect() return # Control each device based on its capabilities for device in client.devices.values(): print(f"\nControlling: {device.name}") # Vibration if device.has_output(OutputType.VIBRATE): print(" Starting vibration at 25%...") await device.run_output(DeviceOutputCommand(OutputType.VIBRATE, 0.25)) await asyncio.sleep(1) print(" Increasing to 50%...") await device.run_output(DeviceOutputCommand(OutputType.VIBRATE, 0.5)) await asyncio.sleep(1) print(" Full power (100%)...") await device.run_output(DeviceOutputCommand(OutputType.VIBRATE, 1.0)) await asyncio.sleep(1) # Rotation if device.has_output(OutputType.ROTATE): print(" Rotating at 50%...") await device.run_output(DeviceOutputCommand(OutputType.ROTATE, 0.5)) await asyncio.sleep(2) # Position (strokers/linear devices) if device.has_output(OutputType.POSITION_WITH_DURATION): print(" Moving to top position...") await device.run_output( DeviceOutputCommand(OutputType.POSITION_WITH_DURATION, 1.0, duration=500) ) await asyncio.sleep(1) print(" Moving to bottom position...") await device.run_output( DeviceOutputCommand(OutputType.POSITION_WITH_DURATION, 0.0, duration=500) ) await asyncio.sleep(1) print(" Moving to middle...") await device.run_output( DeviceOutputCommand(OutputType.POSITION_WITH_DURATION, 0.5, duration=250) ) await asyncio.sleep(1) # Stop the device print(" Stopping device...") await device.stop() print("\nAll done!") await client.disconnect() if __name__ == "__main__": asyncio.run(main()) ``` --- ## Device Enumeration Once the client and server are connected, they can start communicating about devices. ## Scanning To find out about new devices during a session, Buttplug Client libraries will usually provide 2 functions and an event/callback: - StartScanning (Method) - Tells the server to start looking for devices via the Device Manager. This will start the Bluetooth Manager doing a bluetooth scan, the USB manager looking for USB or HID devices, etc... for all loaded Device Communication Managers - **Note:** Scanning may still require user input on the server side! For instance, using WebBluetooth in browsers with buttplug-wasm will require the user to interact with browser dialogs, so calling StartScanning() may open that dialog. - StopScanning (Method) - Tells the server to stop scanning for devices if it hasn't already. ### ScanningFinished Event (WASM only) ScanningFinished is now only used for the Typescript WASM Server setup. For Desktop/Mobile apps connecting to Intiface Central, you do not need to watch for the ScanningFinished event, as most Device Scanners run until StopScanning is called. - ScanningFinished (Event/Callback) - When all device communication managers have finished looking for new devices, this event will be fired from the client to let applications know to update their UI (for instance, to change a button name from "Stop Scanning" to "Start Scanning"). This event may fire without StopScanning ever being called, as there are cases where scanning is not indefinite (once again, WebBluetooth is a good example, as well as things like gamepad scanners). ## Device Connection Events and Storage There are 2 events related to device connections that the client may fire: - DeviceAdded (Event/Callback) - This event will contain a new device object. It denotes that the server is now connected to this device, and that the device can take commands. - DeviceRemoved (Event/Callback) - This event will fire when a device disconnects from the server for some reason. It should contain and instance of the device that disconnected. While the events are handy for updating UI, Client implementations usually also hold a list of currently connected devices that can be used for iteration if needed. Both events may be fired at any time during a Buttplug Client/Server session. DeviceAdded can be called outside of StartScanning()/StopScanning(), and even right after connect in some instances. ## Already Connected Devices Servers will normally stay up and running until users stop them, meaning they can have connections from several different clients over the session. This means that devices may already be connected to servers when you connect. Most clients will query the server for already connected devices when they finish their handshake, after which they will then present them as DeviceAdded() events. This means you will want to have your event handlers set up **BEFORE** connecting, in order to catch these messages. You can also check the Devices storage (usually a public collection on your Client instance, like an array or list) after connect to see what devices are there. ## Code Example Here's some examples of how device enumeration works in different implementations of Buttplug. **Rust:** ```rust use buttplug_client::{ ButtplugClient, ButtplugClientEvent, connector::ButtplugRemoteClientConnector, serializer::ButtplugClientJSONSerializer, }; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; use futures::StreamExt; use tokio::io::{self, AsyncBufReadExt, BufReader}; async fn wait_for_input() { BufReader::new(io::stdin()) .lines() .next_line() .await .unwrap(); } #[tokio::main] async fn main() -> anyhow::Result<()> { // Usual embedded connector setup. We'll assume the server found all // of the subtype managers for us (the default features include all of them). //let client = in_process_client("Example Client", false).await; // To create a Websocket Connector, you need the websocket address and some generics fuckery. let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); let client = ButtplugClient::new("Example Client"); client.connect(connector).await?; let mut events = client.event_stream(); // Set up our DeviceAdded/DeviceRemoved/ScanningFinished event handlers before connecting. tokio::spawn(async move { while let Some(event) = events.next().await { match event { ButtplugClientEvent::DeviceAdded(device) => { println!("Device {} Connected!", device.name()); } ButtplugClientEvent::DeviceRemoved(info) => { println!("Device {} Removed!", info.name()); } ButtplugClientEvent::ScanningFinished => { println!("Device scanning is finished!"); } _ => {} } } }); // We're connected, yay! println!("Connected!"); // Now we can start scanning for devices, and any time a device is // found, we should see the device name printed out. client.start_scanning().await?; wait_for_input().await; // Some Subtype Managers will scan until we still them to stop, so // let's stop them now. client.stop_scanning().await?; wait_for_input().await; // Since we've scanned, the client holds information about devices it // knows about for us. These devices can be accessed with the Devices // getter on the client. println!("Client currently knows about these devices:"); for (_, device) in client.devices() { println!("- {}", device.name()); } wait_for_input().await; // And now we disconnect as usual. client.disconnect().await?; Ok(()) } ``` **C#:** ```csharp // Buttplug C# - Device Enumeration Example // // This example demonstrates how to scan for devices and handle // device connection/disconnection events. using Buttplug.Client; var client = new ButtplugClient("Device Enumeration Example"); // Set up event handlers BEFORE connecting. // This ensures we don't miss any events. client.DeviceAdded += (sender, args) => { Console.WriteLine($"Device connected: {args.Device.Name}"); }; client.DeviceRemoved += (sender, args) => { Console.WriteLine($"Device disconnected: {args.Device.Name}"); }; client.ScanningFinished += (sender, args) => { Console.WriteLine("Scanning finished."); }; // Connect to the server await client.ConnectAsync("ws://127.0.0.1:12345"); // Start scanning for devices. // Devices will be announced via the DeviceAdded event. Console.WriteLine("Turn on your devices now!"); await client.StartScanningAsync(); Console.WriteLine("\nPress Enter to stop scanning..."); Console.ReadLine(); // Stop scanning. Some protocols scan continuously until told to stop. await client.StopScanningAsync(); // The client maintains a list of all known devices. // This list persists even after scanning stops. Console.WriteLine("\nCurrently connected devices:"); foreach (var device in client.Devices) { Console.WriteLine($" - {device.Name} (Index: {device.Index})"); } if (client.Devices.Length == 0) { Console.WriteLine(" (no devices connected)"); } Console.WriteLine("\nPress Enter to disconnect..."); Console.ReadLine(); await client.DisconnectAsync(); Console.WriteLine("Disconnected."); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Device Enumeration Example // // This example demonstrates how to scan for devices and handle // device connection/disconnection events. // // Include Buttplug via CDN: // async function runDeviceEnumerationExample() { const client = new buttplug.ButtplugClient("Device Enumeration Example"); // Set up event handlers BEFORE connecting. // This ensures we don't miss any events, including devices // that are already connected to the server. client.addListener("deviceadded", (device) => { console.log(`Device connected: ${device.name}`); // The client maintains a Map of all known devices. // In v4, client.devices is a Map console.log("Currently connected devices:"); for (const [index, dev] of client.devices) { console.log(` - ${dev.name} (Index: ${index})`); } }); client.addListener("deviceremoved", (device) => { console.log(`Device disconnected: ${device.name}`); }); client.addListener("scanningfinished", () => { console.log("Scanning finished."); }); // Connect to the server (requires Intiface Central running) const connector = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://localhost:12345"); console.log("Connecting..."); await client.connect(connector); console.log("Connected!"); // Start scanning for devices. // Devices will be announced via the 'deviceadded' event. console.log("Starting device scan... Turn on your devices now!"); await client.startScanning(); // Note: In a real application, you would call client.stopScanning() // when you're done scanning, and client.disconnect() when finished. } ``` **TypeScript:** ```typescript // Buttplug TypeScript - Device Enumeration Example // // This example demonstrates how to scan for devices and handle // device connection/disconnection events. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm device-enumeration-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientDevice, } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } async function main(): Promise { const client = new ButtplugClient('Device Enumeration Example'); // Set up event handlers BEFORE connecting. // This ensures we don't miss any events. client.addListener('deviceadded', (device: ButtplugClientDevice) => { console.log(`Device connected: ${device.name}`); }); client.addListener('deviceremoved', (device: ButtplugClientDevice) => { console.log(`Device disconnected: ${device.name}`); }); client.addListener('scanningfinished', () => { console.log('Scanning finished.'); }); // Connect to the server const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); console.log('Connecting...'); await client.connect(connector); console.log('Connected!'); // Start scanning for devices. // Devices will be announced via the 'deviceadded' event. console.log('\nStarting device scan...'); console.log('Turn on your devices now!'); await client.startScanning(); await waitForEnter('\nPress Enter to stop scanning...'); // Stop scanning. Some protocols scan continuously until told to stop. await client.stopScanning(); // The client maintains a map of all known devices. // This map persists even after scanning stops. console.log('\nCurrently connected devices:'); if (client.devices.size === 0) { console.log(' (no devices connected)'); } else { for (const [index, device] of client.devices) { console.log(` - ${device.name} (Index: ${index})`); } } await waitForEnter('\nPress Enter to disconnect...'); await client.disconnect(); console.log('Disconnected.'); } main().catch(console.error); ``` **Python:** ```python """Device Enumeration - Scan for and list devices. This example shows how to scan for devices and handle device connection/disconnection events. Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Start Intiface Central and click "Start Server" 3. Have a supported device nearby and powered on 4. Run this script: python device_enumeration.py """ import asyncio from buttplug import ButtplugClient, ButtplugDevice def on_device_added(device: ButtplugDevice) -> None: """Called when a device connects.""" print(f"Device connected: {device.name} (index {device.index})") def on_device_removed(device: ButtplugDevice) -> None: """Called when a device disconnects.""" print(f"Device disconnected: {device.name}") async def main() -> None: client = ButtplugClient("Device Enumeration Example") # Set up event handlers before connecting client.on_device_added = on_device_added client.on_device_removed = on_device_removed print("Connecting to server...") await client.connect("ws://127.0.0.1:12345") print(f"Connected to: {client.server_name}") # Start scanning for devices print("\nScanning for devices (5 seconds)...") await client.start_scanning() await asyncio.sleep(5) await client.stop_scanning() # List all discovered devices if client.devices: print(f"\nFound {len(client.devices)} device(s):") for device in client.devices.values(): print(f" - {device.name}") if device.display_name: print(f" Display name: {device.display_name}") else: print("\nNo devices found.") print("Make sure your device is on and in pairing mode.") await client.disconnect() print("\nDone!") if __name__ == "__main__": asyncio.run(main()) ``` --- ## What Do Devices Do? We now know that devices are connected to the client, but how do we figure out what we can do with them? In this section, we'll discover what inputs and ouputs a device has, and how we can use them. ## Example Device We'll be presenting a fairly standard, simple device here just to get things going. As of this writing, buttplug supports something like 750 devices with myriad outputs and inputs. We'll cover the full picture of everything the library supports and specific usecases in the [Device Outputs portion of the Winning Ways Section](/docs/dev-guide/cookbook/devices-and-commands/intro.md) later, once the basics are understood. The device we'll be discussing here has the following features: - 2 vibration motors, individually controllable, each with 50 steps of vibration speed. - A battery that we can query for how much power it has left This is vaguely similar to something like a [Lovense Edge](https://lovense.buttplug.io), but form factor isn't really an issue here. We just want an example of something we can control. As an app developer, this is really all you need to know about the device. Buttplug hides most information about how things are connected (bluetooth, usb, etc) so you don't have to worry about them. ## What even _is_ a Buttplug Device? Whenever we get a DeviceAdded() event, it'll usually come with some sort of structure representing the device. This will include: - The _Device Index_ - A unique 32-bit unsigned integer that identifies the device to the server. As long as the user does not clear their server configuration, these indexes can be considered to be stable and usable for saving configuration options across sessions of your application. - The _Device Name_, in 2 forms - The _canonical_ device name, as set in the Buttplug Device Config - The _user_/_display_ device name, which is a name users can set for a device so they can differentiate it from other devices. - A _message gap_ duration, in milliseconds - This refers to the amount of time that the Buttplug Server will put between two messages, so that we don't end up with queued messages. This will be discussed more in the [device control section](./device-control.mdx). - A set of _features_ - This denotes what a device actually does, we'll spend the rest of this section talking about these. ## Device Features Devices in Buttplug are made up of features. Features contain: - The _Feature Index_ - Similar to the _Device Index_. Unique (in the scope of the device) 32-bit unsigned integer that specifies which feature is which. A combination of _Device Index_ and _Feature Index_ are used to write command messages, outlined in the [next section](./device-control.mdx). - A _feature description_ - Describes what the feature does, in English. Useful for showing in UI. - A _feature type_ - This is the main function of the feature, though it may support multiple ways of doing things (i.e. a stroker that can work with positions or can just oscillate between two positions, a motor with an encoder so position can be both set and read, etc...). Feature types are only for getting a general idea of what a feature does, and are not used in commands. - _Outputs_ - Things that the device does. Vibration, rotation, stroking, etc..., are all _outputs_. - _Output_ information will contain the [_OutputType_](../../spec/output.md#outputtype)s a feature exposes, as well as the amount of _steps_ an output can handle. For instance, with the device example we laid out above, _steps_ would be 50 by default. However, servers like [Intiface Central](../architecture/intiface.md) allow users to set upper limits that may be lower than the maximum a device can handle, so _steps_ may be listed as lower than 50. - _Inputs_ - Things a device can sense and relay information to us about. Battery levels, RSSI for radio connections, button presses, pressure sensors, are all types of _inputs_. - Like _Outputs_, _Input_ information will contain the [_InputType_](../../spec/input.md#inputtype)s a feature exposes, and will also contain information about the possible values they can return. For instance, batteries will always return a number between 0-100, representing the percentage of power they have left. Other _input_ types, like various pressure sensors, may vary in their output range. > **Tip: Didn't these used to be called Actuators and Sensors?** They did! In prior versions of the library, we had MessageAttributes because each message denoted a sort of output type, which was horrible and complicated and very difficult to talk about, much less write useful documentation for. Parts of the v3 api moved us to using the _actuator_/_sensor_ terminology. This was kept through the early parts of v4 api development. Then I realized that the project is mostly referred to as buttplug dot io these days, thanks to the shitpost of a domain I got when I started all this. So why not name them Outputs and Inputs? Is it less clear? Possibly. Is it both more on brand and hilarious? **ABSOLUTELY.** Thus, Outputs and Inputs it is. Will it be any easier to write documentation for? I refer you to the previous point about hilarity, which will hopefully hide any issues with documentation complexity from here on out. Here's a few examples of what a device feature can look like: - A single vibrator with 20 steps of vibration - This will be a feature with a single Output, of type _Vibrate_, with _steps_ set to 20. Pretty easy. - A stroker - This will be a feature with two output types: One that allows us to send the device to a position over the duration of time (_HwPositionWithDuration_), and another type that allows us to set the speed of oscillation between two points (_Oscillate_) - A motor with an encoder - This will be a feature with 1 output type of _HwPositionWithDuration_, and 1 input type of _Position_ where we can read the current position of the motor at any time for setting up our own control loops. - *Note:* The _Position_ input type is just a handy example for the reason a feature might have both outputs and inputs. It does not actually exist in the library yet. Buttplug does not support any toys that actually tell us their current position, speed, or anything else. Not because we just haven't had time to support them, but because no toys exposing that information exist that we know of. I hate working with sex toys so fucking much. Why am I writing this library. For our example above, we should expect: - A single device, with 3 Features - A feature for the first vibrator, exposing one Output of type _Vibrate_ with 50 _steps_ - A feature for the second vibrator, exposing one Output of type _Vibrate_ with 50 _steps_ - A feature for the battery, exposing one Input of type _Battery_. The battery type is implicitly assumed to have a range of 0 \<= x \<= 100, so no range information is sent. ## Querying Device Feature Information We'll start from where we left off in the last section. You've established a connection to a Buttplug Server, you've set up your event handlers, and you've just gotten a `DeviceAdded()` event. We know there's a new device, but how can we tell what it does? This code block shows how we can query the device and see what's available. **Rust:** ```rust use buttplug_client::{ ButtplugClient, connector::ButtplugRemoteClientConnector, serializer::ButtplugClientJSONSerializer, }; use buttplug_core::message::{InputType, OutputType}; use buttplug_transport_websocket_tungstenite::ButtplugWebsocketClientTransport; use strum::IntoEnumIterator; use tokio::io::{self, AsyncBufReadExt, BufReader}; async fn wait_for_input() { BufReader::new(io::stdin()) .lines() .next_line() .await .unwrap(); } #[tokio::main] async fn main() -> anyhow::Result<()> { let connector = ButtplugRemoteClientConnector::< ButtplugWebsocketClientTransport, ButtplugClientJSONSerializer, >::new(ButtplugWebsocketClientTransport::new_insecure_connector( "ws://127.0.0.1:12345", )); let client = ButtplugClient::new("Device Info Example"); client.connect(connector).await?; // Scan for devices client.start_scanning().await?; println!("Scanning for devices. Press Enter when ready..."); wait_for_input().await; client.stop_scanning().await?; // Iterate through all connected devices for (_, device) in client.devices() { println!("\n=== Device: {} ===", device.name()); println!("Index: {}", device.index()); println!("Display Name: {:?}", device.display_name()); // Get all features for this device let features = device.device_features(); println!("\nFeatures ({} total):", features.len()); for (feature_index, feature) in features { let feature_def = feature.feature(); println!("\n Feature {}:", feature_index); println!(" Description: {:?}", feature_def.description()); println!(" Type: {:?}", feature_def.feature_type()); // Check for outputs (things the device can do) if let Some(output) = feature_def.output() { println!(" Outputs:"); for output_type in OutputType::iter() { if output.contains(output_type) { println!(" - {:?} (steps: {:?})", output_type, output.steps()); } } } // Check for inputs (things the device can sense) if let Some(input) = feature_def.input() { println!(" Inputs:"); for input_type in InputType::iter() { if input.contains(input_type) { println!(" - {:?}", input_type); } } } } // Convenience methods for checking specific capabilities println!("\nCapability summary:"); let vibrate_features = device.vibrate_features(); if !vibrate_features.is_empty() { println!(" - {} vibrator(s)", vibrate_features.len()); } let rotate_features = device.rotate_features(); if !rotate_features.is_empty() { println!(" - {} rotator(s)", rotate_features.len()); } let linear_features = device.linear_features(); if !linear_features.is_empty() { println!(" - {} linear actuator(s)", linear_features.len()); } } println!("\nPress Enter to disconnect..."); wait_for_input().await; client.disconnect().await?; Ok(()) } ``` **C#:** ```csharp // Buttplug C# - Device Info Example // // This example demonstrates how to query device capabilities, // including features, outputs, and inputs. using Buttplug.Client; using Buttplug.Core.Messages; var client = new ButtplugClient("Device Info Example"); // Connect and scan for devices Console.WriteLine("Connecting..."); await client.ConnectAsync("ws://127.0.0.1:12345"); Console.WriteLine("Connected! Scanning for devices..."); await client.StartScanningAsync(); Console.WriteLine("Turn on a device, then press Enter..."); Console.ReadLine(); await client.StopScanningAsync(); // Iterate through all connected devices foreach (var device in client.Devices) { Console.WriteLine($"\n=== Device: {device.Name} ==="); Console.WriteLine($"Index: {device.Index}"); Console.WriteLine($"Display Name: {device.DisplayName}"); // Iterate through all features on this device Console.WriteLine($"\nFeatures ({device.Features.Count} total):"); foreach (var feature in device.Features.Values) { Console.WriteLine($"\n Feature {feature.FeatureIndex}:"); Console.WriteLine($" Description: {feature.FeatureDescriptor}"); // Check for outputs (things the device can do) var outputs = feature.FeatureDefinition.Output; if (outputs != null && outputs.Count > 0) { Console.WriteLine(" Outputs:"); foreach (var outputType in outputs) { var steps = feature.FeatureDefinition.OutputSteps; Console.WriteLine($" - {outputType} (steps: {steps})"); } } // Check for inputs (things the device can sense) var inputs = feature.FeatureDefinition.Input; if (inputs != null && inputs.Count > 0) { Console.WriteLine(" Inputs:"); foreach (var inputType in inputs) { Console.WriteLine($" - {inputType}"); } } } // Use convenience methods to check specific capabilities Console.WriteLine("\nCapability summary:"); if (device.HasOutput(OutputType.Vibrate)) { var vibrateFeatures = device.GetFeaturesWithOutput(OutputType.Vibrate).ToList(); Console.WriteLine($" - {vibrateFeatures.Count} vibrator(s)"); } if (device.HasOutput(OutputType.Rotate)) { var rotateFeatures = device.GetFeaturesWithOutput(OutputType.Rotate).ToList(); Console.WriteLine($" - {rotateFeatures.Count} rotator(s)"); } if (device.HasOutput(OutputType.Position)) { var positionFeatures = device.GetFeaturesWithOutput(OutputType.Position).ToList(); Console.WriteLine($" - {positionFeatures.Count} linear actuator(s)"); } if (device.HasInput(InputType.Battery)) { Console.WriteLine(" - Battery level sensor"); } if (device.HasInput(InputType.RSSI)) { Console.WriteLine(" - Signal strength (RSSI) sensor"); } } Console.WriteLine("\nPress Enter to disconnect..."); Console.ReadLine(); await client.DisconnectAsync(); Console.WriteLine("Disconnected."); ``` **Javascript (Web):** {/* NOTE: These are browser examples. Include Buttplug via CDN in your HTML: */} ```js // Buttplug Web - Device Info Example // // This example demonstrates how to introspect device features // and capabilities in detail using the v4 API. // // Include Buttplug via CDN: // function printDeviceInfo(device) { console.log("=================================================="); console.log(`Device: ${device.name}`); if (device.displayName) { console.log(`Display Name: ${device.displayName}`); } console.log(`Index: ${device.index}`); if (device.messageTimingGap !== undefined) { console.log(`Message Timing Gap: ${device.messageTimingGap}ms`); } console.log("=================================================="); // Collect output capabilities const outputTypes = []; if (device.hasOutput(buttplug.OutputType.Vibrate)) outputTypes.push("Vibrate"); if (device.hasOutput(buttplug.OutputType.Rotate)) outputTypes.push("Rotate"); if (device.hasOutput(buttplug.OutputType.Oscillate)) outputTypes.push("Oscillate"); if (device.hasOutput(buttplug.OutputType.Position)) outputTypes.push("Position"); if (device.hasOutput(buttplug.OutputType.Constrict)) outputTypes.push("Constrict"); if (device.hasOutput(buttplug.OutputType.Inflate)) outputTypes.push("Inflate"); if (device.hasOutput(buttplug.OutputType.Temperature)) outputTypes.push("Temperature"); if (device.hasOutput(buttplug.OutputType.Led)) outputTypes.push("LED"); if (outputTypes.length > 0) { console.log(`\nOutput Capabilities: ${outputTypes.join(", ")}`); } // Collect input capabilities const inputTypes = []; if (device.hasInput(buttplug.InputType.Battery)) inputTypes.push("Battery"); if (device.hasInput(buttplug.InputType.RSSI)) inputTypes.push("RSSI"); if (device.hasInput(buttplug.InputType.Button)) inputTypes.push("Button"); if (device.hasInput(buttplug.InputType.Pressure)) inputTypes.push("Pressure"); if (inputTypes.length > 0) { console.log(`Input Capabilities: ${inputTypes.join(", ")}`); } // Detailed feature breakdown console.log("\nDetailed Features:"); for (const [index, feature] of device.features) { console.log(`\n Feature ${index}: ${feature.descriptor}`); if (feature.outputs.size > 0) { console.log(" Outputs:"); for (const output of feature.outputs.values()) { console.log(` - ${output.type}: range ${output.valueRange[0]}-${output.valueRange[1]}`); } } if (feature.inputs.size > 0) { console.log(" Inputs:"); for (const input of feature.inputs.values()) { console.log(` - ${input.type}: commands [${input.commands.join(", ")}]`); } } } } async function runDeviceInfoExample() { const client = new buttplug.ButtplugClient("Device Info Example"); // Connect to the server const connector = new buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345"); console.log("Connecting..."); await client.connect(connector); console.log("Connected! Scanning for devices..."); console.log("Turn on your devices now. Info will be printed as they connect.\n"); // Set up device event to print info when devices connect client.addListener("deviceadded", (device) => { printDeviceInfo(device); }); await client.startScanning(); // After a few seconds, also show summary of all connected devices setTimeout(() => { console.log("\n\n========== SUMMARY =========="); if (client.devices.size === 0) { console.log("No devices connected."); } else { console.log(`Found ${client.devices.size} device(s):`); for (const [index, device] of client.devices) { console.log(` ${index}: ${device.name}`); } } }, 5000); } ``` **TypeScript:** ```typescript // Buttplug TypeScript - Device Info Example // // This example demonstrates how to introspect device features // and capabilities in detail. // // Prerequisites: // 1. Install Intiface Central: https://intiface.com/central // 2. Start the server in Intiface Central // 3. Run: npx ts-node --esm device-info-example.ts import { ButtplugClient, ButtplugNodeWebsocketClientConnector, ButtplugClientDevice, OutputType, InputType, } from 'buttplug'; import * as readline from 'readline'; async function waitForEnter(prompt: string): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(prompt, () => { rl.close(); resolve(); }); }); } function printDeviceInfo(device: ButtplugClientDevice): void { console.log(`\n${'='.repeat(50)}`); console.log(`Device: ${device.name}`); if (device.displayName) { console.log(`Display Name: ${device.displayName}`); } console.log(`Index: ${device.index}`); if (device.messageTimingGap !== undefined) { console.log(`Message Timing Gap: ${device.messageTimingGap}ms`); } console.log(`${'='.repeat(50)}`); // Collect output capabilities const outputTypes: string[] = []; if (device.hasOutput(OutputType.Vibrate)) outputTypes.push('Vibrate'); if (device.hasOutput(OutputType.Rotate)) outputTypes.push('Rotate'); if (device.hasOutput(OutputType.Oscillate)) outputTypes.push('Oscillate'); if (device.hasOutput(OutputType.Position)) outputTypes.push('Position'); if (device.hasOutput(OutputType.Constrict)) outputTypes.push('Constrict'); if (device.hasOutput(OutputType.Inflate)) outputTypes.push('Inflate'); if (device.hasOutput(OutputType.Temperature)) outputTypes.push('Temperature'); if (device.hasOutput(OutputType.Led)) outputTypes.push('LED'); if (outputTypes.length > 0) { console.log(`\nOutput Capabilities: ${outputTypes.join(', ')}`); } // Collect input capabilities const inputTypes: string[] = []; if (device.hasInput(InputType.Battery)) inputTypes.push('Battery'); if (device.hasInput(InputType.RSSI)) inputTypes.push('RSSI'); if (device.hasInput(InputType.Button)) inputTypes.push('Button'); if (device.hasInput(InputType.Pressure)) inputTypes.push('Pressure'); if (inputTypes.length > 0) { console.log(`Input Capabilities: ${inputTypes.join(', ')}`); } // Detailed feature breakdown console.log('\nDetailed Features:'); for (const [index, feature] of device.features) { console.log(`\n Feature ${index}: ${feature.descriptor}`); if (feature.outputs.size > 0) { console.log(' Outputs:'); for (const output of feature.outputs.values()) { console.log( ` - ${output.type}: range ${output.valueRange[0]}-${output.valueRange[1]}` ); } } if (feature.inputs.size > 0) { console.log(' Inputs:'); for (const input of feature.inputs.values()) { console.log( ` - ${input.type}: commands [${input.commands.join(', ')}]` ); } } } } async function main(): Promise { const client = new ButtplugClient('Device Info Example'); // Connect const connector = new ButtplugNodeWebsocketClientConnector( 'ws://127.0.0.1:12345' ); console.log('Connecting...'); await client.connect(connector); console.log('Connected! Scanning for devices...'); await client.startScanning(); await waitForEnter('Turn on your devices, then press Enter...'); await client.stopScanning(); // Display info for all connected devices if (client.devices.size === 0) { console.log('No devices found.'); } else { console.log(`\nFound ${client.devices.size} device(s):`); for (const [_, device] of client.devices) { printDeviceInfo(device); } } await waitForEnter('\nPress Enter to disconnect...'); await client.disconnect(); console.log('Disconnected.'); } main().catch(console.error); ``` **Python:** ```python """Device Info - Inspect device capabilities. This example shows how to inspect device features and capabilities: - List all available features - Check output types (vibrate, rotate, position) - Check input types (battery, sensors) - Access individual motors on multi-motor devices Prerequisites: 1. Install Intiface Central: https://intiface.com/central/ 2. Start Intiface Central and click "Start Server" 3. Have a supported device connected 4. Run this script: python device_info.py """ import asyncio from buttplug import ButtplugClient, OutputType async def main() -> None: client = ButtplugClient("Device Info Example") print("Connecting to server...") await client.connect("ws://127.0.0.1:12345") print("Scanning for devices (5 seconds)...") await client.start_scanning() await asyncio.sleep(5) await client.stop_scanning() if not client.devices: print("No devices found!") await client.disconnect() return # Inspect each device's features in detail for device in client.devices.values(): print(f"\n{'=' * 50}") print(f"Device: {device.name}") print(f"Index: {device.index}") print(f"Display Name: {device.display_name or '(none)'}") print(f"Timing Gap: {device.message_timing_gap}ms") print(f"{'=' * 50}") # List all features print(f"\nFeatures ({len(device.features)}):") for feature in device.features.values(): print(f"\n Feature {feature.index}: {feature.description or '(no description)'}") # Show outputs if feature.outputs: print(" Outputs:") for output_type in feature.outputs: value_range = feature.get_output_range(output_type) duration_range = feature.get_output_duration_range(output_type) print(f" - {output_type}: values {value_range}", end="") if duration_range: print(f", duration {duration_range}ms", end="") print() # Show inputs if feature.inputs: print(" Inputs:") for input_type, input_def in feature.inputs.items(): print(f" - {input_type}: commands {input_def.command}") # Show multi-motor info vibrate_features = device.get_features_with_output(OutputType.VIBRATE) if len(vibrate_features) > 1: print(f"\nThis device has {len(vibrate_features)} independent vibrators!") print("Use device.send_output() to control them individually.") await client.disconnect() print("\nDone!") if __name__ == "__main__": asyncio.run(main()) ``` --- ## Writing Buttplug Applications Enough talk, let's get to Buttplugging! We'll now cover the minimal amount of information needed to get you up and running with the Buttplug Library. Links to extra info will be included throughout, but the most important thing for the moment is to get a first example going. After that, we'll spend the Winning Ways section getting in depth with the full capabilities of the library. ## This Ain't Everything This section will cover the absolute minimum functionality you need to get up and running with Buttplug. However, the library is far more extensive than this section covers. It is recommended you go through this section first, get a simple program up and running with your hardware, then check out the [Winning Ways section](/docs/dev-guide/cookbook/intro) for advice on how to structure your application and use some of the other features in the library. ## Example Code Access All of the example code in this section, as well as in the rest of the Developer Guide, is available in the [github repo for the Dev Guide](https://github.com/buttplugio/docs.buttplug.io/tree/master/examples). This includes both the code itself and sometimes project files (VS Studio projects, Cargo.toml for rust, etc) for building the applications. We will do our best to keep these as up to date as possible, but if you run into any issues with compatibility or compilation, please [file an issue on the dev guide repo](https://github.com/buttplugio/docs.buttplug.io/issues). --- ## A Cookbook for Your Butt Now that you know the basics of Buttplug, it's time to move on to more advanced topics. This section is not presented in any specific order, but rather presents a diverse set of subject matter having to do with how Buttplug functions as a library, some of the more esoteric features it presents, and how best to use it in your application. While nothing in this chapter is required to use the library, much of the information will prove handy as you try to create experiences for your users. --- ## Logging Buttplug exposes a few methods to receive log messages from the internal Rust library. These messages relay the internal state of the system, and can be handy for debugging purposes. ## Message Exposure What log messages you'll get depend on the type of system you're building. If you are using an embedded connector (i.e. server and client in the same process), you'll get both client and server information. If you're using a remote connector (i.e. your application uses the client, and the server is in another process/on another machine), you'll only receive log messages for the client. This preserves privacy for users who may not want to reveal information about their local setup to a untrusted client (For more information, see the [Privacy Models section of the this guide](/docs/dev-guide/cookbook/privacy-models)). This model may may things challenging to debug, which is why we recommend doing initial development in an embedded context if possible, the moving to remote once core development is set. ## Accessing Logs Logs are generated in Rust using the [tracing crate](https://github.com/tokio-rs/tracing). This functionality is exposed to Rust via normal tracing subsystems (for instance, output to stdout via tracing_subscriber::fmt), or via various language specifics for FFIs (C# and JS have the ability to emit log messages as events). > **Tip: Temporary FFI Logging Limitations** At the time of this writing, logging capabilties in FFI instances are somewhat limited. Logging must be started manually, can only be set to one level for a session (i.e. if logging is started a "Debug or higher" levels, it will stay there for the remainder of the process), and only comes as string. As library development progresses, this system will be tuned to allow finer grained access to control and log information. Available log levels are as follows: - **Error** - Something went wrong and you should probably pay attention. - **Warn** - Something bad possibly happened, but may not warrant full attention. - **Info** - Something possibly useful to the user happened - **Debug** - Something insignificant but possibly useful to development happened - **Trace** - A butterfly flapped its wings. Trace is _EXTREMELY_ spammy. ## Example Code **Rust:** Handling and/or outputting log messages in Rust is left up to the user, via normal methods of output for the [tracing crate.](https://github.com/tokio-rs/tracing) To output messages to stdout (i.e. the console) we recommend using the [tracing_subscriber](https://docs.rs/tracing-subscriber/) create with its fmt instance, like so: ```rust use buttplug_client_in_process::in_process_client; #[tokio::main] async fn main() -> anyhow::Result<()> { // Run this to turn on the environment logger. Running this more than once will panic. tracing_subscriber::fmt::init(); // Now when you connect here, if you've set the RUST_LOG environment variable // (set it to "Info" or "Debug"), you should see messages about connection // setup. let _client = in_process_client("Example Client").await; Ok(()) } ``` tracing_subscriber::fmt uses environment variables to set log level filters. The filters are strings set to the levels mentioned in the previous section. To set up log output using tracing_subscriber on a shell, you can use ```shell RUST_LOG="debug" ./[your_program_here] ``` To set this up in Powershell on windows, you can use ```powershell $env:RUST_LOG="debug" ``` Running the example above, you should see something like this (may not be exact. For instance, most people probably won't be writing sex toy software documentation on Christmas.): ``` Dec 25 20:49:11.826 INFO buttplug::server::comm_managers::btleplug: Setting bluetooth device event handler. Dec 25 20:49:11.826 INFO InProcessClientConnectorEventSenderLoop: buttplug::connector::in_process_connector: Starting In Process Client Connector Event Sender Loop Dec 25 20:49:11.839 INFO buttplug::server::comm_managers::serialport::serialport_comm_manager: Serial port created! Dec 25 20:49:11.840 INFO buttplug::server::comm_managers::lovense_dongle::lovense_hid_dongle_comm_manager: Lovense dongle HID Manager created! Dec 25 20:49:11.841 INFO buttplug::server::comm_managers::lovense_dongle::lovense_serial_dongle_comm_manager: Lovense dongle serial port created! Dec 25 20:49:11.841 INFO Lovense HID Dongle State Machine: buttplug::server::comm_managers::lovense_dongle::lovense_dongle_state_machine: Running wait for dongle step Dec 25 20:49:11.842 INFO Lovense Dongle State Machine: buttplug::server::comm_managers::lovense_dongle::lovense_dongle_state_machine: Running wait for dongle step Dec 25 20:49:11.842 INFO Client: buttplug::client: Connecting to server. Dec 25 20:49:11.845 INFO Client: buttplug::client: Connection to server succeeded. Dec 25 20:49:11.846 INFO buttplug::server::comm_managers::lovense_dongle::lovense_serial_dongle_comm_manager: Got 0 serial ports back Dec 25 20:49:11.847 INFO Client: buttplug::client: Running handshake with server. Dec 25 20:49:11.847 INFO Client:Client Loop Span: buttplug::client::internal: Starting client event loop. Dec 25 20:49:11.850 INFO Client:Client Loop Span:Client Event Loop: buttplug::server: Performing server handshake check Dec 25 20:49:11.852 INFO Client:Client Loop Span:Client Event Loop: buttplug::server: Server handshake check successful. Dec 25 20:49:11.854 INFO Client: buttplug::client: Connected to Buttplug Server ``` --- ## Privacy Models The architecture of Buttplug strives to provide privacy for whomever may be running the server side of the software in remote connection situations. In this section, we'll cover some of the architectural features that allow for this. ## Privacy in Local (Embedded) Versus Remote Contexts If someone has implemented an application in Buttplug using an embedded connector, it becomes quite difficult to maintain privacy because the application then has access to the full library, including the hardware access mechanisms. At this point, we can't really guarantee that the developer can/can't access anything, as they may as well have written the hardware access code themselves. However, in remote application systems (for instance, a web app accessing a local Intiface Desktop install), we can provide some obfuscation and information hiding that allows the user to regulate the amount of information they provide to the remote application. Whether the user opts to do this is up to them. ## Connectors May Leak Metadata While the Buttplug API does its best to hide info, it is just a hardware access API. Connectors (websockets, IPC, etc) between clients and servers may leak info through their various mediums, depending on how they are designed. If someone needs to be completely privacy conscious, it is possible to design connectors that route through anonymizing services. See the Inflating Buttplug section for more information on connector design. ## Hiding Device Identifiers From the perspective of the Buttplug Client, identifiers that would uniquely identify the device (such as Bluetooth addresses, USB serial numbers, etc...) are not available to the Client through our core API. The client only receives as device _index_, which is a 32-bit number that is either generated per-Buttplug-session, or may be set staticly if the user decides to do so. This is not to say that information is not accessible by applications at all. It is only scoped to what the core API allows. --- ## Adding a New Buttplug Message --- ## Adding to Buttplug This section covers development on extension to the Buttplug ecosystem, including: - Adding new devices, protocols, and device communication managers to servers - Implementing Buttplug clients and servers in new languages - Proposing and adding new messages to the Buttplug Protocol Throughout this section, if a specific language or technology is required, it will be called out. For instance, when implementing new device communication managers or protocols, this will usually be in the Rust implementation of the library. However, for implementing new clients and servers, this will usually be in whatever language the developer is interested in, so general, technology-agnostic advice will be given. --- ## The History of Buttplug * 2007: _An Idea in a Presentation_ * In my presentation at the first Arse Elektronika conference in 2007 ([available to watch on youtube](https://www.youtube.com/watch?v=FRLygav4tcs)), I presented the idea of "obfuscated macros" for controlling toys, a user experience strategy to define how users define haptic control for pleasure without a remote user having to figure out what inputs worked and what didn't. This ended up being the basis of some software experiments over the years until 2013, when the first solidified attempt at implementation happened. * 2013: _Python 2 + greenlet_ * The first, unreleased implementation of buttplug. [It's even in our repos if you want to check it out](https://github.com/buttplugio/buttplug-py-deprecated). This used python 2, greenlet, and ZMQ, but never got as far as talking to a device. It was mostly me playing around with architecture. The project was abandoned because I couldn't figure out how I was going to distribute it easily. * 2016: _Rust, the first time_ * Yes, Buttplug was implemented in Rust at first. Sort of. Due to the lack of hardware libraries, windows support (WinAPI 0.3 wasn't out yet), etc, this version only lived for about a month before being abandoned. * 2017: _C#_ * The second, and most mature implementation of Buttplug. C# was chosen because of Windows compatibility (though all libraries are now .Net Standard and compile cross-platform), which is where most of our users are. This implementation is where the current version of the spec came from. It uses C#'s async/Task features, and the design of this version of the library heavily influenced the later Rust implementation. * 2017: _Javascript_ * In an effort to build a pure web version of Buttplug, a Javascript (well, actually Typescript, but you get it) implementation was created. This ended up being both a pure web library (accessing devices through WebBluetooth), as well as a node library (accessing devices via noble). Due to the inherently async nature of Javascript engines, this was an async implementation, using promises and es7 async/await. This version has constantly lagged behind C# mostly because maintaining multiple libraries sucks. * 2019: _Intiface Desktop_ * While libraries were available for developers to use, there was no good central application for applications to connect to. This meant any time Buttplug updated, so did most of the applications that were using it. To fix this, the Intiface Desktop application was created. It was an Electron based app that ran a Vue frontend, and executed the server as a background process. This was distributed to users so that developers could use Buttplug clients without having to worry about needing to update whenever a new Buttplug version came out, because the server that Intiface Desktop supported would integrate all of the newest hardware in a backward compatible way. * 2019: _Rust, again_ * The split between C# and Javascript also helped us support as many platforms as possible. Going into development on the current Rust implementation in 2019, our platform supports looked like this: * Windows - C# (Node compiles, but is slow and difficult) * Mac - JS/Node (C# compiles, no Bluetooth/USB) * Linux - JS/Node (C# compiles, no Bluetooth/USB) * Android - Xamarin (C#, Bluetooth via Xamarin Bluetooth, didn't really work) * iOS - Xamarin (C#, Bluetooth via Xamarin Bluetooth, didn't really work) * Web - Pure JS (Blink Engines only for WebBluetooth, so users required Chrome or Edge to use in browser) * Needless to say, the fragmentation between the libraries was a problem. None of our users were sure when or how their devices would work. This, combined with the new fragmentation of C# 8.0/.Net Core 3, and the Xamarin lockin on mobile, meant we either needed to put all of our eggs in the .Net basket, or else look at another solution that could get us native everywhere. * Evaluating Rust in late 2019 was a far different situation than it was in 2016. FFI was more mature, WinAPI 0.3 was out and WinRT-rs provided UWP support, multiple Bluetooth libraries had already been written (though none were fully cross platform, [we fixed that](https://github.com/deviceplug/btleplug)), async/await was on the way, many projects were compiling Rust native to mobile platforms and using Java or Swift via FFI on top of it, and compiling to WASM is an option (albeit still a difficult one). Choosing Rust in 2019-2020 got us close to parity with where we were in C#/JS, all in the same language, and we'll be able to progress with the community and technology as it grows. * 2020: _Everything moves on top of the FFI_ * Once the core Rust system was in place, it seemed like it'd be best to move everything to live on top of Rust. This was mostly an effort to reduce core buttplug developer load. Instead of having to worry about implementing messages, websockets, json de/serializers, etc in every language, it could just be done in Rust then everything else could use that. C# was moved on top of FFI, and JS used a WASM implementation. * 2021: _A Breakthru on Mobile_ * In 2021, an anonymous github user named [gedgygedgy](https://github.com/gedgygedgy) created an async android runtime and JNI bindings to the bluetooth portions of the android API. This allowed [btleplug](https://github.com/deviceplug/btleplug) (the bluetooth library Buttplug uses) to be used on Android. Gedgygedgy disappeared in August 2021, but left the repos around. Additional work was done by qDot in April 2022 to bring the libraries up to date and integrate them into btleplug, at which point working versions of the Buttplug Library were built for both Android and iOS. * 2022: _Intiface Central_ * Due to not staying up to date with the latest web/node frameworks, Intiface Desktop had become arduous to maintain, seeing no updates for over a year. Instead of trying to rebuild on Electron, the system was scrapped for a Flutter based application that could be used across Desktop and Mobile. This became Intiface Central, which was released in November 2022. * 2022: _Everything moves off the top of the FFI_ * It turns out that move everything to FFI was overkill. The pure C# and Typescript clients we originally had were fine, it was the maintenance of the server side that was an issue. The server was now solved by the single rust implementation. Trying to force languages with their own runtimes on top of Rust was a bad idea, and ended up causing far more problems than solutions. In late 2022, the FFI layer was removed, and replaced with a binding to [Intiface Engine](https://github.com/intiface/intiface-engine). This binding was originally built for the mobile apps using buttplug, but came in handy for desktop too. --- ## STPIHKAL Protocol Documentation Template Standardization ## Summary Standardize STPIHKAL protocol documentation into a brand-directory structure with structured YAML BLE profile blocks, auto-injected device config data from buttplug's device-config-v4 via a build-time remark plugin, and consistent human-readable markdown sections for commands and protocol details. Covers template design, data pipeline, sidebar restructuring, and migration path for existing docs. ## Definition of Done **Primary deliverable:** A standardized documentation template for STPIHKAL protocol entries that uses (1) structured YAML frontmatter/blocks containing machine-parseable BLE GATT data cross-referenced with the buttplug device-config-v4 YAML, and (2) human-readable markdown sections for protocol details, commands, and notes. Template organized by brand (directory per brand with index + sub-pages per protocol). **Success criteria:** The template is concrete enough that someone (human or LLM) can take any GitHub issue from buttplugio/stpihkal or buttplugio/docs.buttplug.io (protocol-tagged) and produce a correctly-formatted doc page. Existing stpihkal docs have a clear migration path to the new format. **Out of scope:** Actually importing the ~124 issues (separate project). Full standardization of non-BLE protocol types (light touch only). Changes to the buttplug device-config-v4 YAML format itself. ## Glossary - **STPIHKAL**: "Sex Toy Protocols I Have Known And Loved" — the reverse-engineering documentation section of buttplug.io - **device-config-v4**: YAML configuration files in the buttplug repo (`buttplug/crates/buttplug_server_device_config/device-config-v4/protocols/`) defining BLE names, service UUIDs, characteristic endpoints, and device features for ~137 protocols - **GATT profile**: Generic Attribute Profile — the BLE service/characteristic hierarchy used by devices - **tx/rx**: Transmit/receive characteristic roles — tx is written to (commands), rx is read/notified from (responses) - **config_ref**: Frontmatter field linking a doc page to its corresponding device-config-v4 YAML file - **remark plugin**: A Docusaurus markdown processor plugin that transforms content at build time ## Architecture ### Directory Structure ``` stpihkal/ protocols/ / index.md # Brand page: intro, shared BLE patterns, device table .md # Protocol details: GATT profile, commands, notes ... firmware/ # Existing, light-touch update network/ # Existing, light-touch update video-encoding-formats/ # Existing, light-touch update index.md # Existing landing page ``` Every brand gets its own directory, even single-protocol brands, for consistency. The directory name is the brand in lowercase kebab-case (e.g., `we-vibe/`, `hot-octopuss/`). ### Data Pipeline 1. **Sync script** (`scripts/sync-device-config.sh`) copies `../buttplug/crates/buttplug_server_device_config/device-config-v4/protocols/` into `data/device-config/` in this repo. Added to the existing `sync-examples.sh` or as a separate script called alongside it. 2. **Remark plugin** (`plugins/remark-device-config.js`) runs at build time: - Reads the `config_ref` and `config_identifier` fields from page frontmatter - Loads the corresponding YAML from `data/device-config/` - Injects a "Device Configuration" section with: BLE names, advertised services, service/characteristic map, device features (vibrate/rotate/oscillate with value ranges), and per-device configuration table - Renders as both a human-readable table and a machine-parseable YAML code block 3. **Frontmatter** connects each page to its config: ```yaml config_ref: svakom.yml # file in data/device-config/ config_identifier: null # null = show defaults + all configs # or specific identifier like "ERIKA" ``` ### Protocol Page Template ```markdown --- title: brand: transport: btle # btle | serial | network | usb config_ref: .yml # device-config-v4 reference config_identifier: null # specific device identifier, or null for all --- # ## Introduction Brief description: what the device is, who makes it, any notable history. ## BLE Profile ```yaml ble_names: [""] services: - uuid: "" characteristics: - uuid: "" properties: [write] # read, write, write-without-response, notify role: tx # tx, rx, rxblebattery, etc. description: "Command endpoint" - uuid: "" properties: [notify] role: rx description: "Response/notification endpoint" ``` ## Device Configuration ## Pairing (If applicable) Description of any special pairing or initialization procedure. ## Commands ### **Format:** ``` 0xAA 0xBB 0xCC ``` | Byte | Description | Range | |------|-------------|-------| | 0xAA | Command ID | Fixed | | 0xBB | Parameter | 0x00-0x64 | | 0xCC | Checksum | Sum of prior bytes mod 256 | **Response:** ``` 0xOK ``` ### ... ## Notes Any quirks, undocumented behavior, firmware version differences, or caveats. ## Sources - [GitHub Issue](link to the issue this was imported from) - [Buttplug implementation](link to protocol implementation in buttplug-rs) - Any other reverse-engineering sources ``` ### Brand Index Page Template ```markdown --- title: brand: --- # ## Overview Brief brand introduction: manufacturer info, general product line. ## Common BLE Patterns (If applicable) Shared patterns across the brand's protocols: - BLE name prefixes/patterns - Common service UUID patterns - Shared protocol conventions (e.g., all Lovense toys use semicolon-delimited string commands) ## Devices | Device | BLE Name | Protocol Page | Features | |--------|----------|---------------|----------| | | | [Link](page) | Vibrate, Rotate, etc. | ``` ### Sidebar Configuration Update `sidebarsStpihkal.js` to support the new brand-directory structure. The `autogenerated` directive already handles nested directories, so the primary change is that the "Protocols and Memory Layouts" category will now show brand folders instead of flat files. ```javascript { type: "category", label: "Protocols", items: [ { type: "autogenerated", dirName: "protocols", }, ], } ``` Docusaurus autogenerated sidebars will create categories for each brand directory automatically, using the `index.md` as the category landing page. ## Existing Patterns ### Current doc format (varies wildly) - **Lovense** (`lovense.md`): Rich prose, inline UUIDs, command list with examples — most complete existing doc at ~630 lines - **We-Vibe** (`wevibe.md`): Terse, byte-level command format, device model table — good density - **Kiiroo Onyx 2** (`kiiroo-onyx-2.md`): Stub pointing to Fleshlight Launch docs - Others: Mix of quality levels ### device-config-v4 format Each YAML file has: - `defaults`: name, features (output types like vibrate/rotate/oscillate with value ranges), ID - `configurations`: per-device overrides keyed by identifier - `communication`: BLE definition with names, advertised_services, services (with tx/rx/etc. endpoints) ### GitHub issue format Inconsistent but typically contains: BLE name, service UUID, characteristic UUID(s), command bytes with parameter descriptions. Some have pairing procedures, encryption details, or API endpoints. ## Implementation Phases ### Phase 1: Data Pipeline Setup - Create `scripts/sync-device-config.sh` to copy device-config-v4 YAML into `data/device-config/` - Add `data/device-config/` to `.gitignore` (synced, not committed) - Create the remark plugin skeleton (`plugins/remark-device-config.js`) - Update `docusaurus.config.js` to register the plugin - Commit ### Phase 2: Template and Remark Plugin - Implement the remark plugin: parse frontmatter `config_ref`, load YAML, inject device config section - Create the protocol page template as a reference file (`stpihkal/protocols/_template.md`) - Create the brand index page template (`stpihkal/protocols/_brand-template.md`) - Write tests for the remark plugin (loads YAML, injects correctly, handles missing config gracefully) - Commit ### Phase 3: Migrate Existing Docs — Pilot - Migrate 2-3 existing docs to the new format as proof of concept: - Lovense (complex, multi-device brand with rich existing doc) - We-Vibe (medium complexity, good byte-level format) - One simple single-protocol brand (e.g., Cowgirl from stpihkal issue #100) - Restructure into brand directories - Validate build, sidebar rendering, and auto-injected device config - Commit ### Phase 4: Sidebar and Navigation Updates - Update `sidebarsStpihkal.js` if needed beyond autogenerated behavior - Update `stpihkal/index.md` to reflect new organization - Verify sidebar renders brand categories correctly - Commit ### Phase 5: Migrate Remaining Existing Docs - Migrate all remaining existing `stpihkal/protocols/*.md` files to brand directories - Apply new template format to each - Update cross-references between docs (e.g., Kiiroo Onyx 2 → Fleshlight Launch) - Commit per brand or per batch ### Phase 6: Documentation for Contributors - Write a contributor guide explaining how to add new protocol docs - Include instructions for: creating brand directory, using the template, referencing device-config-v4, writing commands section - This guide serves as the "spec" for the future ~124-issue import project - Commit ## Additional Considerations ### LLM Consumption The YAML code blocks in the BLE Profile section are specifically designed for LLM parsing. The structured format with consistent field names (`ble_names`, `services`, `uuid`, `properties`, `role`) creates a predictable schema that LLMs can extract data from reliably. The device-config-v4 auto-injection provides additional structured data (features, value ranges) without manual maintenance. ### Handling Incomplete Information Many GitHub issues have incomplete data (e.g., unknown byte meanings, untested commands). The template should accommodate this with: - `???` or `unknown` markers in YAML blocks - "Unconfirmed" labels on commands - Notes section for caveats about data quality ### Non-BLE Protocols Existing non-BLE docs (serial, e-stim, network) get a light-touch update: - Move into brand directories following the same structure - Add frontmatter with `transport: serial` (or `usb`, `network`, etc.) - Keep their existing content format, applying the general section structure (Introduction, Protocol/Commands, Notes, Sources) where it fits - No YAML BLE profile block (not applicable) ### Breaking Changes - All existing `stpihkal/protocols/.md` URLs will change to `stpihkal/protocols//` - Docusaurus can handle redirects via `@docusaurus/plugin-client-redirects` if needed - Internal cross-references (e.g., Kiiroo Onyx 2 → Fleshlight Launch) must be updated --- ## Embedding The Application Guide portion of this document focuses solely on connecting to Intiface Central in order to access a Buttplug Server. However, there are some situations in which embedding a server in your application may be desirable, or even required. For instance, you may want your users to be able to use your application right after install, without having to also install Intiface Central. Less commonly, your application may be deployed on a platform where talking to Intiface Central may not be available (like running completely in a web browser, or standalone on mobile). There are two methods of achieving this, each with their own drawbacks. > **Caution: Before You Tackle Embedding** If you are going to embed an engine, try to make sure you also provide a way for the user to access Intiface Central if they so choose. This will allow users to use new hardware that may not be supported by the version of Buttplug/Intiface you embed in your application. If you embed without giving users a way to connect outward to updated versions, you may get complaints once new hardware is released and your program does not support it. ## Embedding Intiface Engine For desktop applications that can spawn external processes, one option is to ship with the latest version of [Intiface Engine](https://github.com/intiface/intiface-engine). This is a command line version of the Buttplug Server, with all configuration elements exposed via arguments. The downsides here are mostly related to user configuration. Buttplug ships with support for a lot of devices, and many of those devices may require special configuration by the user. This configuration is handled by Intiface Central, so that when a users starts a server using Central, they can only load what they need and expect. When embedding a server, you may have to use a default setup that may not work with the user's needs. Another downside is modern OS sandboxing. Windows and macOS do not like programs that start other programs, and you may run into problems with a user's security system blocking process execution. The usual strategy for embedding an engine is: - Ship your application with a copy of Intiface Engine for the platform your application is on. - When your application starts, try to connect to Intiface Central (or give the user the ability to pick a new address, as they may be using the mobile app and have to set a new address). - If no port is found for Intiface Central, you can try starting your own Intiface Engine process and connecting to that. You will need to provide the user with a way to restart the engine process in case things lock up or crash. ## Embedded Servers and Connectors > **Warning: You Probably Don't Want This** For most normal desktop and mobile applications, you do not want to use an embedded connector. While embedded connections used to be recommended for Buttplug development, they have ended up causing more harm than good, but are still required for certain situations, which is why they're included here. This section should really only be used if: - You want a fully web based system with no outside dependencies (i.e. using WASM inside the browser) - You need to compile the full server into your application for some reason. For instance, Intiface Central on desktop and mobile has to build with an embedded server in order to host it for other applications, as another process cannot be started due to sandboxing. This is a fairly rare occasion. - Quick one-off examples in Rust since you get it for free there, and even then, you should really use Intiface Central If you want to avoid your users having to download Intiface Central to use your program, see the Embedded Engines section above. An Embedded server means both the client and server are part of the application are you building. While doing this ends up being more convenient for the user in some ways, as they have less setup to do and choices to make, there are a few drawbacks, including: - If the libraries upgrade (which is how we usually deal with new hardware/protocol support), you'll need to upgrade your app too. - This may tie you to a certain platform, i.e. if you're using Windows libraries, your application might only run on windows. This all depends on the library you're using, though. - You may need to set up the server yourself in your application. - The only reference server is currently written in Rust, which means using an embedded server requires pulling in the Rust codebase in one way or another. This is usually done with FFI of some sort (including compiling to WASM). Errors in this setup can be extremely difficult to debug if you are not familiar with your base language and FFI bindings. There's not really much to cover about the first two problems, they're just part of the choice you make in using this method. The example below shows how to set up a server with a bluetooth device manager, using the configuration file built into the library. **Rust:** Currently, this example is only available in Rust. A Javascript example will be added once the FFI system has been rebuilt to use it. ```rust use buttplug_client::ButtplugClient; use buttplug_client_in_process::{ButtplugInProcessClientConnectorBuilder, in_process_client}; use buttplug_server::{ButtplugServerBuilder, device::ServerDeviceManagerBuilder}; use buttplug_server_device_config::DeviceConfigurationManagerBuilder; use buttplug_server_hwmgr_btleplug::BtlePlugCommunicationManagerBuilder; #[allow(dead_code)] async fn main_the_hard_way() -> anyhow::Result<()> { let dcm = DeviceConfigurationManagerBuilder::default() .finish() .unwrap(); let mut device_manager_builder = ServerDeviceManagerBuilder::new(dcm); device_manager_builder.comm_manager(BtlePlugCommunicationManagerBuilder::default()); // This is how we add Bluetooth manually. (We could also do this with any other communication manager.) let server = ButtplugServerBuilder::new(device_manager_builder.finish().unwrap()) .finish() .unwrap(); // First off, we'll set up our Embedded Connector. let connector = ButtplugInProcessClientConnectorBuilder::default() .server(server) .finish(); let client = ButtplugClient::new("Example Client"); client.connect(connector).await?; Ok(()) } #[tokio::main] async fn main() -> anyhow::Result<()> { // This is the easy way, it sets up an embedded server with everything set up automatically let _client = in_process_client("Example Client").await; Ok(()) } ``` --- ## Buttplug Client/Server Ping Ping timing is a property of a Buttplug session negotiated when a client connects to a server. Ping is a Buttplug protocol specific negotiated keep-alive, with the server dictating the expected ping time to the client. A ping time of 0 denotes "no ping expected", while any number above that is the expected maximum amount of time in milliseconds between pings. Ping exists to try ensuring some basic level of safety for usage if a client application locks up, remote connection is interrupted, or other horrible scenarios occur that stop ping messages from being transmitted. If a client does not send a ping message within the alloted time, the server is expected to disconnect and stop all devices that are currently active. Keeping in line with the knowledge that reference, and most likely, all implementations of Buttplug are neither real-time constrained nor safety-guaranteed, the Ping system is more of a vaguely hopeful mitigation than a secure requirement. Your milage may vary. Don't die. For some connectors, like the Websocket connector, there may already be ping built into that protocol, at which point Buttplug Server Ping may be redundant. In reference library implementations of the Client, ping negotiation is handled opaquely by the client API. It is assumed that if the client's event loop fails to send a ping, the program has most likely locked up or crashed, and therefore everything should be shut down. Therefore, no code samples are provided for this. It should *just work*. On ping failure in the client APIs, you should either receive some sort of event or callback denoting the error. The event or callback arguments will contain an error with an error class type of ERROR_PING. Any subsequent calls to server commands (device search/commands, etc) will fail from this point on. **C#:** ```csharp // Buttplug C# - Ping Timeout Example // // This example shows how to handle the PingTimeout event. // Note: Ping handling is automatic in the C# client. The PingTimeout // event fires when the server fails to respond, indicating the connection // should be considered dead. using Buttplug.Client; var client = new ButtplugClient("Ping Example"); // The PingTimeout event fires when the server doesn't respond to keep-alive pings. // This usually means the connection has been lost. client.PingTimeout += (sender, args) => { Console.WriteLine("Ping timeout! Server connection lost."); Console.WriteLine("All devices should be stopped by the server."); // In a real application, you would: // - Update UI to show disconnected state // - Attempt to reconnect if appropriate // - Clean up any resources }; // Connect normally - ping handling is automatic await client.ConnectAsync("ws://127.0.0.1:12345"); Console.WriteLine("Connected. Ping keep-alive is handled automatically."); Console.WriteLine("Press Enter to disconnect..."); Console.ReadLine(); await client.DisconnectAsync(); ``` --- ## Devices and Commands In this section, we'll be covering how device command and control works. While this was mentioned briefly in the [Your First Buttplug App section](../../writing-buttplug-applications/intro), here we'll be going into the specifics of each device message type for the current Buttplug Spec and what you can do with them. --- ## Buttplug and Games This section will give an overview of integrating Buttplug with various game engines, or via mods to games. Every game is unique, so the amount of advice that can be provided is limited, but we'll start with some general rules for game dev with Buttplug, and cover what can be done with the major engines and modding frameworks. ## Rule #1: READ THE REST OF THE DEVELOPER GUIDE **Seriously.** Just because you're developing or modding a game does not mean you are immune to using Buttplug as a library. It just means you may be integrating Buttplug under a different framework than a desktop gui, mobile app, web page, etc... Even with that difference, all of the same rules of using Buttplug will still apply, and you'll need to know how clients, devices, and other pieces of the system work. ## Rule #2: Make Sure Integration Will Be Worth Your Time Take some time to make sure you know why you're integrating Buttplug, and that it's going to be worth it. Here's an incomplete list of things to consider: - Do players of your game expect sex toys to work with it? - For porn games, this is pretty obvious - For other games, think about the community. Will they actually want to use what you build? If they don't, will they appreciate the shitpost at least? - Do players of your game *have* sex toys that work with it? - It can be worth it to do a quick poll to see if you have users that already have hardware, so you can use them as testers. - Even if they don't, if you think your idea is good enough, integrating toy access could work in your favor by drawing players in. Think of it as a marketing tactic. - What mechanics are in the game that will work with toys? - Interacting with toys usually needs some sort of contextual event to take place, and those events need to happen enough to keep things interesting. Remember, your player is going to have to get out the toy, turn it on, connect it, make sure it stays connected, etc... So if your game would only trigger it once in a long while, are they going to do that? - You know your players better than anyone, so even if your game mechanics are such that toy interaction would be sparse, would they still be interested? - Is gamepad rumble already integrated in the game? - If so, this may make your life way easier. You can just send a subset of the rumble commands to Buttplug and release that as a first pass. - Do you want to put in the work to move beyond vibration? - Buttplug supports more motion/actuation types than just vibration. For instance, stroking devices may be far more interesting to some players than vibration. However, integrating type of hardware actuation that *only* Buttplug supports can be extra work. When considering real time interaction, sometimes this may be a *lot* of extra work. That work can reap serious rewards both for current players that have the hardware and marketing to new players, but consideration of the effort should be done up front. Make sure you have good answers to all of these questions before progressing to the next rule, otherwise you may just be needlessly costing yourself resources. ## Rule #3: Always Make Sure You Can Turn Off Buttplug Before you even get to figuring out how you're going to integrate Buttplug: Unless your game requires hardware to function, make sure usage of Buttplug is opt-in. Hardware support is complex, and Buttplug will be hiding a lot of that complexity from both you and your users. While we strive to make sure that the library doesn't crash arbitrarily, we aren't perfect, and bugs will happen. You want to make sure your game is playable without hardware, and that if there is a hardware error/failure, the game degrades gracefully. ## Rule #4: Choose Your Integration Strategy Up Front How you integrate Buttplug with your game is something that should be decided early on. While there's a recommended way to do things that we'll go over first, there are also alternatives that may work better for you but will require extra upkeep on your end. ### Rule #4.1: Recommended - Just Connect Out To Intiface Central The easiest thing to do about managing Buttplug hardware management is leaving it to us (the Buttplug at Nonpolynomial). This means having your users download and install [Intiface Central](https://intiface.com/central), which handles devices configuration and connections, as well as updates to the hardware portions of our systems. In your game, you'll use a plugin like [Buttplug Unity](https://github.com/buttplugio/buttplug-unity) or [Buttplug Twine](https://github.com/buttplugio/buttplug-twine) to connect to Intiface Central. We do our best to maintain full backward compatibility with older versions of our libraries, so hopefully if your game works with Intiface Central whenever you develop it, it will continue to work in the future. It's important to know that there are certain pieces of hardware that require specialized configurations that Intiface Central handles via user configuration. Games that do not connect to Intiface Central may miss these configurations and will have to deal with user questions regarding those issues. While we realize there's issues in requiring users to download *more* software when you'd like your game to Just Work, this method is similar to how other commercial systems like bHaptics, various system LED/Lighting systems, etc work. Gamers are used to having support programs these days, and Intiface Central is just another one on the pile. Directly using Intiface Central also means that if users have hardware access issues, support can come from the Intiface community, as everyone is using Intiface Central. ### Rule #4.2: Shipping Intiface Engine With Your Game And Also Connecting to Intiface Central If you absolutely, positively cannot live with your user possibly having to download and run an outside program with your game, there is an option for you that is not recommended and we do not support. You can ship a copy of [Intiface Engine](../../architecture/intiface.md) with your game, and, after checking to make sure Intiface Central is not running already, start the process when your game starts. This will give you a visibly seamless start to your game's hardware support, but at a very high cost. Shipping Intiface Engine is what the Buttplug Unity plugin used to do, and it was a very bad idea for multiple reasons: - Any time Intiface Engine updates, you need to update along with it, otherwise you miss out on support for new hardware, or bugfixes. - You need to detect if the user is already running Intiface Central. - Starting extra processes that access hardware and other OS resources can possibly be flagged as a security issues on some user's machines. - You miss any configuration that the user may have set up in Intiface Central, which may include configuration required for certain devices. - You have to bring up all device communication managers, as you don't know what devices your user may have. This may cause extra resources to be used on the system that will be wasted. We highly recommend just relying on Intiface Central and not shipping Engine with your game. We do not have any officially supported plugins that handle this strategy now, so you're on your own if you go this route. ## On To Game Dev With all of that out of the way, let's talk about developing games in specific engines and mod frameworks. --- ## Buttplug and Unity This will be a relatively short chapter for now, because: Using [Buttplug Unity](https://github.com/buttplugio/buttplug-unity) is now just using [Buttplug C#](https://github.com/buttplugio/buttplug-csharp)! As of Buttplug Unity v3, there's nothing particularly special about using Buttplug with Unity anymore. We're just repackaging the DLLs from Buttplug C# in a way that's easy to use with Unity. Our package also follows [Rule 4.1](../intro.md) of our Buttplug Game Dev Rules, meaning that it only connects out to Intiface Central. This means that, for you as a Unity developer trying to integrate with a Buttplug game, you can just go through our [Writing Buttplug Applications](../../writing-buttplug-applications/intro.md) section and learn most of what you'll need to know about basic usage of the Buttplug library. There's an example Unity project in Buttplug Unity for those wondering what simple interaction with the library looks like from a Unity standpoint. > **Caution: More Unity Content Coming, Someday** We've found out the hard way that a lot of Unity devs aren't necessarily .Net flavored C# devs. Buttplug C# relies heavily on things like the C# Async system and other components that may be new to Unity developers. At some point in the future, we are hoping to feature more information about using Buttplug with Unity in this guide, to better describe how to integrate buttplug with games. We just have to learn Unity first. --- ## Buttplug and Unreal Buttplug support for Unreal Engine is provided by the community. The [List of Awesome Buttplug Projects](https://github.com/buttplugio/awesome-buttplug) has a [section for game development libraries](https://github.com/buttplugio/awesome-buttplug#game-development) with multiple options for Unreal Engine integration. --- ## Adding a New Device Comm Manager --- ## Adding a New Device Protocol --- ## Device Configuration When run with no configuration, Buttplug has no information about any devices and won't actually do anything. As this is a device control library, that situation is not ideal. There are a few ways to two device configurations to buttplug: - Via the API - Via the configuration files While configuration files will be the way this is done 99% of the time, both methods will be covered here. ## Configuring Devices via the Device Setup API > **Info: Rust Only section** As this requires working with the Buttplug Server, the content covered in this section is currently only available via the Rust implementation of buttplug > **Warning: Not Yet Written** Skipping writing this section for now so I can get the file sections written up. I highly doubt anyone uses this anyways. ## Configuring Devices via the Device Configuration File > **Caution: Feature Not Standardized** The following feature is an aspect of the Buttplug Reference implementation, and is not part of the specification for the protocol. Therefore, this information may change in relation to revisions of the Buttplug Library rather than the protocol specification. > **Caution: Section Incomplete** This section will cover the basics of device configurations for now, but doesn't go into the specifics of identifier blocks for device enumeration, or message capability definition. In lieu of having to change source code every time a new device needs to be added, the Rust implementation of the Buttplug Server has a utility system for loading device configurations from a JSON file. This is known as the Device Configuration File, or DCF. The DCF is the main source of truth for device configuration in Buttplug, and as such, is stored with the source code. For human readability and ease of editting, the core file is a YAML file that is converted to JSON (and checked against [a JSON Schema](https://github.com/buttplugio/buttplug/blob/master/buttplug/buttplug-device-config/buttplug-device-config-schema.json)) on build. [These files are available in the Buttplug Github Repo.](https://github.com/buttplugio/buttplug/tree/master/buttplug/buttplug-device-config) The DCF is indexed by device protocols. Each protocol contains multiple key/value pair sections: ### Identifiers - Keys for identifiers are `btle`, `serial`, `usb`, `hid`. All other keys are usually specialized for specific Device Communication Managers (DCMs). There may be multiple identifier keys in a single protocol, as some protocols support toys that work on multiple DCMs (i.e. the manufacturer makes toys that connect over bluetooth or USB and uses a similar control protocol over both, etc...). - These sections define how devices that implement this protocol should be found by a DCMs. Bluetooth LE identifiers will list device names and service/characteristic info, Serial identifiers will list port names, baud rates, etc, USB and HID identifiers use VID/PID pairings. - Some specialized systems do not have identifiers. For instance, the XInput Gamepad connection system will simply find all compatible gamepads connected to the system by default, and therefore does not need an identifier setup. These sections will usually have a single specialized identifier set to `null`. ### Default Configurations - Key for default configurations is `defaults`. - Defaults denote what name should be assigned, and messages allowed, for a device that we cannot detect more info on. For instance, it can be assumed that all Lovense devices will react to a single vibrator command, even if there is no information available about exactly which type of Lovense device it is. Therefore the name is set to _Lovense Device_ and the messages can be set to a _ScalarCmd_ with _Vibrate_ type and _20_ as max steps. This means that, if a new Lovense device is released and the Buttplug Library and/or its configurations have not been updated yet, the library will still at least support some features of the toy. - For some devices/protocols, there is no identifying information available. Therefore the `defaults` section is used to set capabilities for all devices that use that protocol, and no custom configurations are given. Here's an example of a simple device/protocol configuration. The manufacturer Aneros only puts out a single toy that Buttplug supports, the _Vivi_ prostate massager. Therefore, we know that any hardware with the bluetooth name of `Massage Demo` and the specific services/characteristics setup listed will be a _Vivi_, and so we can just use a `defaults` section that defines the 2 controllable motors. ```yaml aneros: btle: names: - Massage Demo services: 0000ff00-0000-1000-8000-00805f9b34fb: tx: 0000ff01-0000-1000-8000-00805f9b34fb defaults: name: Aneros Vivi messages: ScalarCmd: - StepRange: [0, 127] FeatureDescriptor: Perineum Vibrator ActuatorType: Vibrate - StepRange: [0, 127] FeatureDescriptor: Internal Vibrator ActuatorType: Vibrate ``` ### Custom Configurations - Key for custom configurations is `configurations`. - Custom Configurations provide name and message information for a specific device type. Information from the `defaults` section is inherited here, but any included top level settings in a custom configuration (`name`, `messages`, etc...) will override the corresponding `default` key. - Extending the Lovense example from above, the Lovense protocol implementation has a way to detect the identifier for a device. The Edge Prostate Massager has 2 motors available: an internal vibrator and a perineum vibrator. Knowing that, a custom configuration can be added with the Edge identifer (in this case, _P_ is the identifer for the Edge in the Lovense Protocol). This block will provide the specific name (_Lovense Edge_) and specific message information (a _ScalarCmd_ specification with 2 _Vibrate_ definitions) to provide control methods for all device components. A condensed example of the Lovense protocol section is provided below as an example of customized configurations: ```yaml lovense: btle: names: - LVS-* - LOVE-* services: 50300011-0023-4bd4-bbd5-a6920e4c5653: # Edge2 paired tx: 50300012-0023-4bd4-bbd5-a6920e4c5653 rx: 50300013-0023-4bd4-bbd5-a6920e4c5653 defaults: name: Lovense Device messages: ScalarCmd: - StepRange: [0, 20] ActuatorType: Vibrate SensorReadCmd: - FeatureDescriptor: Battery Level SensorType: Battery SensorRange: [[0, 100]] configurations: # For lovense, our identifiers are the letters returned from the # DeviceInfo query sent on initialization. - identifier: - B name: Lovense Max messages: ScalarCmd: - StepRange: [0, 20] FeatureDescriptor: Vibrator ActuatorType: Vibrate - StepRange: [0, 3] FeatureDescriptor: Air Pump ActuatorType: Constrict - identifier: - P name: Lovense Edge messages: ScalarCmd: - StepRange: [0, 20] ActuatorType: Vibrate - StepRange: [0, 20] ActuatorType: Vibrate ``` ## Customizing Devices via User Device Configuration Files While the DCF is good for configuration global information about devices in order to connect them, there is information that a user might want to add for their specific instance. Specifications for protocols that are context specific like Serial port names, customized device names for situations where multiple of the same device may be used, limited to the maximum power output, etc... For this situation, there is the User Device Configuration File (UDCF). The UDCF allows customizations on protocols and custom device configurations. It **does not allow** for additions of new protocols, only refinement of or additions to already supported protocols. ### UDCF Protocol Extensions > **Caution: Section Incomplete** This section is pretty much specifically for OSR-2/SR-6 users, who can continue to wait. ### UDCF Device Customizations In addition to connection identifiers, users can change or add device customizations on top of what is provided in the DCF. Unlike the custom configurations in the DCF which pertain to a type of devices, these customizations are per-specific-device. ## Experimenting with DCF and UDCF Changes --- ## Adding Devices Overview Devices are by far the most common addition to Buttplug. Between new devices that've just arrived on the market, or filling out support in the library for older devices missing implementations, the device portion of the Server sees a lot of code editing actions. As a quick refresher on the device system as it's implemented in Buttplug v6+: - Device information is loaded from a combination of the Device Configuration File and the User Device Configuration File. - When a Buttplug Server is created, these configuration files are loaded into the server, along with Device Communicaiton Manager instances that define how devices can be connected (via Bluetooth, USB, HID, etc) - When the Buttplug Server is sent a `StartScanning` message, Device Communication Managers look for devices, which are then compared to the information from the Configuration files. - If a device matches the specifiers in the configuration file, and Buttplug implements the protocol that the device uses, then the device is connected and emitted to the client for control. This section outlines all the actions needed to add new devices to the system, going from most to least common tasks: - Adding devices in the Device Configuration File - In addition to this, we'll cover the User Device Configuration system, which allows users to futher customize devices or add configurations that are purely local (DIY builds, etc...) - This requires editing YAML/JSON files. - Connecting device via the Websocket Device Manager - This allows users to have Buttplug send command packets over a network instead of a dedicated hardware connection, meaning they can either build a simple hardware flow without having to learn Bluetooth/USB/etc, or build pure software network devices for testing or simulation. - Connection to the Websocket Device Manager can happen from any language with a network library and websocket capabilities - Adding new device protocols - When a new company appears or a new set of devices is released, new protocols need to be added to the library to support device control. - Implementing new protocols requires work in Rust. - Adding new device communication managers - While Buttplug already handles multiple types of device communication, new technologies and systems appear every once in a while that require additions of completely new communication managers. While this is rare, it's good to know how to add these to make sure device support is robust as possible. - Implementing new device communication managers requires work in Rust. --- ## Websocket Device Manager > **Caution: Feature Not Standardized** The following feature is an aspect of the Buttplug Reference implementation, and is not part of the specification for the protocol. Therefore, this information may change in relation to revisions of the Buttplug Library rather than the protocol specification. The Websocket Device Manager (WSDM) takes advantage of the User Device Configuration File (UDCF) to allow for dynamic addition of devices to Buttplug. This allows users to connect devices that may not be supported directly by the library, such as DIY systems or devices that are difficult to obtain. The WSDM also allows users to build simulated devices in software in whatever language they please (that supports websockets), for testing and prototyping purposes. This section outlines the requirements for adding device configurations to Buttplug for use with the WSDM, as well as describing the handshake protocol used with the system. It will end with a full example script for building a simulated device in Python, and testing the script with [Intiface Central](https://intiface.com/central) or [Intiface Engine](https://intiface.com/engine). ## WSDM Functionality Here's an overview of how the WSDM works: - Creation of the WSDM allows for setting the host and port that the WSDM server will listen on. - The WSDM is added to the ButtplugServer during the Buttplug server configuration step. - When the Buttplug server is started, the WSDM will start its own server, and listen on the specified host/port combination. - At this time, a device can be connected to the WSDM server port. - Devices will need to follow the handshake protocol to identify themselves to the system. - Devices can connect to/disconnect from the WSDM *outside of _StartScanning_/_StopScanning_ pairs. _DeviceAdded_ events may fire at any time. - Once the device is connected and emitted via _DeviceAdded_, it can be used normally by Buttplug Clients. - Communication with the device will use the same protocol as any original device would use, so any expected returns must be provided. **Outside of the initial handshake, which is text, all information sent and received by a Websocket Device will use binary format websocket messages.** As Buttplug usually has to format strings into byte arrays when sending to hardware, that expectation is continued with websocket devices, even when they may send text back and forth as part of their protocol. ## Extending Protocol Configurations for the WSDM Before connecting a Websocket Device, it must be added to the User Device Configuration File. This allows the user to define the protocols that will respond to websocket device connections. Any protocol that already exists in the DCF can be extended in the UCDF to use the websocket system. A `websocket` specifier is used, which will contain the possible identifiers of the connecting device. Unlike bluetooth name definitions, **websocket names cannot use wildcards**. For a running example through this section, the Lovense protocol will be extended to handle a websocket device connection, starting with a completely clean UCDF. ```json { "version": { "major": 2, "minor": 6 }, "user-configs": { "specifiers": { "lovense": { "websocket": { "names": ["LVSDevice"] } } } } } ``` This is all that is contained in the UCDF for the moment, but will now allow creation of a new websocket device that will communicate using the Lovense Protocol. ## Connecting to the Websocket Device Manager With the protocol extended to expect websocket devices, specific device information can now be added. For simplicity, the device added in this example will just have a single vibrator, emulating a Lovense Hush device (lol, buttplugs). The WDM handshake expects as single JSON packet as its first received data, in the following format: ```json { "identifier": "", "address": "", "version": 0 } ``` - `identifer` should match the identifier of the originating device to map to the connecting device. The Lovense Hush uses the identifier _Z_. - `address` is an arbitrary string used to identify the device across sessions. It should be set to a random string. - `version` is the version of the WDM protocol being used. As of this writing, the protocol is on version 0. Any increment in this protocol should be considered to be backwards incompatible, and connecting systems may be rejected if they do not match the version number. For the Lovense example, the generated JSON block would look like this (with the address mapping to the expected output of the Lovense `DeviceType;` protocol command): ```json { "identifier": "Z", "address": "8A3D9FAC2A45", "version": 0 } ``` This JSON block should be the first thing sent to the WSDM server. After this, one of two things will happen: - If the WSDM server accepts the device, all further communication will be in the context of the requested protocol, from its initialization phase. - If the WSDM server rejects the device, the websocket is closed with an error reason. Proper handling of the initialization phase for a protocol will be required. Check [STPIHKAL](/stpihkal) for info on the initialization phases of certain protocols. ## WSDM Python Example The following code is a full python example of a WSDM setup. The python script: - connects to the WSDM server - identifies as a Lovense Hush to the WSDM - sends back a valid `DeviceType;` respond to handle the lovense protocol initialization - prints out any vibration command send - responds to battery level queries ```python # TODO: WebSocket device manager example for Buttplug v4 # This is a stub file - real example coming once client library support is implemented ``` ### Running the WSDM Python Example A UDCF will need to be created with the following info (this file is also in the examples/python directory of the docs repo): ```json { "version": { "major": 2, "minor": 6 }, "user-configs": { "specifiers": { "lovense": { "websocket": { "names": ["LVSDevice"] } } } } } ``` To run the example above using [Intiface Engine](https://github.com/intiface/intiface-engine), build or download the executable for your platform and run: ``` intiface-engine --websocketport 12345 --use-device-websocket-server --user-device-config-file [path to the UDCF created above] ``` To run the example above using [Intiface Central](https://github.com/intiface/intiface-central), the UDCF will need to be copied to the Intiface Central configuration directory. > **Tip: This will be in the UI someday** As of this writing, Intiface Central is currently lacking a User Device Configuration UI. Getting this added is one of the top priorities for development, but for now, manual file editing and moving is required. The Intiface Central Configuration directory on desktop platforms is as follows: - Windows: `C:\Users\[UserName]\AppData\Roaming\com.nonpolynomial\intiface_central\config\buttplug-user-device-config.json` - macOS: `/Users/[UserName]/Library/ApplicationSupport/com.nonpolynomial/intiface_central/config/buttplug-user-device-config.json` After the UDCF is copied, open Intiface Central and make sure the `Device Websocket Server` is turned on in the settings panel. ![Intiface Central Settings Dialog](/img/dev-guide/inflating-buttplug/websocket-device-manager/intiface-central-wsdm.png) --- ## Adding New Programming Language Implementations via FFI --- ## Writing a Buttplug Client --- ## Writing a Buttplug Server --- ## Client Architecture(Writing-new-clients) --- ## Client Devices(Writing-new-clients) --- ## Intro --- ## Buttplug Development Docs - [Buttplug Developer Guide](dev-guide/) - [Buttplug Protocol Specification](spec/) - [Sex Toy Protocols I Have Known And Loved](/stpihkal) --- ## Plans for the future So maybe you're wondering why I started a patreon now, well after that bandwagon has already set down the highway at full speed? Like I said in the campaign description, there's a lot of toys coming out now. I really want to reverse engineer all of them so I can continue my plans for world domination via genital manipulation robots. However, it's getting kinda spendy to keep buying stuff myself. For instance, I dropped $600 on the ET-312 last year, and while we've gotten a HUGE amount of reversing milage out of that (more on that in a later post), that was still super spendy.  Here's my toy purchasing list at the moment: - SayberX - Rends Vorze A10 Cyclone - Kiiroo Launch - Vibratissimo Duo - Whatever the OhMiBod bluetooth toy is - eJaculator when it comes out And I'm sure there's more toys on the way. The plan for the moment is to try to burn through that list, get as many things bought and reversed as possible, and get [https://buttplug.io](https://buttplug.io) into at least alpha release so I can start integrating what I've reversed there. While I'll really be shocked if I make enough money from Patreon to fully fund any of these toys completely, it's nice to know there's people out there interested enough to put money toward this. In 13 years of doing this, I've really not made very much cash, mainly because I've never tried. This is a hobby, not a job. There's never been advertising on Metafetish, and unless a company buys the VIP status thing, there probably never will be (and even if they do, I'll try to keep it interesting). So, thanks for donating. Now to see where this goes. --- ## Fleshlight Launch and Vorze A10 Cyclone on the Way I now have a Kiiroo/Fleshlight Launch and a Vorze A10 Cyclone on there way to do. I have a feeling the Launch will just be the Kiiroo protocol as it is at the moment, but it'll be fun to see what the Battleship Cockrobot looks like in person (no seriously it's huge. [http://fleshlight.com/launch).](http://fleshlight.com/launch).) The Vorze ([http://vorzeinteractive.com)](http://vorzeinteractive.com)) is a Japanese toy that finally got american release. Having looked through their player software (which is literally just libvlc plus a tiny bit of glue code, and all in japanese), it seems to just be a using a USB VCP/Serial driver. Hopefully that should come apart pretty quick. Anyways, new fun stuff to take apart, partially thanks to Patron cash! Thanks again for supporting Metafetish! --- ## Sex Toy Reverse Engineering Update A public patreon update, just to give everyone an idea of the kind of work that patreon dollars fun! (Well and also because this is a [metafetish.com ](http://metafetish.com) post anyways)Most of the reverse engineering happening now is in preparation for getting v0.1 of [Buttplug](http://buttplug.io/) out the door. What that release will actually look like is anyone's guess, but the more toys we have documented and reversed, the better. I'll usually be covering reverse engineering and software development work over on [the Buttplug.io blog](http://buttplug.io/blog) and leaving this blog for featuring news, business, and other people's projects (with buttplug update posts every so often), but I'm taking this opportunity to update both places since I haven't written anything about my own work in a while. First off, all of our documentation and code repos are still at [http://github.com/metafetish](http://github.com/metafetish) I'm also trying to keep hardware information up-to-date and available on the [buttplug.io website](https://buttplug.io/). Keep an eye on the hardware menu, and I'll probably add a "Recently Updated" section to the front of the site soon. Anyways, onto the libraries! The Kiiroo and Lovense libraries have been getting the most love lately, but I'm slowly working my way through documenting as much as possible now before writing any more code. # Miiyoo Repos for the [Kiiroo](http://www.kiiroo.com/) line of toys, including the [Onyx](http://www.kiiroo.com/onyx), [Pearl](http://www.kiiroo.com/pearl), and upcoming [Launch](http://fleshlight.com/launch) toys. - Documentation of Kiiroo's devices, bluetooth protocol, and REST API   for their "desktop platform" software is   at   [http://metafetish.github.io/miiyoo-docs](http://metafetish.github.io/miiyoo-docs),   repo   at   [http://github.com/metafetish/miiyoo-docs](http://github.com/metafetish/miiyoo-docs). - I'm also working on python libraries for direct control of Kiiro   toys, as well as platform (http server) emulation   at   [http://github.com/metafetish/miiyoo-py](http://github.com/metafetish/miiyoo-py).   Javascript and Rust implementations will come after that. # Lovesense Repos for the [Lovense](http://www.lovense.com/) line of toys, including the Max, Nora, Hush, and Lush.  - Documentation of Lovense's devices and bluetooth protocols are   at   [http://metafetish.github.com/lovesense-docs](http://metafetish.github.com/lovesense-docs) - There's protocol libraries for python at [http://github.com/metafetish/lovesense-py](http://github.com/metafetish/lovesense-py) (or [lovesense on pypi/pip](https://pypi.python.org/pypi/lovesense), node/javascript at   [http://github.com/metafetish/lovesense-js](http://github.com/metafetish/lovesense-js) (or  [lovesense on npm](https://www.npmjs.org/package/lovesense)). Rust   libraries coming soon at [http://github.com/metafetish/lovesense-rs](http://github.com/metafetish/lovesense-rs) # KHole Repos for the [Minna KGoal](https://www.minnalife.com/products/kgoal) bluetooth kegel exerciser - Python proof of concept at [http://github.com/metafetish/kgoal-py](http://github.com/metafetish/kgoal-py) - Documentation and more code coming soon! # Wejibe Repos for the [Wevibe](https://www.wevibe.com/) line of products. - Very basic documentation   at   [http://github.com/metafetish/wejibe-py](http://github.com/metafetish/wejibe-py) # Buttshock (Estim Reverse Engineering) Repos for reverse engineering the [Erostek ET-312/ET-232](http://erostek.com/), [Estim Systems 2B](https://www.e-stimsystems.com/index.php?main_page=product_info&cPath=1&products_id=71), etc... - There's so many repos for this now that I'm just going to point to   the   [buttplug.io hardware page for the ET-312](https://buttplug.io/hardware/erostek-et312/).  # The Past The above toys are things that are still in production. We've still got repos for the Real Touch, Rez Trancevibe, VStroker, and Virtual Hole. # The Future I'm hoping to flesh out the above projects more. Getting documentation for everything, even the out-of-production toys, is the highest priority. After that, coding the usual set of python/javascript/rust libraries for toys still in production.  Python is usually just because I work fastest in that, so it's good for proof of concept. Now that WebBluetooth is defaulted on in Google Chrome on OS X, I'm trying to make javascript libraries that work either via node/[noble](https://github.com/sandeepmistry/noble) or WebBluetooth, where I can. Rust libraries are how we'll provide access from C, as well as integrate things into the actual Buttplug software. There's new toys to be working on, too! This includes: - [Kiiroo/Fleshlight Launch](http://fleshlight.com/launch) - [Rends Vorze A10 Cyclone](http://vorzeinteractive.com/) - [OhMiBod Bluetooth Toys](http://ohmibod.com/) - [SayberX](http://sayberx.com/) I'm hoping the patreon will fund some of these, because this hobby is getting expensive lately. The biggest problem right now is when I get to coding, I forget to write updates about what I'm doing, so the only people aware of updates are those that follow me on github. As I'm not sure anyone *actively* reads their github status timeline, I'm hoping having a dedicated blog for those topics on buttplug.io will help. It could also just end up being yet another blog I don't update. Time will tell, I suppose. --- ## Vorze Arrives Today! My Vorze ([http://vorzeinteractive.com)](http://vorzeinteractive.com)) arrives today! Mostly hacking this one due to interest from the RealTouchScripter forums at [http://www.realtouchscripts.com,](http://www.realtouchscripts.com,) same reason I'm working on the Fleshlight Launch. Small but engaged community, not to mention they share my nostalgia for the RealTouch. :) --- ## Well That Didn't Take Long! The problem with most sex toys is that no one is really trying to hide protocols these days, so once I get the hardware, this takes maybe half an hour.Vorze was no different. I've created the documentation repo at [http://github.com/metafetish/libcockblender-docs](http://github.com/metafetish/libcockblender-docs) And the formatted documentation is at [http://metafetish.github.io/libcockblender-docs](http://metafetish.github.io/libcockblender-docs) -- Basically, you just send 3 bytes to the toy, of the format [0x01, 0x01,  0xZZ]. The byte represented by 0xZZ denotes both direction and speed.  Speed is determined by the most significant bit (so 0x00-0x7f is  clockwise, 0x80-0xff is counterclockwise), speed makes up the rest of  the bits. It seems like there's 100 (0x64) speeds available, though  speeds < 5 don't seem to do anything. Sending speeds > 100 (like,  say, 0x65) don't seem to do anything, so if you're already running at a  certain speed, it'll just keep going. There may be error messages  incoming, but I haven't checked that yet. On windows, the dongle  acts as a serial port.  This is just a serial port emulation over USB on top of Bluetooth 4 (all  the protocols! \o/ ), so baud rate/data bits/etc don't matter. I think  you can just open the port and start spewing bytes at it. Still  not sure what those first 2 bytes in each packet denote, and the movie  player ain't real helpful for that. Will keep on that after I get this  initial documentation written up. --- ## Defeat of the Battleship Cockrobot For anyone not watching twitter tonight, I ended up livetweeting my reverse engineering and teardown of the fleshlight launch. I'll be writing up documentation and making a video too, but it's just too much fun to tweet stuff while I'm doing it (streaming soon hopefully!).If you want to experience the thread, it's at [https://twitter.com/qDot/status/844357346402873344](https://twitter.com/qDot/status/844357346402873344) --- ## Fleshlight Launch Shimming So, after talking to some people about the Fleshlight Launch hacking last night, I realized that the Launch really could work with almost any ona-hole style toy, all you need is a shim. Gosh. If only there was a way to get custom made, one-off plastics... :3 We're now working on some CAD models for 3D printing that should fit in the Fleshlight Launch, and allow usage of non-fleshlight toys like Tenga, Spider, etc. this would also allow for different toy offsets, as the Launch itself has a good .5-1" gap that would usually be filled by the extra length of the fleshlight insert. Once we get models and some tests done, I'll upload the models here, as well as putting up an instructable and posting them on thingaverse. --- ## The Yak Factory New blog post going up on buttplug.io tomorrow, but you get to read it first!-- When writing software for hobby projects, there's a tendency to go "Oh, I want to learn [thing]" and add that to the stack of things required to build the project. So far, buttplug has been no exception. Using [Rust](http://www.rustlang.org/) to build the desktop version was a great start for that. While Rust is a fantastic language that's really coming into its own, and provides great facilities for safe programming (something that doesn't happen in sex toys much if ever), the library ecosystem leaves a bit to be desired. There's not much in the way of GUI or hardware access libraries, and things like Bluetooth 4 libraries are basically non-existant (I realize [blurz](https://github.com/szeged/blurz) exists, but it's linux/dbus only). Instead of just writing libraries to support the toy hardware, I decided to try and fill things in, writing a [simple systray application library](http://github.com/qdot/systray-rs), which I'll then just use for status and opening a browser based GUI. Hardware is still a problem, though. Serial and USB Sex Toys shouldn't be too difficult to deal with, as there's already [serial](https://github.com/dcuddeback/serial-rs) and [libusb](https://github.com/dcuddeback/libusb-rs) bindings for rust. Unfortunately, most sex toys these days are Bluetooth 4/BLE, so serial and USB only get me support for legacy toys. I haven't been able to find libraries in ANY language that handle full Windows 10/macOS/Linux BLE. [node.js's noble](https://github.com/sandeepmistry/noble) comes close, but still doesn't work with Win10 UWP bluetooth APIs (though that support will be [coming in with the noble-uwp repo](https://github.com/jasongin/noble-uwp) the Creator's update next month). There's more info on desktop bluetooth [in this article I wrote on the subject last year](https://kyle.machul.is/2016/11/07/talking-bluetooth-le-on-desktop-in-2016/). Speaking of noble and node.js, at some point I decided one of the [things] I need to learn was node. I've been developing hardware access libraries in 3 languages: - Python: For proof of concept work, as this is the language I work   fastest in - Rust: For buttplug application work - Javascript: To both learn node and WebBluetooth, meaning that for   browsers supports WebBluetooth, no software has to be downloaded. Then there's the toys themselves. I've been picking up a bunch of new toys lately, including the [Vorze Interactive](http://vorzeinteractive.com/) and [Fleshlight Launch](http://fleshlight.com/launch). Getting new toys means: - Reverse engineering the toy - Writing documentation - Taking pictures - Adding a buttplug.io page - Writing libraries - THEN trying to figure out integration with the buttplug application   framework Needless to say, I haven't made it very far into development of the actual Buttplug application yet. To remedy this, I'm trying to give myself a good first goal for release. Coming up with these goals has been driven off conversations with [my patreon funders](http://patreon.com/qdot) and members of communities like the [RealTouchScripts Forum](http://realtouchscripts.com/), as well as assessing how I want to use what I've learned so far. The problem being that buttplug in itself is more of a development platform and less of an end-user application. That means adding yet another project to the pile, that will exercise the applications and the libraries in a way that's interesting to both me and users. With that in mind, I've created a repository for something I'm calling [SyncyDink](http://github.com/metafetish/syncydync). There's a trend these days of make web-based video players for toys, since it's fairly easy to throw together a GUI and play videos in HTML, and get the timing information out of them via javascript and requestAnimationFrame updates. However, every player uses a different format for their specific toy. Making a single player that can take the formats and send them to the Buttplug application (or just straight thru to WebBluetooth for platforms and toys that support it) seems like a good goal for QA'ing things. There's already a TON of haptics-encoded content out there, as well as people familiar with using it. ... But also it means I get to play with WebVR for 180 SBS videos.  See? I keep shaving, and the yaks keep coming out of the factory. Expect Buttplug and SyncyDink to be released sometime near the heat death of the universe. --- ## New Toy That's actually not mine (forwarding it to Internet of Dongs) but hey I can grab protocols before I reship. Vibratissimo Sette. Germany "underwear" toy. Has a temperature sensor as well as vibration, but there are no buttons on the device. It actually just stays on, constantly broadcasting until it dies. Only way to control it is an app that also has weird micro transaction purchases. --- ## Filming Wrapped for ButtPlugin with QDot Episode 001 Finally decided to stop waiting for all of the equipment I'd ordered to film, and just filmed yesterday. Did an unboxing-ish thing (since I unboxed it right when I got it it's not a true unboxing. I am horrible.) and teardown of the fleshlight launch. I'll be editing together the material over the next couple of days and posting soon to my new Youtube channel.Also, I'll be adding a new perk for all patrons: Blooper reel! It's less funny and more violently awkward, especially since I decided to try doing this episode without a script to see how well I could improv.  The answer is: not well. --- ## Filming continues Re-filming the Fleshlight launch teardown since I wasn't really happy with the first run thru. Looks like it'll end up being nearly an hour when I'm done, but it's a top to bottom analysis of the toy, the services it works with, marketing around it, etc. Hoping to have it out this week, just depends on how long editing takes. --- ## Buttplug with QDot Episode 0001 - Fleshlight Launch Unboxingish Analysis Oh my fucking god, I thought I was never going to get this finished. 43 minutes of hardcore buttplug engineering analysis about the Fleshlight Launch.I realize this is a REALLY long episode to start on, but I think I subconsciously decided to just throw all of my ideas at this and will now see what sticks. Upcoming videos will hopefully be closer to the 10-20 minute range, and divided into multiple videos if they're gonna break that limit. If you've got comments or suggestions, please let me know! This is my first foray into youtube video making, so I'm sure I've got a ton more to learn. Note that you'll probably get another post notification about this video too, as I'll be making a public patreon post once I get all of the cards/annotations/transcriptions done. But I figured I'd like patrons in on it now. :) --- ## Buttplugin with qDot Now Available on Internet Archive For those that don't want to watch via Youtube, Buttplugin' with qDot is now available for download on Internet Archive! [https://archive.org/details/buttplugin-with-qdot-episode-0001-fleshlight-launch-overview-and-teardown](https://archive.org/details/buttplugin-with-qdot-episode-0001-fleshlight-launch-overview-and-teardown) I'll be building an RSS feed for these soon too, so they can be used in podcast/vidcast apps. --- ## Metafetish Dev Log - Week of 2017-04-24 I just posted the first edition of my new weekly open source sex tech development log! Read all about what the open source buttplug development community has been up to this week.[https://www.metafetish.com/2017/04/26/metafetish-dev-log--week-of-20170424/](https://www.metafetish.com/2017/04/26/metafetish-dev-log--week-of-20170424/) --- ## Coming Soon - An Application I Have Yet to Name But That Involves the Buttplug Last week, after 4+ years of trying to figure out some completely cross platform solution before even starting to build my sex toy server application, I decided to just do a quick implementation in C#, which should at least cover Windows 10 Creators Update (possibly earlier versions if you don't mind losing BLE device support), and possibly iOS and Android if Xamarin works out.Turns out, this ended up being a pretty good idea, because I now have a basic system working that can communicate via json over websockets, to control the Fleshlight Launch, as well as gamepad rumble. I'm now working on getting a simple CLI and GUI together for it, as well as some documentation and tests, and I'm hoping to make a v0.0.1 release this week. You may have noticed the overly long title to this post, though. Originally, I was just going to call everything Buttplug, 'cause that's what I do. The library, the application, all of it. However, after talking to a few people and doing a bit of thinking, I realized I should probably leave the reusable library portion of the software named Buttplug ('cause then I can say software has Buttplug inside :D ), but the application name should probably line up across Desktop and Mobile platforms, and should probably be somewhat innocuous, just in case I try to get this into the app stores (it'll be free there, mostly using that for distribution). I'm still working on what that name is going to be, but I've still got a few days before I have things releasable, so I've got time to think. If anyone has any ideas, I'm listening. For anyone interested, the repo for all of this work is [http://github.com/metafetish/buttplug-csharp.](http://github.com/metafetish/buttplug-csharp.) I still plan on doing a cross-platform Rust implementation, but this has already given me a lot of ideas about how this should be put together that will be helpful for all future implementations. --- ## Still Buttpluggin The code binge to get C#/Win10 buttplug out the door continues, and it's going really well! Support for the Fleshlight Launch, Vibrating Lovense Toys, and XInput/XBox compatible gamepads is in and working, and I'm hoping to start implementing some applications on top of this functionality soon, ahead of a v0.0.1 release.I'm also starting to plan for the post C# world, mostly looking forward to getting back to the comfyness of Rust. I've done a bit of repo shuffling, so now the main buttplug repo ([http://github.com/metafetish/buttplug)](http://github.com/metafetish/buttplug)) is now just documentation, json schemas, etc. I've moved the rust implementation to [http://github.com/metafetish/buttplug-rs.](http://github.com/metafetish/buttplug-rs.) The JSON schema for the messages I have implemented in C# so far is done, and this should be a HUGE help on implementing clients and servers in other languages. Unfortunately, I do realize I'm running way behind on the tier rewards. Like, so far behind they haven't even happened yet. I'm also assuming most donors are going to be interested in Buttplug once it's released too though, so I'm just counting on that. If you REALLY want your tier reward, feel free to poke me and we can figure something out. :) --- ## Artifact Builds of Buttplug C# for Win10 Now Available I have set up the Appveyor CI to output ButtplugGUI installers on every build I make now.  If you go to[https://ci.appveyor.com/project/qdot/buttplug-csharp](https://ci.appveyor.com/project/qdot/buttplug-csharp) and click on one of the build configurations, then click on the "Artifacts", you can download installers from each build. Note that these installers may not actually /work/. Just because all of the tests passed and the installer was built does not mean this is a functioning product. I just spent an hour trying to figure out why builds failed silently after install due to fucking up assembly version number insertion, so I've still got a lot to do on the QA side here. Also, there is currently no documentation for Buttplug other than the code itself. There's not even really comments in the code at the moment. Not my finest hour in terms of documentation, but I've fallen down on a lot of my normal habits (tdd, comments, etc) just 'cause it's been nice to actually get this out of my head. I'll be sweeping back through to comment at some point. So, here's a few tips about it at least: - Right now builds support the Fleshlight Launch, Lovense Hush, and XInput gamepads (xbox gamepads). The builds will detect Kiiroo Onyx/Pearl toys but something is wrong with how I talk to their serial chips so the connection is very iffy. - The "Device" Tab: Here you can trigger device scanning (instantaneous for gamepads, bluetooth might take a bit), and see what devices it finds. When Buttplug finds a device, it connects with it and will stay connected until the program ends, the device turns off, or something throws an exception that I missed that frees the device somehow. The number shown at the front of the name is the "Device Index". This is important for later. - The "Applications" tab: Turning the "Websocket" Application on will make Buttplug a (unsecured) websocket server, able to talk to other applications via a JSON protocol. This hasn't been tested in a while and may not be working. The "Kiiroo Platform Emulator" application turns on a webserver that receives HTTP requests from applications that expect to talk to the Kiiroo Onyx, like [http://flickr.tv](http://flickr.tv) movies and VirtualRealPlayer. The device list shown here is devices you can select to control with the commands the server receives. Currently, only the Fleshlight Launch works for this, and it's just using the FeelConnect protocol, so don't expect much. Note that, outside of closing and reopening the application, there's currently no way to turn off the http server once you turn it on because the library I'm using doesn't seem to have that working.  - The "Log" tab: Shows the current log messages coming from Buttplug. If you have repeatable, non-crashing problems and need to send me documentation, this is where that'll happen. You can save logs I can use to remotely debug things to a file and poke me on here, or just email me if you've got my address. - The "About tab: Just shows version info, links (yes I know the documentation link is a 404 :p ), and begs for cash. I'm keeping the bug list on github as up to date as I can, so as issues disappear from there, they'll show up in these artifact builds. [http://github.com/buttplug-csharp/issues](http://github.com/buttplug-csharp/issues) The current path to v0.0.1 involves: - Writing more tests - Figuring out how to test the installer on appveyor so we don't have bogus builds - Moving logging and some other stuff to dependency injection - Figuring out NuGet for library distro - Writing basic application documentation - Starting on the "Big Book Of Buttplug", the developer documentation for the library/protocol/architecture/whatever the hell it is I've done here As for platform support, this currently will not run at all on Windows 7, most likely because I'm hard linking against UWP metadata that requires at least some version of Windows 10. I've got a Win7 VM with visual studio up now, and I'm going to see about adding a Win7 version of the project that gets rid of that. It'll be missing all of the bluetooth parts for now, but at least gamepads will work. Tracking of that work is at [https://github.com/metafetish/buttplug-csharp/issues/40](https://github.com/metafetish/buttplug-csharp/issues/40) Ok. Back to work. --- ## State Of The Buttplugs 2017 05 22 First off, Hello new patrons! Thanks for the donations! They will be used for new buttplugage assuming I don't die from burnout soon.Now then, moving on... Remember when I thought programming applications for sex toys would actually involve programming sex toy stuff? Yeah I'm an idiot. The past week has mostly been lost to learning the ins and outs of window dependency conflicts. Luckily most of that is now over, and I've come out of the ordeal with: - A nifty new crash reporting system - Binaries that work on Win7/8/10 at the same time - Significantly smaller executables (but not quite to my dream of having a 64k buttplug demo yet) and simpler code While stability and better structured code are great, that hasn't pushed Buttplug forward much in terms of features. I'm now trying to get back to building sex toy interaction features rather then endlessly kit out the CI for these applications. The installers from appveyor ([https://ci.appveyor.com/project/qdot/buttplug-csharp,](https://ci.appveyor.com/project/qdot/buttplug-csharp,) click on either Release or Debug, click on Artifacts) should now work on Win 7/8/10 without crashing on startup, but will only bring up bluetooth on Windows 10 15063 or later. Other platforms can currently only use XBox Gamepad vibration, though I don't have a Kiiroo output for that quite yet so that only works via Websockets. As mentioned in the post last week, there's a Kiiroo Platform Emulator and a Websocket server in there, both seem to work right now, though there's no documentation for the JSON protocol yet. My goal for the next few days is to build a fairly minimal javascript client library, wire that into some of the old test WebBluetooth programs I made (so they'll now work on all platforms), then document things enough to make some vague sort of sense and release v0.0.1. Hoping to get there in the next couple of weeks, but I originally said this would be an "over the weekend" project 5 weeks ago so yeah. Right now I'm using github issues as my todo list: [https://github.com/metafetish/buttplug-csharp/issues](https://github.com/metafetish/buttplug-csharp/issues) I'll probably be making a trello board once things calm down some, so we can start planning new features across versions. I'll make another post when that happens. Thanks to everyone for your support so far. Hope this turns out usable. :) --- ## Buttplugin Away After taking a break this past long weekend (helped immensely with some of the twinges of burnout I was getting), I'm back at it on trying to get a minimal application working for Buttplug using C# and Typescript. I just posted a full update on Metafetish at[https://www.metafetish.com/2017/05/31/metafetish-dev-log--week-of-20170529/](https://www.metafetish.com/2017/05/31/metafetish-dev-log--week-of-20170529/)  Still getting lots of contact about the project from random places, the scattered interest is nice. Just hoping I haven't overhyped a bit with how long implementation is taking. Back to poking at vue.js... --- ## Metafetish Now Has Discourse Forums [https://metafetish.club](https://metafetish.club)Just in case the slack, the blog, and the patreon updates weren't enough for you, now we have a Discourse instance! I'll be using this as the forum installation for Metafetish, and probably wiring blog post comments to it at some point too. --- ## New Episode Of Buttplugin With Qdot Buttplug Software Alpha Demo Episode 1 production time: 3 weeksEpisode 2 production time: 2 hours After getting support for translating Kiiroo commands to Gamepads, figured I'd finally post a demo of what the current state of Buttplug looks like. The good news is, I've also had a couple of outside testers who've managed to get it working with both gamepads and the Fleshlight Launch! This is starting to look like it may be releasable. :D I need to nail down a few more things on the programming side, then there's a TON of documentation to write. In the video I say release in the next couple of weeks to keep things conservative, but as you know from being patrons, artifacts builds are available on appveyor, and they tend to stay fairly stable now (though my test coverage is plummeting at the moment :( ). Thanks for supporting the project! --- ## Who Wants To Help Review The Buttplug Protocol Spec [https://metafetish.club/t/buttplug-standard-document-review-thread/31](https://metafetish.club/t/buttplug-standard-document-review-thread/31)I just finished writing the first draft of the Buttplug Protocol Spec. This is the message board thread for the refinement conversation.  If you're the kind of person that enjoys systems planning work, please take a look at it and lemme know on the message board thread if you have any suggestions, if anything is missing, etc... If you don't know whether you enjoy systems planning work but always wondered what sort of exciting documents engineers get to write, print this out and read it before bed. It should put you right out. :) --- ## This Is The Buttplug That Never Ends It Just Goes On And On My Friiiiends We're now 8 weeks out from the first commit in the buttplug-csharp repo. Someday we'll get to a release. Someday. Since the last update: - We now have 2 developers working on Buttplug, soon to be 3! - We have support for all Lovense toys minus the Ambi (I don't have one yet and need to know the bluetooth name/services on it). This includes the new Edge prostate massager, 'cause I got mine yesterday and got support in within 3 hours of receiving it. :) - As of the end of last week, Launch control is now FAR faster and more stable. We were waiting too long for some bluetooth calls, that's now cleaned up. It should stutter less on video sync with fast moment. - We now have Code of Conduct and Contributor documents in the repos, in the hopes of making the project a little more welcoming. - Fixed a few crashing bugs. I'm working now to try and figure out a path to a first release. Some of the major blockers on that are: - Fix up crash reporting - Create update notification system - Run websockets over SSL (maybe) - Start Application Design Guidelines document (doesn't need to be finished by the time we release, just needs to have a couple of chapter drafts up somewhere) - Update website - Maybe comment some code somewhere. Maybe. So yeah, lots of both technical and documentation/presentation stuff, none of it all that exciting.  The trudging continues. --- ## New Patreon Tier Images Thanks to Astolpho ([http://patreon.com/dawnchapel),](http://patreon.com/dawnchapel),) I now have awesome tier images for my Patreon page and videos! --- ## Buttplug Development Update Funny how a month can fly by without noticing. I just made a quick update on metafetish about the current state of the buttplug repos, after realizing I didn't post anything at all during June. [https://www.metafetish.com/2017/07/05/metafetish-dev-log--week-of-20170703/](https://www.metafetish.com/2017/07/05/metafetish-dev-log--week-of-20170703/) Now for the more in-depth version: I was out most of last week with a dayjob travel. Was hoping to get a lot of documentation done but ended up too tired. :/ Work is continuing on Buttplug, and I think we're close to release #1, but we're definitely hitting the 80/20 rule hard now. Did some bug/feature triage to try to get us to a minimal release. The major worry now is that we'll release software that no one has any idea how to use, but since we're also not sure of our target demographics yet, we may just have to release and let the reaction guide us from there. Our movie player, syncydink, can now play movies and load haptics files. I'm working on getting that hooked up devices communication, and this may give us what we need to at least have something usable with our first release, though the UI may be rather spartan as I'm still figuring out this whole frontend development thing. Also looking at building some simple control components just so people can make sure things are up and running ok before trying something like movie sync. This would possibly include the "random" controls that have been asked for constantly for toys like the Launch. That's where things are at the moment. Back to work. Thanks for your continued support, and feel free to poke me if you want more updates. I've been lagging on them. --- ## Checking In Hey everyone! So I just learned that Patreon has exit surveys for patrons leaving your campaign. Last month, a couple of people left citing "The creator wasn't engaging like I expected.". Unfortunately there weren't any feedback comments so I'm not quite sure what it was they expected.Just wanted to let you know that if there's some sort of engagement you are expecting (like, say, the shit I put on my patron tiers :| ), do let me know. The production of the first version of the Buttplug software and Syncydink player has turned into... well, software production, thus meaning 2x-3x estimated time, and I did build the patreon on the idea of videos that are currently delayed due to that.  Since you're giving me money, if there's something you'd like to see, poke me and tell me. :) And speaking of things to see: SyncyDink controlled a fleshlight launch via Buttplug on windows for the first time last night! We now have a full MVP technology stack for v0.1. We'll be cleaning that up this weekend, and I'll hopefully have a post here on how to give it a shot pretty soon. --- ## A Launch Player While You Wait For Syncydink Around the time I started Buttplug, I met up with someone on the Milovana web tease forums, where a good chunk of the anime Cock Hero community hangs out. They were working on a C# based movie player with Launch support, mostly focused on the Cock Hero community.They ended up putting out their first beta release last week: [https://milovana.com/forum/viewtopic.php?f=25&t=19817&sid=a1be9f1e4a820781c42bfbb8d0e160c3&start=30](https://milovana.com/forum/viewtopic.php?f=25&t=19817&sid=a1be9f1e4a820781c42bfbb8d0e160c3&start=30)#p236911 That post lists the github release page and scripts repo. I recommend reading the rest of the thread as there's some information on how to use it, as well as some interesting comments. The player is open source and on github, so if you feel like it you can build it in VS2017 and get the latest patches that way. While this version of ScriptPlayer does list Buttplug support, ignore that, as the current beta doesn't work with our current builds (our patches to fix that are landed in ScriptPlayer, but they haven't built a new release yet). We're of course still working on our own web-based movie player, but we're working with this developer to make sure Buttplug support stays up to date. This video player has also been a massive help in QA for Buttplug C# libraries. :D --- ## Buttplug Syncydink Preview 1 Ok so I said I'd have it done by the end of the weekend and I did!I just finished a test of Buttplug (on windows 10) + Syncydink (on iPhone!), and it's working rather well, even over WiFi, and at this point, the UI is ok enough that I think people can try it out. First, some caveats: - This only works with funscript files so far. We can parse like 6 different haptic movie types, but I haven't built translators for those to toys yet. - This only works with the Fleshlight Launch. See prior issue of needing to build more message translators. Going to try to get vibration done tomorrow and will send an update then, at which point it should work with all Lovense toys and XInput gamepads also. Other than that, Buttplug should run on Windows 10 15063, and Syncydink needs to run on a decently modern browser. I've tested it on Firefox 54-56, Chrome 59 (desktop/android), Safari (macOS and iOS 10.3), and MS Edge (40.1.15063). Funscript haptics files are available at: [https://github.com/FredTungsten/ScriptPlayer/tree/master/Scripts](https://github.com/FredTungsten/ScriptPlayer/tree/master/Scripts) You can usually download a script, then search for the name on Pornhub and find the corresponding video. I used the "Pendulum (No Host)" file for testing. I realize Cock Hero might not really be everyone's deal, but that community is contributing scripts right now so it's a good test base at least. Instructions:  1. Download Buttplug Server, Version 0.0.0.404: [https://ci.appveyor.com/api/buildjobs/rewqfwljlvs9mfe7/artifacts/Buttplug-Release-0.0.0.404-installer.exe](https://ci.appveyor.com/api/buildjobs/rewqfwljlvs9mfe7/artifacts/Buttplug-Release-0.0.0.404-installer.exe) 2. Install it 3. Run Buttplug Websocket Server.  4. Go to [http://buttplug.world/syncydink.](http://buttplug.world/syncydink.) This may take a minute, as the javascript file is 2.3mb (MODERN WEB TECHNOLOGIES! \o/ Though seriously if any of you are webpack experienced and understand the following sentence please let me know: we need to code split to get to smaller sizes 'cause we can't uglify our client module, and I haven't had time to figure it out how. We should be able to get down close to 200k.) 5. Open sidenav by either right swipe or clicking on the purple hamburger in the upper left corner 6. Choose a movie 7. Choose the corresponding haptics file 8. Change to "Buttplug" tab, change address to whatever it needs to be, hit connect 9. Hit "Start Scanning". Note that buttplug will find all capable devices, but only the fleshlight launch will work with this demo. 10. Once the fleshlight is listed, you're ready to hit play on the video, and synchronization should start. For getting syncydink running on a phone, I used dropbox to get the files over. They're pretty big though, so there may be better options. The best experience will be had by just running on localhost on a windows box for right now. Let me know in the comments or in a patreon message or in email or twitter or whatever if you have any problems. --- ## Buttplug Scriptplayer Updates First off, there's now a new version of ScriptPlayer up, with more expansive Buttplug support. [https://github.com/FredTungsten/ScriptPlayer/releases](https://github.com/FredTungsten/ScriptPlayer/releases) SyncyDink is coming along nicely. We're still trailing behind ScriptPlayer on features, though we do support many more platforms. Syncydink now has support for the Launch and all toys that support Vibration (at this point, Lovense, Vibratissimo, XBox Gamepads). The latest working version of SyncyDink is always at [http://buttplug.world/syncydink](http://buttplug.world/syncydink) In terms of the first "official" release of Buttplug, we're down to days rather than weeks. The C# server/client is basically done, we're shoring up the Javascript client libraries, and making sure Syncydink is stable. The plan is to do our first release quietly, then work on growing our presence around it in a piecemeal way. Otherwise, the whole ordeal of website updates/video making/tutorials/etc would push the release out another 2-3 weeks. We'd rather have users that know what they're doing already using the software while we build these things, so we can field their questions and add those questions to the content. :) --- ## More Buttplug Fox Images Stickers So I know everyone is all thinking "Hey qDot, instead of actually finishing software, why don't you just get some more stickers made."Well, you thought, I delivered. Thanks to [http://twitter.com/rootsworks](http://twitter.com/rootsworks) for making this happen. For those of you on Telegram: [https://telegram.me/addstickers/buttplugs](https://telegram.me/addstickers/buttplugs) --- ## Qa For Real This Time Hello $3+ patrons! So way back when I started this Patreon, I said I was gonna do Q&A videos, answering questions for people that paid $3 or more a month. So far I have done zero of those. But that ends now! Maybe.I'm hoping to spend more time writing/filming than coding this month, and part of that is restarting the Q&A thing. If you've got questions you'd like answered, lemme know! I've got like 3 questions backed up from my first try at this, so definitely need to add more to that list. --- ## Buttplug C 010 Released Finally gave up polishing. Ship it.[https://github.com/metafetish/buttplug-csharp/releases/tag/0.1.0](https://github.com/metafetish/buttplug-csharp/releases/tag/0.1.0) This will most likely be the only place I announce this release, as I'm now going to be spending the next while building documentation and tutorials around it. Otherwise no one will have a clue how this is supposed to work. Most of my testing with Buttplug has been on syncydink, which is now in rolling release at [http://buttplug.world/syncydink](http://buttplug.world/syncydink) As of tonight, syncydink can play either 2d or 180SBS VR movies.  - For 2D, pretty much anything works. Even phones. - For VR, you'll need Firefox 55 or higher. Chromium VR won't work yet as it doesn't have a mp4 decoder in it. This MAY work on mobile chrome but I haven't tried it (don't have hardware to do so). In terms of file formats, we now support: - Funscript - VirtualRealPlayer - Kiiroo (flicker.tv) - Feelme These movie files will turn into either Fleshlight Launch or SingleMotorVibrate (Gamepad, Lovense) commands. I may add support for Vorze movie files and hardware pretty soon too. I realize there's not a lot of information around on how to get all of this working together, and that's what I'm planning on spending the rest of the week working on. I just figured I'd let everyone here know first since you're, you know, paying me. Thanks for supporting me through this first development push. I'm hoping things from here on out will happen in more of a rolling manner, so it's not just 3 months of "one more week". --- ## Buttplug C Syncydink Tutorials I've written up some quick tutorials to give an overview of what's currently available in Buttplug C# 0.1.0 and Syncydink.Buttplug C# 0.1.0: [https://metafetish.club/t/buttplug-c-0-1-0-tutorial/80](https://metafetish.club/t/buttplug-c-0-1-0-tutorial/80) Syncydink: [https://metafetish.club/t/syncydink-tutorial/82](https://metafetish.club/t/syncydink-tutorial/82) Work is happening now on the Javascript server, which will expand Buttplug bluetooth LE support to Mac/Linux/Android/ChromeOS, meaning Syncydink will also be able to control toys on those platforms. --- ## Buttplug Js Aka We Now Support Mac Linux Android Chromeos As of yesterday, I managed to get the javascript web technologies version of the Buttplug Server done. This is now integrated into Syncydink:[https://buttplug.world/syncydink](https://buttplug.world/syncydink) If you go to the site now in Chrome (and yes this requires chrome, for WebBluetooth, and you will need to use https), then go to the Buttplug tab and click on "connect local", the "Start scanning" button now triggers a search for devices. Currently, we support: - MacOS/Android: Fleshlight Launch, all Lovense toys - Linux: Some Lovense toys - ChromeOS: Haven't tested Yes, there's a problem with Linux and the Launch (and apparently the Lovense Hush but not the Edge?!). We can connect to the launch via WebBluetooth, but it can't actually establish communications. We figure this is a Chrome bug (we've successfully controlled the launch with gatttool), and will be following up on that with the Chrome WebBluetooth team. Also, this list doesn't have Gamepads in it for any platform, because gamepad vibration on web browsers is an extremely new thing, implemented as part of the Gamepad Extensions spec for WebVR. While rumble is implemented for VR controllers, it has yet to be extended to gamepads in any browser that I am aware of. Either way, we'll still try to support touch rumble with this soon. # Next Steps Here's our plans for the next while if not more: - Add more toy coverage to buttplug-js and buttplug-csharp We recently added TranceVibrator and WeVibe support, and OhMiBod should be on the way shortly. Starting to look toward things like the SayberX, as well as backward toward things like the RealTouch. - Videos! Seriously! So to everyone who started donating to this patreon because I was gonna make videos, don't fret! I'm gonna make some more! We've now just got miles and miles of topics to cover since I have a solid software base to work from. Buttplug is to my videos as MIX/MMIX is to Art of Computer Programming, as it were. :) - Documentation. Any at all. We documented the protocol but so far that is it. We have a LOT more documentation we need to write in order to make this huge pile of code easier for others. - Start adding ui/ux features to syncydink Syncydink right now is a bare minimum haptic movie player. There's no chapters, no looping, no bookmarking. We've got a lot of work ahead of us to make it an ideal viewing system - Working with new partners Thanks to the Vice article as well as community outreach, we're starting to get interest from possible partners. As things solidify in this department I'll post about them here. - Ramping up media/attention We're almost done with the checklist I made for myself of "things to do before I can really start pushing this hard in public". We've got a few small things left, but once those are done, we'll probably be trying to drum up more coverage and interest. - buttplug-node and buttplug-rust In terms of server implementations, we can now expand buttplug-js to also support Node.js bluetooth. This would detach us from requiring the browser on mac and linux, and could also possibly work on windows for people that want to work in JS instead of C#. I'm still dedicated to a Rust client/server pair because damnit I want to write more rust, and we've had a ton of interest in that community. It's just a fun language to work in. We've got a large hill to climb there though, as there's a lot of library code (usb/bluetooth support etc) to write. - Tutorials Now that buttplug-js is technically runnable from a browser, depending on your platform, we're hoping to build some tutorials on glitch.com. This will allow people to quickly and easily remix on top of the buttplug-js node module to make their own webapps. # Closing Thanks again to everyone who has stuck with me through this somewhat quiet development period. I'm really hoping that we're going to have more to show that the base software is usable. As always, if you have any questions, feel free to contact me via the comments here, or on twitter at [https://twitter.com/qdot,](https://twitter.com/qdot,) or by email at kyle@machul.is. --- ## Vice Motherboard On Buttplug We're in Vice![https://motherboard.vice.com/en_us/article/433w8d/heres-why-we-need-more-open-source-software-for-buttplugs](https://motherboard.vice.com/en_us/article/433w8d/heres-why-we-need-more-open-source-software-for-buttplugs) This article is a great overview of our goals with [https://buttplug.io!](https://buttplug.io!) --- ## Syncydink Vr Works On Android Chrome I've just updated the Syncydink tutorial, because thanks to some nudging from a new patreon on here, I just finished some fixes and we now work on Android Chrome with VR and no extra software/apps required![https://metafetish.club/t/tutorial-syncydink-v20170821/82](https://metafetish.club/t/tutorial-syncydink-v20170821/82) Basic steps: - Put movie files and haptics files on your phone somehow. I also recommend having a file explorer app like AndExplorer (free version is fine) handy so you can actually select the files in the syncydink interface - Go to [https://buttplug.world/syncydink](https://buttplug.world/syncydink) - Open your movie/haptics files in the player - In the Buttplug tab, hit "Connect Local", then scan for and choose your devices - Put the phone in VR mode, put it on your head, have fun! One of the major things missing right now is any way to actually control a video while it's in VR. So, uh, beware that just because you're finished doesn't mean your phone or hardware might think you are. We're trying to figure out a good solution for this, but I currently don't have an android phone capable of VR (I'm working on a Nexus 7 which at least basically does the job) so it may be a bit before we get this worked out. Let me know if you have any issues or feature requests. I'm gonna try to get parity between Windows and JS for bluetooth toys next, as well as starting on more doucmentation for all of this stuff. --- ## Buttplug Game Vibration Router A couple of weekends ago, I got the stupid idea of "Hey. Rez Infinite came out. Wouldn't it be funny if I could make it work with the original USB Rez Trancevibrator?"48 hours and a lot of education about DLL Hooking later, it was done. We now have a way to control sex toys via Gamepad vibration command on Windows, with no modifications required to the game in question. This works with any game that supports XInput (XBox Compatible) gamepads, and I'll be extending it to work with vibration commands to Oculus/Vive controllers soon. Also, this currently only works with toys that vibrate, as that's all I've had time to implement. This certainly can work with the Launch, Vorze, and other toys, I just need to sit down and figure out the translation algorithms to do so.  I've now run it by a couple of testers, and it seems to work, so I'm releasing it only to Patreon members first. I'm planning on making a Buttplugin' With qDot video about this and releasing it to the general public next week, but figured it might be fun to have more people trying it with games first. For those interested in the technical explanation: The basic idea here is similar to something like x360ce ([http://www.x360ce.com/).](http://www.x360ce.com/).) x360ce allows players to use joysticks/gamepads/other controllers for any game that will take an XInput gamepad.  It does this by "hooking" the DLL, which means injecting code into the process and intercepting/rerouting calls to library functions that relate to controller input and output. I used the same methodology here, except that my case is much simpler, since I'm just looking at commands that make the controller vibrate and then passing them on to the controller while also sending them to Buttplug. The package I used  for this is called "EasyHook", and the name is completely honest advertising. It's crazy how easy this was.  [https://github.com/EasyHook/EasyHook/](https://github.com/EasyHook/EasyHook/) To get the Game Vibration Router app (or as it's currently called the XInput Injector, which will be changing sono), you'll currently need to switch to running on a CI build of the Buttplug Application Suite. The latest version is the only working one, so you'll want anyhing >= 0.1.0.447. [https://ci.appveyor.com/api/buildjobs/cvyusr3kxu0pyd5a/artifacts/Buttplug-Release-0.1.0.447-installer.exe](https://ci.appveyor.com/api/buildjobs/cvyusr3kxu0pyd5a/artifacts/Buttplug-Release-0.1.0.447-installer.exe) As usual, this requires Win 10 15063 if you want bluetooth toys, otherwise you can use it if you want to play the game with one gamepad while using another for whatever you need vibration for.  I've conferred with some people from the game anti-cheat industry, and they've said that this hook should NOT trigger anti-cheat mechanisms in games (at least for VAC/EAC). That said, be careful with it in online situations, as explaining this to customer support might be awkward. :) I've set up a thread on the message boards for reporting game compatibility: [https://metafetish.club/t/game-vibration-router-compatibility-thread/105](https://metafetish.club/t/game-vibration-router-compatibility-thread/105)  If you try this out on something not on the list, lemme know (either by signing up for the forums and commenting, or feel free to DM me on twitter or email me at kyle@machul.is if you want privacy), and I'll add it to the list. Have fun! --- ## Metafetish Dev Log Week Of 2017 08 28 Just posted a new Dev Log on the blog! Now that we've got releases out, going to try to get back into a better writing cadence so we're not developing in a black hole.Right now, we're in the middle of the black hole, try to develop *out *of it. Buttplug was in development for so long and has so little documentation that it's hard for users to figure out what to use where, and what works on what platforms. This became very evident when I posted about syncydink on a couple of forums over the weekend and was met with a lot of either silence or "???" in response. I'm going to be spending the next while trying to fix that somehow. This may end up in me begging for tech writing help on twitter. :) --- ## And Now We Have A Discord Server Too Yes ok I may have a slight chat protocol hoarding problem.Invite Link: [https://discord.gg/BGNjpbf](https://discord.gg/BGNjpbf) For Patrons: If you join the discord and would like to have the special Patron role, just message me and I'll get that set up. I've been doing a lot of support for video encoding lately, and a lot of contact for that has been through skype and discord. I figured I'd set up yet another chat outpost on Discord, hoping the people I've been helping there can help each other too. This means we now have: - Discourse Message Boards at [http://metafetish.club](http://metafetish.club) - Slack Instance (mostly developers/tech/engineering) at [https://metafetish.slack.com,](https://metafetish.slack.com,) message me for an Invite - Discord at [https://discord.gg/BGNjpbf,](https://discord.gg/BGNjpbf,) just come on in - Unofficial Telegram that I'm not actually in but has been surprisingly on topic lately (people doing 3d printing and small electronics builds for sex toys) at [http://telegram.me/metafetish](http://telegram.me/metafetish) Not an ideal situation in terms of information fragmentation, but it is what it is. I'm not super keen on trying to tie all of these together (that was kind of a mess on slack/telegram), but if enough people whine I'll think about it. --- ## Support For New Lovense Hush Toys Just a heads up since Lovense Hush toys seem to be pretty popular.We had a user show up on the Discord today reporting a Hush toy that would not connect to the Windows Buttplug App Suite. They had direct ordered it and received it sometime last week (last week of August 2017).  Turns out that Lovense is loading new firmware onto toys, and also changing their device names and service IDs. We've updated the Windows Buttplug Server for this new device, and CI Builds of 0.1.0.464 or later should work. I'm hoping to get support into buttplug-js this evening. We're now also looking at more flexible ways to define and add hardware to Buttplug across all platforms, that will hopefully make problems like this easier to remedy. More information on that as we figure out how we're gonna do it. --- ## Metafetish Dev Log For The Week Of 2018 09 05 New dev log post. Nothing too exciting since I usually post most of this kinda of info to patreon for patrons in real time, but hopefully helpful![https://www.metafetish.com/2017/09/05/metafetish-dev-log--week-of-20170905/](https://www.metafetish.com/2017/09/05/metafetish-dev-log--week-of-20170905/) --- ## The End Of Fleshlight Launch Firmware Bricking Took a bit of a diversion from buttplug/syncydink over the past few days.Having finally gotten sick of reading all of the reports of people having their Fleshlight Launch bricked by firmware updates, I spent the weekend writing my own firmware loader. I now have a node.js/typescript based loader that can load Launch firmware (and as soon as I get one, Pearl 2 firmware) from desktops. I'll be porting this to work in Chrome, so that we can hopefully fix firmware loading from Android, which is usually where problems crop up. I'll be writing a full blog post about the internals of firmware loading, but that may be a bit. Some fun facts I learned along the way: - Firmware load bricking happens because there's very little in the way of failure tolerance and redundancy in FeelConnect. If something goes wrong, there's not much in the way of retries. Not only that, with the current v1.3.12 of the app, the firmware may load fine, but the final step of "mode locking" may fail because of a bad reconnect. We've been discussing this on the message boards: [https://metafetish.club/t/launch-firmware-update-problem/117/10](https://metafetish.club/t/launch-firmware-update-problem/117/10) - All of the byte operations in FeelConnect happens as string operations. No, really. They actually do string concats and splits for leading zeros when doing nibble operations.  It's sick (in the bad way). My typescript version is all node.js Buffers or ES6 Uint8Arrays, which admittedly still feels weird over, say, uint8_t[].  - There's a lot of trust of the bluetooth stack in FeelConnect, leading me to believe it may be developed on iPhone more than Android. Android bluetooth straight up lies to you constantly, and this is where the firmware bricking issue comes in. FeelConnect sends a lot of data over without checking whether it was written correctly, trusting that the phone will give the application correct write responses (it won't, and even if it does that's not a good signal for the write being completey done yet). When things do fail, there's no retries. - There's no firmware signing. The CRC check happens on the host, not the machine itself. My Launch is currently running firmware version v6.9 because I can just change the firmware version and line CRC for the intel hex file, and there doesn't seem to be any internal verification of the loaded firmware. This bodes well for us writing our own firmware for Kiiroo toys. An added bonus of this is that it gets us close to being completely free of FeelConnect. We'll still need a way to load firmware over Windows and iOS, but now that we know how, it's mostly a problem of actually getting it implemented. All of this is up on github at [https://github.com/metafetish/miiyoo-firmware-utils.](https://github.com/metafetish/miiyoo-firmware-utils.) I'll be prettying it up, hooking it up to WebBluetooth, and creating a firmware fixing utility on buttplug.world soon. --- ## Fleshlight Launch Running The Firmware Version It Shouldve Been Running All --- ## Google Chrome 61 On Linux Now Works With Fleshlight Launch Lovense Hush Plug I just updated to Chrome 61 on my Debian box, and whatever bug was holding up bluetooth usage on Chrome on Linux is fixed! The Fleshlight Launch now works fine with syncydink in local connect mode! Also tested the Lovense Hush Plug, it works too. I think this puts Linux Chrome in feature parity with macOS and Android for buttplug-js --- ## September Qa It's time for this month's Q&A post! I keep saying these are going to be videos, but has yet to happen, so this month I think I'll be a bit more realistic and just say post your questions about Metafetish/Buttplug/Me/Whatever in the comments to this post and I'll answer here like I normally do. :) --- ## Buttplug C V011 Released Buttplug C# 0.1.1 is out! Get it at[https://github.com/metafetish/buttplug-csharp/releases/tag/0.1.1](https://github.com/metafetish/buttplug-csharp/releases/tag/0.1.1) # Features - Added auto update and update checking functionality - Added support for the following hardware: WeVibe 4 Plus, Ditto, Nova, Pivot, Wish, Verge, Lovense Domi - Added more product names for the Lovense Hush (LVS-Z36, LVS_Z001) - Added Game Vibration Router application - WebsocketServer now defaults to SSL # Bugfixes - Fixed hang when no XBox controllers and no Bluetooth adapters are connected - SSL Errors in Websocket Server are now shown in GUI or as a notification, not in modal dialogs - Fixed ObjectDisposed Exception in Kiiroo App - Fixed port number changing in Websocket Server - Fixed crash when copying IP addresses in Websocket Server - Fixed version number listing in logs - Vibratissimo devices now required to be named "Vibratissimo" On to v0.1.2 or v0.2.0 or whatever we decide the next version is! --- ## Buttplug C V012 Released Our first emergency bugfix! Found an issue in the updater right after I released v0.1.1, fixed that and pushed out v0.1.2 shortly afterward last night. According to logs, only 5 people downloaded v0.1.1 before that, so if you're one of those 5, you should update to v0.1.2. :) --- ## Buttplug Playground Aka The Launch Manual Control App Everyone Wanted [https://buttplug.world/playground](https://buttplug.world/playground)So far, all of the applications for Buttplug has been about outside media. Movies, games, etc...  Decided to go more minimal and just make a web app for testing toys and basic "manual" control. It's called Playground. The Buttplug connection interface is the same one Syncydink uses. However, this time, instead of video sync, when you select devices to use a control system pops up.  For vibration, there's a slider to set speed.  For the Launch, there's a range slider to set the oscillation range, and a speed slider. You can then make the launch oscillate between the two chosen positions at the selected speed. You can also change positions/speed while it's oscillating. So, basically, it's what everyone has been asking for since April. :| If there's any other features you'd like to see, like patterns, random, settings, etc, lemme know. I'd like to keep things fairly simple up front since this will most likely be our new entry point for people new to Buttplug, but I can always add "advanced controls" or something and provide UI to choose. I'll be making a Websocket Server tutorial video using this next, so if things are confusing, let me know and I'll try to either improve the interface or talk about it in the video. --- ## October Qa It's time for this month's Q&A! If you've got any questions for me about Metafetish, Buttplug, Sex Tech, Me, The Universe, etc..., post them in the comments to this post.(General project status post coming later this evening) --- ## Buttplug Update Ok, time to make an "I'm not dead" update.I'm not dead. There's lots of work happening on Buttplug right now, but most of it is fairly invisible. I've been spending lots of time learning about how to properly build web app dependencies so developers can start using the same components I used to make Syncydink and Playground. This has taken more time than planned (was a rather complex learning process to get typescript/vue.js/webpack to all play together nicely), but is finally done. The hope here is that people that want to write new webapps for buttplug can do so quickly and easily with these components. BTW, if anyone is experienced with React/Angular/other frontend frameworks and is interested in helping build a similar component set for those, please let me know. Playground is now complete as a minimum viable product. It allows users to test vibrating toys, the Fleshlight Launch, and the Vorze A10 Cyclone. This means I can now start making user documentation built around it, to introduce people to the current Buttplug workflow. Really hoping this relieves some of our support load once finished. On the protocol side of things, we're starting work on handling getting input from devices (accelerometers/buttons/sensors/etc), as well as the inevitable "downgrading" situation, which refers to using new clients with old servers and vice versa. Getting all of this done soon should hopefully future-proof us for a while to come, at which point we can get back to doing fun stuff like movie player integration and game engine plugins. I'll be spending the rest of this week preparing and filming new tutorials, as well as playing with some interactive documentation/tutorial systems to see if those work better that videos. I may also try to slide a haptics-file-only player into Syncydink, as we're getting requests for that now and I'd rather not block it on the whole haptics editor system getting done. As always, if you have any questions/requests/etc, feel free to messages me here or ask in the comments. Thanks for your continued patronage, and I look forward to making slightly more exciting updates soon. --- ## Standalone Haptic Playback And Toy Simulator In Syncydink In lieu of video recording, I guess my brain decided it wasn't done futzing with web programming. I ended up making improvements to the syncydink haptics timeline viewer, and added a toy simulator with graphics by funjack (of golaunch/launchcontrol/funscript fame). Now you can see how a toy will react to a video or haptic script, even if you don't have the toy handy!Also, if you just want to play a script without a movie, that's doable. If you load a haptic script, then choose "Show timeline", there's now a play/pause button on the bottom of the timeline bar. This will play the script without needing a movie loaded. If you /do/ have a movie loaded, the playhead in the haptic timeline can now control movie position, and vice versa. The other buttons there are for looping, and locking the timeline. Unlocking the timeline will let you edit/add/remove points, which will be part of the upcoming encoding feature. Right now, it's mostly for show. --- ## Buttpluggin With Qdot Windows Websocket Server Tutorial SEE I TOLD YOU I'D GET BACK TO MAKING VIDEOS.Even if they are pretty spectacularly boring. This is a quick (well it still took me like 6-7 hours between scripts, editing, etc :| ) video showing how to use the Websocket server. We've got a lot of UI needs to clean up, but we're having to operate on so many fronts right now that prioritization is difficult, so instead I'm just making videos to act as a patch until our UX sucks less. I'll be working on another one of these for the Game Vibration Router next, then a quick overview of WebBluetooth usage for non-windows platforms, then a syncydink tutorial (I realize this sounds like a lot but these are all screencasts, which take WAY less time to film), then hopefully back to fun teardown and informational vids. --- ## Survey What Would You Like To Improve On Current Software While filming the Buttplug Websocket tutorial, I realized how painful it is to do the first SSL setup in the websocket server. On top of that, we're still not signaling to users what toys actually work with their setup.These are things I get lots of questions about, yet we haven't really been addressing those questions lately. I'm trying to do some development planning right now, and I'd like some feedback on what'd you'd like to see improved if you use Buttplug/Syncydink/ScriptPlayer/etc..., or if you can't, why not. For  example, here's some things I'm aware of (if you're having problems  with things in this list, please still comment here and let me know,  just so I can get some basic numbers together): - Lack of Windows 7 Support - Not enough feedback on which toys work, when, and why - Secure socket setup for websocket server doesn't give enough feedback - No available list of applications that can be used with Buttplug We're looking for everything from the biggest issues to the smallest nits, so let us know what you think! --- ## Update On Windows 7 Support Ok, the survey has only been up a day, but the Windows 7 community has definitely been vocal. :)I've created a github issue for possible Windows 7 Support options at [https://github.com/metafetish/buttplug/issues/40](https://github.com/metafetish/buttplug/issues/40) This outlines 3 different solutions for Windows 7 support, so we've at least got some options available. We'll be exploring these to see which will work best. --- ## Ok Fine Taking a shot at Win 7 support. Don't get too excited, it may take a while to make this anywhere near user friendly. --- ## Luxuria Suburbia Buttplug Holy shit, the first Buttplug based stunt hack that didn't come from our own dev channels!A developer I used to work with on Rez Trancevibrator stuff a while ago ([https://twitter.com/curious_jp)](https://twitter.com/curious_jp)) posted the python script for this earlier today, after seeing the game at the BlushBox ([http://blushboxgames.com/)](http://blushboxgames.com/)) intimate games exhibition at PAX Australia. I pulled it and it pretty much just worked! There's more explanation in the video description on youtube. I'll be making a longer video about how the script works soon, but just wanted to get a video demo up now 'cause HOLY SHIT! :D --- ## The Shit I Do For You People Win7 Launch Control Demo There ya go. Proof of concept demo using the Launch with Win 7 on a laptop. No VM, no tricks, this is just normal ol' Windows 7 on a normal ol' laptop.I'm using the same Plugable dongle I recommend for Win 10 users. It just requires some different drivers to be installed. Please do not pass this video around, as I don't want a ton of people poking me about this. Getting the proof of concept going was the easy part, getting the system to the point of being usable by others and ready for release is going to require more work. Ideally, we can just release the Buttplug Windows App Suite with this embedded alongside our Windows 10 code, so everyone can seamlessly use the same package. That's going to require some rearchitecting and orchestration in the GUIs, though. Before that point, I may have some intermediate builds ready that people can try. I'll post here when that happens, along with instructions on which drivers you'll need. --- ## November Qa Ok. Time for that part of the month where you ask questions and I answer.ASK. --- ## Buttplug Win7 Bluetooth Le Server Alpha 1 Here we go.[https://ci.appveyor.com/api/buildjobs/3lohva12t662uun2/artifacts/ButtplugNodeServer-1.0.9.7z](https://ci.appveyor.com/api/buildjobs/3lohva12t662uun2/artifacts/ButtplugNodeServer-1.0.9.7z) Please do not pass this URL around. This is not meant for general public consumption yet. If you're running Win 10, ignore this and just use our C# server like you have been. This is really for Win 7/8 users only. This 7zip file contains a bare, command line Buttplug websocket server based on node. There's no installer, this is just the executable and supporting modules. I usually don't release things quite THIS raw, but I'd like to get some idea of how this works for people before figuring out which direction to go with it next. In terms of bluetooth dongles, right now the only one I have that I've tested with is the usual Plugable dongle I recommend. ([https://www.amazon.com/Plugable-Bluetooth-Adapter-Raspberry-Compatible/dp/B009ZIILLI)](https://www.amazon.com/Plugable-Bluetooth-Adapter-Raspberry-Compatible/dp/B009ZIILLI) Here's the steps for usage. 1. Install Zadig WinUSB drivers. Download Zadig from [http://zadig.akeo.ie/](http://zadig.akeo.ie/) and start it. Look at the device list for your bluetooth dongle, select it, and make sure the VID/PID pair that shows up is on the list at [https://github.com/sandeepmistry/node-bluetooth-hci-socket](https://github.com/sandeepmistry/node-bluetooth-hci-socket). If it is, install the WinUSB drivers for it. This means your dongle will no longer work with other devices, and you'll need to uninstall these drivers if you want to get it working with other things again. If this is a problem, upgrade to Windows 10. :) 2. Run the buttplug-node-server.exe executable. It should print a few messages followed by a "bluetooth on!" message. If you don't see a "bluetooth on!" message, then bluetooth is not running. 3. You'll need to do the cert verification step, same way as you do in the C# server. Open your browser, go to [https://localhost:12345](https://localhost:12345) and accept the certificate. 4. Go to [https://buttplug.world/playground](https://buttplug.world/playground) and try to connect to the websocket server, then do a "Start Scanning" and see if your device comes up. Currently, this will only work with playground/syncydink. ScriptPlayer compatibility is a top priority but I may not have time to work on it for a few days and just wanted to get something out. If you start scanning and your device isn't found, stop the websocket server, unplug/replug your dongle, start the websocket server again, then reload playground and try reconnecting. I've had problems with scanning just not finding devices at all until I replug the dongle, but haven't had time to debug. The goal is to integrate this into the same GUI the Win10 server users, but we're a ways off from that and I'm still trying to figure out how that's going to work. For now, this will hopefully work as a stop gap. I'll post updates as they happen, and please let me know if you do/don't get things working. Good luck. --- ## New Scriptplayer V103 Release Now With Whirligig Support [https://github.com/FredTungsten/ScriptPlayer/releases](https://github.com/FredTungsten/ScriptPlayer/releases)ScriptPlayer 1.0.3 was released this morning, now with Whirligig support! This means you can now use any buttplug compatible toy with a real VR Movie Player, versus our hacked together player in Syncydink that I still need to fix up. I haven't checked with the Whirligig dev yet, but in testing we've had to run with the Beta version of Whirligig on Steam, so you may need to set the beta channel. There's info on how to use ScriptPlayer and Whirligig together at [https://github.com/FredTungsten/ScriptPlayer/wiki/Whirligig](https://github.com/FredTungsten/ScriptPlayer/wiki/Whirligig) And for all of you who are about to ask "But when can we use it with Win 7?": I helped out on some of the development to make sure ScriptPlayer at least runs in Win7. I'm hoping to have the alpha version of the Win7 BLE server available in the next day or two, for patreon members only. :) --- ## Buttplug Development Updates It's been a little quiet around here lately, so I figured I'd share what's going on in development.- ET-312 Estim serial protocol support is now in the C# client. This allows users with ET-312 boxes to scale intensity based on input. - .NET Standard conversion of the C# project is finished. This is a fancy way of saying we're getting closer to being able to use C# for mobile apps on Android/iOS. Our goal there is to have a Websocket Server App for phones, which will solve even more platform issues (we hope). - We're working toward a v0.2 release of the C# projects, which will contain a lot of architecture work to make sure that software developed around Buttplug is forward/backward compatible. The goal is making sure we don't have someone's favorite program suddenly stop working because of changes made in the future. - Lots of architecture/documentation work. So things are a little quiet on the "interesting/exciting" feature front right now, but a lot of the work we're doing at the moment will ensure that we can get back to the exciting stuff with a more stable platform to build on. --- ## December Qa Another month, another Q&A. Roping in the $1 tier for this month because it's Christmas.So, if you got questions about metafetish/buttplug/life/etc, feel free to post them here and I'll answer to the best of my ability. --- ## Patreon Fee Model Etc Just wanted to say, anyone that does not want to deal with the new Patreon fee model, no hard feelings if you stop support for my campaign. What I have gotten so far has been very appreciated, and I plan to continue my patreon campaign, as well as look at other options like Ko-fi.  I know the new fee system change is pretty rough though, and I'm not gonna hold it against anyone if they don't agree with it. Thanks for your support. --- ## Patreon No Longer Implementing Fee Change Yet another quick non-buttplug-related update, but it's important.[https://blog.patreon.com/not-rolling-out-fees-change/](https://blog.patreon.com/not-rolling-out-fees-change/) I will now return to holding it against you if you discontinue your patronage. (No I won't) Thanks for sticking with me through this stupid, tough, stupid time. --- ## December Buttplug Update Thanks to the holidays I've been rather quiet, but that doesn't mean work isn't happening!However, that also doesn't mean the work is very interesting to anyone but core developers, either. :) As of last week, we've mostly finished up the new v1 implementation of the Buttplug Protocol Spec. This adds a couple of really important things: - Message Versions: We need to be able to tell whether a client and server are running the same version of the Buttplug Protocol. We now have the ability to do that, as well as deal with situations where the client is older than the server, so that **hopefully** we will never have to drop support for old applications that cannot be upgraded. We'll see how well that works in practice. - More Generic Messages/Commands: Right now, the types of commands you can send to toys is fairly limited. We have a specific command for the launch, another one of the vorze, or a command that will set all motors in a device to vibrate at the same speed, no matter how many motors it has. We've broken these down and generalized them, so that we can now support devices with multiple vibrators/rotators/thrusters. This should make it easier to writing software that controls toys in a generalized way, which is, you know, kind of the whole point of this project. This work has been in progress since October, and it's now mostly landed in the master branches of our repos. We're moving on to writing tests and updating documentation, then hopefully we can let the core sit for a while and update/fill out applications. In the mean time, I'm also working on scripts for new videos (like, buttpluggin' with qdot videos, not scripts for porn. Though maybe I'll make funscripts for buttpluggin' with qdot videos...) and building a set of interaction macros for the twine interactive fiction engine ([http://twinery.org),](http://twinery.org),) with which we'll be building our new Interactive Buttplug Usage Tutorial. If anyone is interested, that work is happening at [https://github.com/metafetish/buttplug-twine.](https://github.com/metafetish/buttplug-twine.) Ok and maybe I should rethink the title "Interactive Buttplug Usage Tutorial".  Anyways, hoping to start posting about more features like Win 7 support, Syncydink upgrade, and other stuff soon. Thanks for sticking with me, and hope you are having a good holiday season. --- ## 2018 Year Of The Buttplug I mean, 2017 was too, but nothing saying that we can't have multiple years with that as the theme.Working on lots of documentation right now, as well as finishing up the Buttplug Twine interactive fiction engine integration so I can build our new interactive tutorial in that. Also finished up scripts for 2 new videos, and got myself a fancy new microphone setup, so hopefully gonna have new video content posted this month! Hope everyone had a good holiday season, and thanks again for your donations. --- ## January Qa Just realized I forgot to post a Q&A at the beginning of the month, so if you've got any questions, as usual, feel free to post them here. --- ## Buttplug C 020 And Buttplug Js 050 Released Fucking. Finally.It's been 4 months since the last release of the C# applications and library, which is just way the fuck too long for a small project like this. I'm really hoping we'll speed up iteration on that side, because I've released... wow. 12 versions of the JS library in that time. If you upgrade the C# applications (WebSocket server, Game Vibration Router, etc...), chances are you're probably not going to notice much in the way of changes. While there's some new hardware support (ET-312, Youcups, etc...), most of the changes in these releases are deep in our libraries, around how we communicate let applications communicate with devices. Since you're giving me money, I figure you may be interested in some details, so here you go: Back in August of 2017, I'd been working on Buttplug for about 4 months with no releases yet, and was getting a little stir crazy. I ended up jumping the gun a bit and putting out 0.1.0 without really considering what we'd done at that point. That means we have messages that are... not very ergonomic.  For instance, if you want to make something vibrate, you normally used "SingleMotorVibrateCmd". While this supports an infinite speed range, it only does so for one vibrator. The Wevibe has 2 vibrators, the lovense edge has 2, the mysteryvibe crescendo has /6/. So we were throwing away a lot of toy capabilities.  Similarly, for controlling the fleshlight launch, we have a message named FleshlightLaunchFW12Cmd. Ugly, right? You send it a position and a speed, and it just sends that to the fleshlight launch. However, thanks to funscript, we have a lot of movies that are encoded with commands for position and time to move to that position from the last implied position, which we then have to calculate speed for. If we're gonna adapt those commands to vibration or estim or whatever, we have to do a lot of message gymnatics around that. To fix these issues, we now have messages like VibrateCmd and LinearCmd. VibrateCmd takes up to an infinite number of speeds, for an infinite number of vibrators. LinearCmd takes up to an infinite number of positions to move to within a certain amount of time for a certain amount of linear movers (the launch only has 1, but the real touch, with its belts, has 2). From those, we can adapt as needed between devices, and we're also future compatible for toys we don't even know about yet. Planning for this and making sure things would be backward compatible with what we've written so far is why all of this took so long, and why it kinda doesn't look like much on the outside. Having these features in will allows us to start retrofitting applications like syncydink and playground to take advantage of more toy features (so for those of you that read this far, YES I AM GETTING BACK TO SYNCYDINK WORK SOON). We're also developing new applications that will benefit from this. We've also massively increased test coverage on both libraries, meaning shit will hopefully break at least a little bit less. Anyways, that's it for now. I'll hopefully have more frequent updates about application upgrades soon, and now that this release is out, I can finally work on the videos I've written scripts for, so new Buttpluggin With qDot eps soon! Thanks for your continued support! --- ## Buttplug Development Video Update Here's a quick update about what's going on around Buttplug HQ (aka my office in my house)We released Buttplug C# 0.2 and Buttplug-js 0.5 last week. So far, the C# version has seen over 160 downloads and zero crashes reported so far, which is pretty exciting.  The JS library has seen... 3 point releases because it's complicated and our tests still aren't covering everything we need. :| I've updated both Buttplug Playground and Syncydink to use the new version of our libraries, though outside of extra toy support, there's not gonna be too much noticeable there yet. We've also had some reports that FeelTech has changed the file format for WankzVR/MilfVR haptics files again, so new files may be broken at the moment. Hopefully going to fix that in the next day or two. In terms of projects, right now my main focus is finishing the first round of our Interactive Tutorial. So far, we've used either the forums or direct communication via twitter/discord/etc to teach people how to use the software. I'm now working on a system that uses the Twine Interaction Fiction engine to bring people up on what Buttplug is, how it works, and get them connected, without having to send them to out-of-date message board posts or talking to them myself. You can see it in development at [https://metafetish.github.io/buttplug-tutorial](https://metafetish.github.io/buttplug-tutorial) If you can think of any problems you had getting things set up, or ideas we should include, feel free to comment here! It's pretty bare-bones at the moment. We'll be expanding it to have images/gifs to show what to expect in installation steps, more story paths to show how you can play movies/games/etc with Buttplug, and whatever else we can come up with. On the development side, I made some developer tools to make it easier to write web apps for buttplug without having hardware around. You can check out a demo of these at [https://how-to-buttplug-devtools.glitch.me](https://how-to-buttplug-devtools.glitch.me) Just tweeted about them today ([https://twitter.com/buttplugio/status/958085272289202176)](https://twitter.com/buttplugio/status/958085272289202176)) and got some good feedback! I've got a couple of new Buttpluggin' With qDot videos ready to make, having finished editing their scripts. Making the videos and starting work on Playground/Syncydink upgrades are mostly waiting on the tutorial being finished, because I don't want to announce a new round of updates then have to tell everyone how to use those updates personally. Thanks for your ongoing support! --- ## Buttplug Tutorial Beta Now Live Buttplug Js V060 Released [https://metafetish.github.io/buttplug-tutorial](https://metafetish.github.io/buttplug-tutorial)Been spending the last few weeks putting this together. It's a Twine (interactive fiction engine) based tutorial for getting people up and running with the basics of the Buttplug App Suite. Probably not going to be much new for patrons here, but if you have feedback, do let me know. I'm hoping to use it as our main guide for both the Buttplug App Suite (which will be changing names at some point in the nearish future I hope) as well as things like Syncydink, and maybe even outside apps like ScriptPlayer if the authors are interested. The tutorial has been a pretty heavy test of the buttplug-js library, and I've just pushed v0.6.0 which has most of the features and bugfixes required. Hoping to get playground and syncydink on this soon too, should fix a few bugs there. Also, we've just added support in buttplug-js for a $10 bluetooth vibrator you can get off Amazon US: [https://www.amazon.com/dp/B017N016S4](https://www.amazon.com/dp/B017N016S4) Hopefully going to have C# support soon too. If you want a cheap toy to test with, this is definitely the way to go, though we're still working on reversing the complete protocol. Right now all we can do is control vibration speed (but we can't actually turn off vibration, just turn it down to the lowest level. Kinda weird.), or power off the vibrator completely. :) That's it for now. --- ## Buttplug Interactive Tutorial Released [https://buttplug.world/tutorial](https://buttplug.world/tutorial)Calling the first version done, 'cause otherwise it's never gonna be. I suspect most patrons won't really learn much from this, since a lot of you have been around since I started the project in the first place, but we've now got a place to point new users to show them how the software works. Lemme know if you've got any feedback! --- ## Game Vibration Router Tutorial Demo Video Here's an unlisted version of the GVR Tutorial. Trying to get some feedback before I mark it public, so let me know what you think! --- ## Buttplug Win7 Server Alpha 2 [https://ci.appveyor.com/api/buildjobs/f54kxtmhtmprm62n/artifacts/ButtplugNodeServer-1.0.10.7z](https://ci.appveyor.com/api/buildjobs/f54kxtmhtmprm62n/artifacts/ButtplugNodeServer-1.0.10.7z)After our major library upgrade last month, I forgot to bring the Win7 alpha server up to date with it. That's all fixed now. The above executable should work with Playground/Syncydink again. Lemme know if you have any problems. --- ## Gvr Tutorial Video Update Re-did the responsibilities part of the video, shaved a good 30 seconds off of it and took a bit less combative tone. Good chance this will be the final version. --- ## Blooper Reel Qdot Being A Dumbass With Buttplugs YES. I HAVE SHIPPED A TIER REWARD THAT IS SOMETHING OTHER THAN Q&A.Here's some no-context b-roll from an upcoming Will It Buttplug video. Enjoy. --- ## Gvr Tutorial Now Live Tutorial video is up! Only announcing it here and in chat groups for now, as I'm working on the Will It Buttplug episode for Rez Infinite that will be considered the actual GVR release video, and this will mostly go alongside that. The video is public and on my youtube channel now tho, so if you want to pass it to people to check out, go for it. --- ## Will It Buttplug Trailer I decided to make a trailer for my new Video Game Review series. Lemme know what you think! --- ## Will It Buttplug Rez Infinite The first episode of Will It Buttplug is done! Covers Rez Infinite and getting it connected to the Rez Trancevibrator.Next up, a teardown video of the trancevibe, and a Buttpluggin' 101 video on the GVR. --- ## Gvr On Vice Motherboard The Will It Buttplug video made it on Vice!More videos coming soon. :D --- ## Buttplug C V021 And Buttplug Js V061 Released Software update time! Just released a new version of Buttplug C# with some bugfixes, toy support additions, and upgraded Game Vibration Router.[https://github.com/metafetish/buttplug-csharp/releases/tag/0.2.1](https://github.com/metafetish/buttplug-csharp/releases/tag/0.2.1) Also released v0.6.1 of buttplug-js, which contains some API additions and more toy support. [https://www.npmjs.com/package/buttplug](https://www.npmjs.com/package/buttplug) --- ## New Metafetish Discord Invite Link [https://discord.gg/t9g9RuD](https://discord.gg/t9g9RuD)Our old invite link was set to kick people who didn't say anything if they disconnected, but it kinda went way farther than that and randomly disconnected a ton of users. So we've fixed that but now require a new link to get to the discord. Remember, if you're a Patron of any tier, you get a special role! --- ## Yiffspot Teledildonics Via Buttplug If nothing else, you're paying me for these post titles, right? :)Well, this is definitely not how I planned on spending the past couple of weeks, but here we are. A few weeks ago, I got pinged on a twitter thread about NSFW github repos. In the same thread, this repo came up: [https://github.com/kisuka/yiffspot](https://github.com/kisuka/yiffspot) Yiffspot is a node.js based anonymous sex chat server, which runs the domain [https://yiffspot.com](https://yiffspot.com). You can go there now and have text sex with some anonymous furry if you'd like. Anyways, since the code was open source, I decided to look through the repo. Surprisingly enough, the project was written in fairly clean, simple es5 Javascript. Not only that, the project is a complete standalone server. As long as you have a machine to host it on, it handles both the client and server side. This seemed like a perfect candidate for Buttplug integration. I had figured that doing a full person-to-person teledildonics server was going to take more work because I'm apparently stuck in the past, but this was everything I needed to make a quick, decentralized teledildonics server. 2 weeks later, I've gotten the patches into good enough shape to submit as a PR to the main project. The server, with buttplug integration, is also up and running at [https://teledildonic-yiffspot.glitch.me](https://teledildonic-yiffspot.glitch.me) With documentation at [https://metafetish.club/t/using-buttplug-with-yiffspot/267](https://metafetish.club/t/using-buttplug-with-yiffspot/267) And remixable/clonable on glitch at [https://glitch.com/edit/](https://glitch.com/edit/#!/teledildonic-yiffspot)#!/teledildonic-yiffspot You may be wondering why this is important. That's a good question. Well, I mean, first off, more ways for furries to fuck is always important. Obviously. Outside of that, the only things that make Yiffspot "furry" is the name, and the fact you have to choose a species for partner matching. Beyond that, it's just a plain chat server (with some weird BDSMy options I guess but hey). We can easily modify the look and options and turn this into a generic teledildonics server. I've also cleaned it up enough that it's easy to bring up on places like Glitch or Heroku, so people can have their own server if they don't want to use a central one. This means it's basically decentralized. If you have the codebase and the server, you're mostly ready to go. Having this as a proof of concept is giving me all sorts of ideas about other simple, connected things we can do. For instance, having synchronized movie playback with Syncydink, in case you wanted to watch a video with someone else at the same time. Also, this was a great test run of one of the biggest use cases of Buttplug: bolting it on to shit that is already out there. Before people start building applications specifically for Buttplug, we have to prove its worth, and most everything I've built so far has been from the ground up. This will be the first time I've added Buttplug functionality to something I didn't start, and handed it back to the original developer. Will be interesting to see how well that works out, assuming any normal Yiffspot users even have computer connected toys. Now that this project is done, I'm hoping to get back to polishing up things like Syncydink (REALLY I AM ACTUALLY GOING TO WORK ON IT AGAIN), the Twine libraries, and finally getting some of the UI/UX nightmare that is the Windows GUI tamed. There will hopefully be more video production in between all that too. I'll be writing up a longer blog post about the Yiffspot work on Metafetish, and will have a better status update on the rest of the projects hopefully sometime in this upcoming week. Thanks for your support! --- ## New Easy To Remember Urls For Buttplug Stuff Finally spent some time learning to make subdomain redirects in AWS, so now we have:Discord: [https://discord.buttplug.io](https://discord.buttplug.io) Youtube Channel: [https://youtube.buttplug.io](https://youtube.buttplug.io) Trello Board for Feature Requests (which I'm still working on): [https://trello.buttplug.io](https://trello.buttplug.io) Github (main buttplug repo): [https://github.buttplug.io](https://github.buttplug.io) --- ## New Buttplug Website In Beta [https://io.buttplug.world](https://io.buttplug.world)After spending most of GDC going "Yeah I make some sex toy software but don't look at the website it sucks", I'm trying to fix that. That's where the site will be in beta until its done. Hoping to have it finished in the next week or two. Lemme know if there's anything you think should be on there! --- ## Project Updates And April Qa Welp, we've now reached me being on patreon for a whole year! Thanks to everyone for sticking with me so far.Trying to get back in the swing of doing monthly Q&A's, so if you've got questions, lemme know! However, since most questions have usually been "What are your plans for [piece of software you made that you haven't touched in a while]?", I'll give updates on all of those first. **Hardware** Getting Vorze and Lovense key access working would be great, as it would open up more chances for users on Win7. We have the hardware, it's just a matter of getting it all figured out. We're still trying to finish out the Kiiroo Onyx 2. We have the Pearl 2 and Fuse done, I think the Onyx 2 is mostly the same, but we don't have one to test on yet so we're developing for it blind. Haven't had any other hardware requests lately, so if you've got a toy we don't support, let me know. **Buttplug Protocol/Libraries (General)** We've got a couple of big things that need to be done in general across all libraries right now. First off, we need an external way to define hardware. Right now, if a company changes their toy identifiers (like Lovense does CONSTANTLY), we have to basically release a new version of the software. The hope is that we can make an external config file that will be updated and distributed online, so we can update server capabilities for new hardware we already have protocol support for, without requiring everyone to download everything all over again. Secondly, we need to start thinking about inputs. This will probably start with something benign, like retrieving battery levels from toys, but could grow to encompass accelerometers, buttons, and other sensors on toys too. How we abstract this (i.e. how do we make toy accelerometers all return the same basic normalized data) is going to be a tough problem to figure out.  **Buttplug C#** We just landed code comments and documentation, as well as support for the USB Cyclone X10. Oddly enough, the Cyclone is the first toy we've found that was already open source! You just have to be able to read Japanese, heh. All of the USB HID code was available in an open source C library on their website, which made this pretty simple to implement. I'd like to get libraries and applications divided up, and we'll hopefully be moving to a new application system soon that is slightly less jank than our current controls library crap I threw together in half a day like a year ago. I'd also like to get IPC capabilities added to the client/server, so local apps no longer have to route through Websockets. This will save a lot of trouble with all of the SSL hoops users usually have to jump through. **Buttplug JS** Haven't touched the JS libraries much lately, and they're mostly running ok. Hoping to get more documentation together soon at least. **Syncydink** Priority #1 on syncydink is getting a news panel up on load, so you can actually see what version you're running, as well as any updates that've happened. I get a lot of questions about if I've updated Syncydink because it's not working, but I haven't touched it in months, so it'd be better if it just said that itself. After that, I really need to bring all of the packages and dependencies up to date. This is usually a matter of just typing in a couple of commands, but some of the packages we use are like, multiple versions back (the biggest culprit being our video player package), so that's gonna take some concentration. Finally, once we're up to date, I really want to get the encoder done. I know everyone else wants that done too. Then it's on to things like streaming capabilities and new encoding interfaces. **Playground** Playground is still pretty good at doing what it needs to, not a lot of things to add here. I'd like to get something in to control rotation toys like the Cyclone X10/A10, but that's about it. It'll also get the same news panel as Syncydink, not that it seems to matter much there. **Buttplug Tutorial** I finished the tutorial, and have been pointing people at it when they ask, but the current website still doesn't mention it. I think it'll start getting tested more when the new website comes up, since it's front and center there. Definitely needs a CSS overhaul. **Unity Plugin** This was the #1 question I got at GDC last week. The good news being that there's also a lot of Unity experts at GDC, and I'm hoping to get help from a few of them to get this going. So hopefully more news on that soon. **Unreal Plugin** This was the #2 question I got at GDC last week, surprisingly. So that's at least on the radar now. **Twine Plugin** The twine plugin has been running the tutorial for a while now with no real complaints, but it's still not in a state where anyone can easily use it, so I'd like to get more documentation work done on that. Got some initial interest in it at GDC, so worth polishing. **Youtube** More Will It Buttplug videos are in the pipeline, and I'm really hoping to start a series on how Porn Sync works soon too, which will hopefully drive more interest in Syncydink dev. So, uh, that's everything in my head for the moment. If there's some status I haven't covered, please comment and I'll be happy to answer! --- ## Buttplug Android App Yes Really I'm as shocked as you are. Someone just showed up to our discord server, mentioned trying to build an android app, and then all of the sudden it was ready to use and they're working on a VR movie player app too.[https://github.com/metafetish/buttplug-android/releases](https://github.com/metafetish/buttplug-android/releases) This is an alpha release of the Buttplug Websocket Server Android App. This app works just like the windows app, in that it runs a websocket server and allows Buttplug compatible apps like ScriptPlayer, Syncydink, etc to control toys through it. I've tested it with the Launch and Lovense toys, and it worked for me. This means, as long as you have an android phone and it's on the same network as the computer you want to run apps on, you should be able to control toys from any OS, including Windows 7. You'll need to download the WebsocketServer APK on your phone and install it, as the developer is still working toward getting it into a state where we can put it on the app store. Also, I personally have had problems getting SSL to work, so I haven't tried it with syncydink or playground. ScriptPlayer, which does not use SSL, did work with it for me though. When connecting via apps on other machines, you'll need to use the IP address that shows up on the phone server UI (not the 127.0.0.1 one on there either). Let me know if you have any questions, or feel free to hop on the discord server at [https://discord.buttplug.io,](https://discord.buttplug.io,) where both I and the developer hang out. --- ## New Buttplug Website Is Up [https://buttplug.io](https://buttplug.io)After 1.5 months or so of work, the new, simpler, cleaner Buttplug website is live. Hopefully this will be slightly more useful than the last one. --- ## Buttplug And Oculus Go I picked up an Oculus Go yesterday, and will be spending the next while testing it with Buttplug. The Go runs android, and has a built in browser based on Blink/Chrome. While it ostensibly supports WebBluetooth (our Playground and Syncydink apps have the "Connect Local" feature enabled, which means bluetooth is present), the browser currently crashes on device scan. I'm hoping that will be fixed in the future, as having this supported in the browser would be fantastic for building quick control apps without having to get things into stores. While I wait for a fix on that, I'm going to be testing other ways to hooking up the Go with Buttplug, as this seems like it will be the perfect platform for movie VR content + hardware control. If you have any questions or anything you'd like tested, please let me know. --- ## New Version Of Buttplug Playground Is Live [https://buttplug.world/playground](https://buttplug.world/playground)Finally finished overhauling Playground with Typescript 2.8, Vuetify, Webpack 4, etc... It's now much cleaner codewise, though also 75% larger somehow (probably due to some issues with Vuetify that I'm still waiting on resolutions for). For new patrons out there: Playground is the our web-based minimal testing/control application. It allows you to connect to vibrating/rotating/stroking devices and set controls for them. It doesn't do much, but it's super handy if you don't need to do much. :) One of the nice features is that the About panel on the sidebar is now actually useful. You can use it to see what version of Buttplug is running under Playground, as well as when it was built. This is autogenerated on deploy so it should stay up to date. Next up, overhauling Syncydink. Finally. --- ## Nipple Blenders Are Hopefully On The Way Since you're all paying me, here's a bit of pre-release info, and also some information about what the money gets used for.!!!!! I FINALLY FOUND A PLACE TO ORDER A VORZE UFO SA !!!! Was doing some random toy searches on Amazon and decided to see if it came up, and sure enough, some tiny place apparently has *1* available and I ordered it. I'm trying not to get my hopes up too much, but this has been one of my Holy Grails of Sex Tech for a while now. It's just so different from everything else, and most Japanese outlets don't ship internationally. It should show up in 2-3 weeks, I'll definitely update when that happens. Expect Buttplug support and videos and who knows what else soon after. --- ## Nippleblenders Have Arrived AAAAAHHHHHH I FINALLY HAVE A VORZE UFO SA NEVER HAVE I BEEN SO EXCITED ABOUT GETTING A SEX TOY I HAVE FEW PLANS TO ACTUALLY USE. BUTTPLUG SUPPORT SOON. --- ## Buttplug C 023 Released [https://github.com/metafetish/buttplug-csharp/releases/tag/0.2.3](https://github.com/metafetish/buttplug-csharp/releases/tag/0.2.3Big) Big release! Lots of bugfixes, plus support for the kiiroo onyx 2, Vorze UFO SA, MysteryVibe Crescendo! Added a new community contributed vibration multiplier to the game vibration router! --- ## Translating Buttplug Now that the Buttplug website is in order and I have some vague ideas about software direction, I'm looking at getting translation work done. I *think* this is i18n work, but I'm not sure and don't want to confuse anyone that actually knows what they're talking about, so I'm just saying translation. I posted about this on twitter and already have interest for German, French, Spanish, and Ukrainian. Japanese is a major goal that's currently not covered right now, so definitely looking for that. The first translation priority will be the Buttplug website at [https://buttplug.io,](https://buttplug.io,) which doesn't have a ton of text on it but is key for bringing in new community and contributors. Hoping this will be a good way to iron out the process, as this is also gonna be the first time I've ever done this on one of my projects. After that, we'll look at documentation, libraries, and applications, figuring out which translations would best serve the community.  Right now I'm figuring out which translation service I want to use. I'm pretty sure I'm going with [http://crowdin.com](http://crowdin.com) . If anyone has worked with that or any other services like [http://transifex.com](http://transifex.com) , [http://phraseapp.com,](http://phraseapp.com,) or others and have opinions, please do let me know, 'cause I'm starting from basically zero knowledge here. If you've done this kind of work before and have advice, or are interested in helping expand the Buttplug community by translating some of our work into new languages (or can help cover the languages already listed), please feel free to message me on here. --- ## Vorze Ufo Sa Video Blooper I'm currently filming the Buttpluggin' with qDot UFO SA overview video. I was trying to record some of the movies that came on the demo disc, but I forgot to turn my voice over mic off while recording. It ended up picking up the sound of the UFO SA being controlled by the video, which, without visual context, ends up... yeah.Please enjoy the sounds of robot nipples being tweaked. --- ## What The Hell Do Yall Want Anyways It's been another crazy month of patrons joining, leaving, and shifting levels, so let's see what the temperature is here.What would you like to see more of? You can vote for as many as you'd like, and I may sub-poll this depending on how this goes. If there's something not on the poll that you'd like to see, leave a comment! --- ## Buttpluggin With Qdot Unboxing And Analysis Vorze Ufo Sa Nippleblender Finally, patrons actually getting a prerelease of a video!Video is done but I'm still working on the description and stuff, so you get a whole 12+ hours of it all to yourselves before I release it for real tomorrow morning. :) --- ## What's qDot Up To This Week? (2018-06-08 Edition) Ok, gonna try a new thing. Weekly updates! Just so you have some idea what's going on, since you're like, you know, paying me.These will probably get posted on Wednesdays from here on out. **This Week: **Unfortunately the update this week is gonna be super boring, because it's one of those super boring tasks weeks. Almost all of my time has been spent shuffling our hosting, so the end of this post is going to be about one of the topics nobody voted for in that last poll. :) Also did some work on a Will It Buttplug? video, just to see if I can start cranking those out a little faster. The UFO SA video took 5 days of work, and I'd like to be able to release a video every 1-2 weeks versus every 3 months. **Plans for Next Week:** I have to travel for my dayjob (all the way across the bay bridge to San Francisco :) ) next week, but that doesn't mean things won't get done. I usually hide in my hotel room during the evenings, so there may be work happening. I'm also planning on starting up a couple of new polls to drill down on the results from the last one, since people want more videos and more   **The Horrible Details Of Moving Hosting:** **Note:** If you aren't interested in the details of hosting moves, the rest of this post has absolutely nothing to do with sex toys, you can probably just skip this. If you happen to be paying me for sex toy work and also have an interest in devops, consider this some extra bargains for your cash! I've been hosting my sites on Dreamhost shared hosting for the past 16 or so years, 'cause, well, I never had much in the way of needs. Almost everything we host is either a static site or a client-side SPA. However, that hosting is super slow ('cause it's shared), and isn't really going to scale for our needs, and I didn't want to just sit Cloudflare in front of it.  The original plan was to move to AWS. While I finally managed to get the AWS chain of s3, Route 53, CloudFront and Certificate Management going (buttplug.io and buttplug.world are currently running on this setup), it kinda sucked to set up for new sites and manage for the ones I'd moved, and it was really hard to track resource requirements, even though our sites are static. I still couldn't really figure out when/why we were getting S3 puts/gets, despite having set up metrics management.  The next move was going to be taking metafetish.com from DH to AWS, but that was turning into a nightmare due to the massive amount of redirect rules (1200+) metafetish has thanks to having existed for 14 years across 4 blog engine moves (soon to be 5 as it will move to Hexo from Pelican), as they would have to be expressed as s3 object redirects, which would require a ton of scripting to set up and would drop some of the wildcard rules I was currently running in Apache.  Having stalled on that move, I stumbled upon Netlify ( [https://netlify.com](https://netlify.com) ) which looks like exactly what we need. They're made for static site or SPA hosting, and they're like, weirdly free. I've got one of my domains moved over there now, and will be moving buttplug.io and buttplug.world there over the weekend, followed by figuring out how metafetish.com will work out there. Honestly, this isn't gonna mean much for users, possibly ever. It mainly buys us reliability just in case we get featured on HN or something, but that's a very "what if" case. It's still more flexible than static hosting though, and Netlify folds in Let's Encrypt management, does their own CI, etc, so it's less steps from nothing to working site. In the end, we'll be hosting all static sites on Netlify, and anything that requires compute resources on Digital Ocean Droplets. Our Discourse instance is currently taking up pretty much all of a $10/month Droplet (thanks, Ruby On Rails :| ), and I may move Matomo Analytics onto a Droplet over there too, which will pretty much finish off my Dreamhost hosting. I cannot wait to get back to literally anything other than this. --- ## What's qDot Up To This Week? (2018-06-15 Edition) Dear god, if I never talk about web browsers again it will be too soon.Too bad that's my dayjob. >.> Was at a dayjob meetup all week, so not much got done in terms of development on Buttplug. I mentioned this might be happening in the update last week, so no real surprises there. However, I've got some new ideas for web based interaction via WebExtensions that I'm going to be poking at, that I think may improve how Buttplug works with movie sync in web browsers and on sites outside of syncydink. More on that soon hopefully. Our server move is 98% done, now down to fixing some links to old domains and we should be good for a while. I'll hopefully be getting this finalized over the upcoming weekend. --- ## Automated Motion Analysis Research Fun new toy showed up today, as there are lots of computer vision papers and tools coming out of a big CV conference this week![https://github.com/MagicLeapResearch/SuperPointPretrainedNetwork](https://github.com/MagicLeapResearch/SuperPointPretrainedNetwork) So, for those of you that don't read computerese... This is a small tool that does motion analysis on sets of images or a movie. It'll pick out points it can detect motion on, and track those points across time as the movie progresses, handing back information on where it thinks things have moved between frames. I've attached a movie of me running this against some random porn. In an ideal world, this would run in real time via the GPU, but I don't have CUDA set up on any of my machines at the moment and didn't want to fuck with it, so this is the extremely slow CPU-bound version, hence the 1fps display. However, you can still see the motion vectors being generated across frames. We should be able to use this data to create Buttplug commands to automatically encode ***some parts of movies*** ***in some instances***.  This is absolutely not a panacea for our movie encoding requirements. We'll still need to deal with scene edits, camera changes, camera motion, and as the ML was trained on what I am assuming are real scenes, it will have issues with hentai and furry art (and yes I tried it on furry art first because I most certainly have my own interests in mind here). However, this could vastly speed up encoding scenes where the camera is static and things stay in frame. How this will look for people who just want to encode quickly, I can't yet tell you. I'm still a long ways off from being able to turn this into a usable tools that I can redistribute. Thought it might be fun to show off some ideas in development though. Fun times ahead! --- ## What's qDot Up To This Week? (2018-06-22 Edition) Ok, guess we're sticking to Fridays for weekly updates. Or maybe Saturdays, as is the case now.First off... If you ever wonder what I'm doing with your money, well, the image in this post is a good indicator. I get a lot of questions on [our discord](https://discord.buttplug.io) about cheap toys that work with Buttplug, which is why we have support for things like the [Youcups Warrior 2](https://www.aliexpress.com/item/YouCups-new-Warrior-II-APP-interaction-electric-male-masturbator-Vibrating-oral-Sex-products-adult-sex-toys/32833568062.html) and [Pipijing Whale](https://www.aliexpress.com/item/Electro-shock-8-speed-vibration-Smart-Kegel-Exercise-remote-control-silicone-egg-G-spot-ben-wa/32850060447.html). People want something to play with, but may not be able to shell out for a Lovense, much less a Launch or ET-312. I try to keep a list of < $50 toys from Alibaba that may take a couple of months to arrive and be less-than-body-safe, but will at least provide *something* for people to work with. That means I also find stuff like bluetooth speaker onaholes. One of those is on the way to me now, and there will most definitely be a Buttpluggin' With qDot video about it when it arrives. Now, Software Updates! All of our server moves are done, and I'm now down to ironing out bugs from the move, like our CI scripts not working (CI = Continuous Integration, a system that allows us to make sure that our software builds and works somewhere other than our own development machines). This means I can get back to more important work. I've just accepted some fixes to our C# code to improve Lovense device handling, and we're starting to discuss input and sensors. Right now, Buttplug in general is output only. We can make things vibrate, but we can't, say, read an accelerometer or pressure sensor (or battery level!). That's one of our next big areas to implement, though right now it's mostly in the discussion phase. This week, I'm hopefully going to be spending a bit more time updating our Javascript library to be at parity with our C# library for toy support, and trying to bring all of our various JS apps up to date too. I got most of the way to upgrading Syncydink (which still is running on the version from last fall -.-) a couple of months ago, would be nice to get that over the line so features are easier to add again. As I posted about earlier this week too, I'm making a pile of research stuff to work on at some point. This includes: - Automated encoding using ML and CV (translation: blinding chaining python scripts because I have no clue what I am doing) - A new way to use hardware sync with movies on webpages outside of syncydink (so you could, say, go to porn hub and play a movie on there and it'd work with your toy, versus having to download a movie locally) - New UI for our windows apps (because our UI sucks) That's it for now, back to work! --- ## What's qDot Up To This Week? (2018-06-29 Edition) Javascript, javascript, and more javascript. Well, ok, it's actually all Typescript. But you get the idea.buttplug-js has been lagging behind our C# libraries for a while, so I spent the first chunk of this week bringing it up to date, and buttplug-js v0.8.0 is out now. We now have Lovense device queries working everywhere, which is a massive help for the new versions of firmware constantly being released. Also fixed quite a few bugs. Once that was finished, it was time to go update the rest of the apps that depend on it. I've updated our Twine and Tutorial apps, so they run on the new version. Buttplug Playground also got an update, and now supports per-feature control, meaning if you have a piece of hardware with multiple features (like the Lovense Edge, Max, Nora, or Mysteryvibe Crescendo), you can now control motors/rotators/etc individually). Finally, the thing most people are actually interested in... **Syncydink** As I'm sure everyone is painfully aware, I haven't updated Syncydink in for-fucking-ever. There's a few reasons for that. - I had to change a bunch of the underlying libraries, including the UI library it was built on. - It's a complex program, and building both 2D and VR into it made it really difficult to work with. - I've just been generally busy anyways. I started overhauling the UI back in May, and that's mostly done now. Syncydink mostly works now, outside of the device simulator, which I'm hoping to get rid of and just use the Buttplug DevTools for, and VR, which... I'm trying to figure out what to do with. I'd really like to keep 2D and VR in the same application, but the VR libraries make up over half of the code size. My hope is to get these issues knocked out and a new version of Syncydink up soon. It's been rather annoying because this upgrade basically gets us back to where we were except with newer libraries, while what I'd really like to be doing is adding new features. Hopefully the maintenance work will be done soon though. Thanks again for your support! --- ## Syncydink Beta [https://beta.syncydink.buttplug.world](https://beta.syncydink.buttplug.world)Here's the URL for the beta of the upgraded Syncydink. Outside of the widget set changes, the biggest change right now is to Video Modes.  Mostly, that there aren't Video Modes anymore. :) My assumption right now is that less people are using Syncydink for VR than for regular old 2D movies, so having the modes front and center was a little silly when not that many people needed them, and maintaining the split mode was a god damn nightmare. This doesn't mean VR is completely gone though, there's just some new steps to get to it. When you open the side panel, there is now an "Enable VR" checkbox. You'll need to check that, then when you load movies, there will be a "VR" button on the movie control bar.  Note that if you're on a slow connection the "VR" button popping up on the control bar may take a few seconds. Syncydink downloads the code for the VR player whenever you enable VR, which saves around 40% of our initial load amount (Syncydink is around 400kb base gzipped and minified, and the VR is another 300kb on top of that). Anyways, clicking that button will send you into fullscreen VR mode, which should display in a helmet/phone/etc if you have one hooked up. There's really not any new features here to speak of yet, so don't get too excited. The work so far has mostly been cleanup to make sure changes I want to make in the future will be easier to do, so new features are coming, they're just still a bit in the future. :) --- ## Syncydink Beta One Extra Thing You can hit Escape on a keyboard to open and close the side panel now. This will be extremely important if you have a movie that's larger than the side widget. :) --- ## Syncydink V003 Is Now Live May god have mercy on us all.Syncydink v0.0.3 is now live, making it the first major update of Syncydink since December 2017. There's still not much in the way of new features, as most of this was cleanup and package updates, but development should be much simpler from now on since the mess that was Video Modes is gone. I've also switched out the opening page with a card that shows slightly more info. In the coming days, this will fill out some to actually include documentation on how to use the player, as well as news and updates, so users won't have to guess about when the last time I changed things was. If you have any problems or issues, please let me know. For those that are about to ask when I'm going to get back to working on the encoder part and possibly add gamepad encoding or something, the answer is "now, hopefully". --- ## Totos Africa Played On A Bluetooth Speaker Onahole Your patreon dollars, hard at work.My bluetooth speaker onahole arrived. Full review video coming soon. --- ## What's qDot Up To This Week? (2018-07-06 Edition) A couple of days late, but I'll blame that on the Steam sale selling me Metal Gear Solid 5 for cheap and getting me addicted to it. Sure.*attaches fulton extraction device to buttplugs* Anyways, busy week around Buttplug Labs before that! Finally got the new version of Syncydink out after 7 months of quiet. I'm now working on doing rolling releases of it with smaller features, since that overhaul took so long. Getting web based encoding up and running is the next big deal, which is mostly down to me remembering how d3 (the visualization library I used to build the timeline/graphs) works, and how our data interacts with it. It's a super complex library, but hopefully I can get everything cobbled together enough to spit out a funscript file. Would also like to get basic documentation and changelogs built into the playground and syncydink apps, as so far it's been quite difficult for anyone not me to figure out when things were updated, how they work, etc... I just got in a stack of toys from Aliexpress, including the Bluetooth Speaker Onahole I posted yesterday. I have a lot of catching up to do on toy documentation and implementation! That's it for now, back to work! --- ## Youtube Access In Syncydink Beta [https://beta.syncydink.buttplug.world/](https://beta.syncydink.buttplug.world/)Below the file entry on the syncydink side panel, there is now a place to paste in youtube urls. If you paste in a URL and hit enter (I need to fix up that UI), it'll now load a youtube video directly into syncydink.  We don't actually check whether a URL is youtube yet, so if you try to paste another URL or something in, I can't really tell you what will happen. Feel free to test that and let me know. :) The main idea for this feature is to make it easier to at least show demos of the player without requiring people to have videos on their drive, as well as create sync files for Buttpluggin' With qDot videos. Also, this means that once the encoder is done, you'll be able to encode youtube videos from the syncydink interface. Fun! I realize youtube isn't exactly as useful to most people as, say, pornhub, but I'll have to figure out if I can do direct video embeds from places like that or if they're gonna require iframe loads. I'm sure there will be bugs with this, so please let me know what you run into, either in the comments of this post, or in the forums or discord server. Thanks! --- ## What's qDot Up To This Week? (2018-07-13 Edition) A rather quiet week due to some personal stuff getting in the way, but still got some work done!Youtube Embeds are still in beta on Syncydink. The goal here is to provide scripts alongside Buttpluggin' With qDot videos, so when my toys vibrate in videos, yours can too! This means I've gotta build recording features into our apps, but that shouldn't be too much of a problem. With that in mind, I'm also working on making my recording setup a little easier to work with. Editing is usually the #1 time sink when making youtube videos, so I'm trying to see how much composition and one-shot recording I can do to maybe crank out videos like the Will It Buttplug series faster. This isn't gonna work for everything, as my more complicated videos will still require multiple cameras and editing work, but it's worth a shot. Also trying to actually get a list of hardware we support on the website! Wild to think the project has been running for 16 months with no easily-accessible list of what hardware it works with. Bit of an oversight there. >.> The plan for the moment is to continue on improving Playground and Syncydink. Unity is being worked out slowly too, and over on the discord, we've got some Twine developers exercising our Twine library to make sex toy interaction with Twine games. Lots of exciting stuff on the way! --- ## Buttpluggin With Qdot Will It Buttplug Crimsonland Yay, a Buttpluggin' with qDot video made in an evening instead of multiple weeks! A review of how well 10tons Ltd's Crimsonland (which I randomly picked up on steam for like $2 but ended up enjoying quite a bit as an actual game because I just love twin stick shooters) works as a sex toy controller.  Is Crimsonland Art? Watch to find out! --- ## Poll Phasing Out The Kiiroo Emulator Most of the crash reports we get from Buttplug C# these days have to do with the Kiiroo Emulator. For those not aware, this application simulates the old Kiiroo server that was used with the Onyx 1 and Pearl 1 before FeelConnect was a thing. The movies at [http://flicker.tv,](http://flicker.tv,) which is where we usually directed people for easy to get free films, expect the server, but we've built readers for their file format into Syncydink and ScriptPlayer, so that's not as much of an issue. Kiiroo took the actual server out of production around the time Buttplug started development, but I used the simulator as a test for early builds and it's just kinda stuck around since.We'd like to remove the Simulator completely, as it'll be one less application to take care of for us, but I want to make sure no one has any dependencies on it before we do that. I've got a twitter poll up at [https://twitter.com/buttplugio/status/1020800900829286400,](https://twitter.com/buttplugio/status/1020800900829286400,) but I'm posting a poll here 'cause you're all paying me so I listen to you more. :) --- ## What's qDot Up To This Week? (2018-07-20 Edition) Videos and toy support!We had a couple of questions about toy support this week that we're now getting filled in. Turns out the Kiiroo Onyx 1 was never fully supported in our Kiiroo code, so one of our contributors took care of that. We also now support the WeVibe Classic, as requested by someone on the forums. Finally, I now have access to a Estim Systems 2B, meaning we can fill out a bit more of our estim support. In Youtube land, I finally cranked out another Will It Buttplug video, covering Crimsonland, a twin stick shooter that also works as a surprisingly decent vibration pattern output. The big deal here is that I managed to get the video out in 2 hours start to finish, versus the usual 3-5 day filming/editing time of the hardware analysis videos. Hoping to get a better pace on video output now, and have a few more games lined up to test! Finally, welcome to my 3 new patrons this week! Been great to get more support, and I look forward to providing you with quality buttplug related content. --- ## What's qDot Up To This Week? (2018-07-27 Edition) As the weekly updates drift farther from the date they're supposed to be on...This week has mostly been working with some other developers on what may end up being our first full Unity integration! I'm not sure how this will look going forward, but I've got high hopes, since Unity support remains our #1 requested feature. The work here was mostly adding some small features like the ability to inflate/deflate Lovense Max toys, and to run the Buttplug Server on windows without a GUI. Hopefully these features will prove useful for others too. Other than that, life has gotten in the way of working on Syncydink and more videos the past week or two, but that's hopefully clearing up now. Once I can sort the gigantic pile of sex toys on my filming desk (my attempt at "cleaning my workspace"), that should help quite a bit. --- ## August Monthly Qdot Qa I haven't sent out an official one of these in a while, so it's time to get started again as I try to vaguely adhere to my own tier rewards.Anyone got any burning questions for me? Ask in the comments! --- ## What's qDot Up To This Week? (2018-08-03 Edition) When it rains, it pours.Even though no one may really notice. >.> I spent all of Friday evening and most of Saturday completely rewriting our C# Client interface. The current version didn't really mesh with the Client code in our Javascript library, and I wanted similar architectures between the two so that I could write one set of documentation for both APIs. We're now much closer to that possibility. In terms of what this means for you as a user of Buttplug? Right now, not a ton. This is all developer focused work. However, with the ability to now combine docs across languages, it means I can provide guidance to those interested in using Buttplug in their software, which hopefully means more Buttplug software in the future. Think of this as making boring investments now for hopefully more exciting work later. With this also comes the ability to start connecting pieces together in different ways. For instance, I could now rewrite the Game Vibration Router to work on desktop, or connect to our Android app on a phone. We no longer require everything to exist on a single desktop for C# stuff. I'm also hoping this could move us toward exposing a C# GUI on top of the node server, which would finally solidify our Windows 7 support into the same frontend that the Win10 stuff runs on. I'm finishing up this work over the next week, and then figuring out how all of these should be released and documented (which is the opposite order in which things should normally happen but yay open source). --- ## What's qDot Up To This Week? (2018-08-10 Edition) It's been a week of me being angry at me from a year ago, mostly.Work on cleaning the Buttplug C# codebase continues. I'm currently trying to get all of the changes I've made over the past week finished enough to merge the code and figure out what all there is to do after this. This is hindered by me constantly running into something I did in the early months of the project and having to sit there for a while going "What was I thinking?". The nice part of this is that I now have an updated perspective on the state of ALL of the code in Buttplug, which will hopefully mean I can write coherent documentation about it once I finish this overhaul. One of the major goals of this C# work is to make it so I can write one document for developers that has both C# and Typescript/Javascript in it, and that's pretty close to possible now. Things that are left on C# work: - Lots of bug hunting and fixing. I most likely broke a lot of stuff on the way through this, even though all of our tests pass and there's less code than there was. - Modernizing the GVR application. It's the first app I wrote outside of the Websocket Server, and I was in a hurry and slung it together. I'm gonna try to do the minimal amount of work possible, as I'm hoping to start on a new version of our GUI system once this is over. - Generalizing our Serial Port access. Right now, the SerialPort class is made specifically to talk to the ET-312B. I'm hoping I can make a general manager so we can start using Lovense and Vorze USB keys (and DIY arduino toys and...) on Windows. - Playing with Xamarin for cross-platform C# work. Part of my work so far is seeing how much of this I can built in a possibly cross-platform way, but I haven't had a chance to really test that yet. We're much farther along on possibly being able to build iOS/Android apps with C#, though that's still a long ways out for having something actually shippable. Hopefully I'll have something more exciting to talk about soon, but thanks for supporting me during the boring maintenancy times too. :) --- ## The End Of The 268 Teledildonics Patent I took a break from being productive on Buttplug to write a long, rambling blog post about the expiration of the 268 Teledildonics patent, which happens in about 7 minutes from now.I make bad choices sometimes. --- ## Qdot Bbc 5live Interview On Teledildonics I did a quick interview with BBC 5Live. At 3:45am UK time, heh. Luckily it was 7:45pm for me. Above link is my recording of it, please don't redistribute. Actual BBC archive is at [https://www.bbc.co.uk/programmes/b0bfxpfy,](https://www.bbc.co.uk/programmes/b0bfxpfy,) I'm 2:43:00 in. Don't expect to learn much here but you can at least listen to me be awkward! Weekly update coming tomorrow because Holy fuck it has been a WEEK and I just want to sit here and play Yakuza 0 and not talk about teledildonics for a bit. --- ## Whats Qdot Up To This Week 2018 08 17 24 Edition Well at least I have a good excuse for the first 2 week gap I've had in these updates, heh.As you are probably aware because I haven't (been allowed to) shut up about it for the past 2 weeks, the 268 teledildonics patent is now expired. So far this has meant LOTS of talking to press. A few examples: - [https://www.wired.co.uk/article/teledildonics-hacking-sex-toys](https://www.wired.co.uk/article/teledildonics-hacking-sex-toys) - [https://arstechnica.com/tech-policy/2018/08/cybersex-toy-industry-heats-up-as-infamous-teledildonics-patent-climaxes/](https://arstechnica.com/tech-policy/2018/08/cybersex-toy-industry-heats-up-as-infamous-teledildonics-patent-climaxes/) - [https://www.ozy.com/fast-forward/are-you-ready-for-a-sex-toy-revolution/88432](https://www.ozy.com/fast-forward/are-you-ready-for-a-sex-toy-revolution/88432) - [https://www.geek.com/tech/whats-next-for-smart-sex-toys-post-teledildonics-1750177/](https://www.geek.com/tech/whats-next-for-smart-sex-toys-post-teledildonics-1750177/) - [https://motherboard.vice.com/en_us/article/ne55x8/teledildonics-patent-has-expired](https://motherboard.vice.com/en_us/article/ne55x8/teledildonics-patent-has-expired) I really doubt any of you see this will find much of above educational, since you're paying me to write at you about it once a week at a minimum. The attention has still been quite good for the project though, as it was even posted on everyone's most favorite/most hated orange website, Hacker News. [https://news.ycombinator.com/item?id=17781879](https://news.ycombinator.com/item?id=17781879) Anyways, that's mostly died down so now it's back to work. I've been on semi-vacation the past few days at the SF Pen Show (documented at [https://twitter.com/qDot/status/1032720657539260416](https://twitter.com/qDot/status/1032720657539260416) if you're really curious), but with that winding down today and the C# client code at a "done enough" state, I'm planning to get back to writing the developer guide and example code work. There's been more and more interest about how to use the API lately, but outside of a few examples I made for the JS library, there's not really a good guide on how to use any of this outside of showing up on the discord and asking me. Getting that fixed up will hopefully let people work on their own. Other than that, got a few more toys to reverse and add, and hopefully can start looking at restarting the localization project soon so we can support more languages. Since the teledildonics patent is expired, I can also say: Yes, I plan on working on a generalized teledildonics server. The goal is to provide a server that is containerizable so people can just bring it up on VM instances as needed quickly, though I'm also considering other hosting options. While the current setup is pretty good for local connections, I've had lots of requests for things like Second Life, Telegram, Discord, etc support and this is the missing piece there. That's enough of a ToDo list to fill up the next few months so I'm gonna shut up and get back to work now. :) --- ## What's qDot Up To This Week? (2018-08-31 Edition) An update! On time!If you guessed that I don't have much to say, congratulations, you're right!  This week has been more about fighting infrastructure than I would've liked. There's been some lingering breakage in how some of the Buttplug code is tested, and that ended up needing to be fixed and taking a non-trivial amount of time. Nerd speak version: Appveyor CI (windows builds) auth broke after I did the Github org move from metafetish to buttplugio, so our PR checks were never returning correctly. I was just working around it but it turns out other people want to contribute and that was tripping things up, but fixing it was... more of a challenge than I had originally planned on. The gritty details are at [https://help.appveyor.com/discussions/problems/16277-build-fails-on-master-branch-for-unknown-reasons](https://help.appveyor.com/discussions/problems/16277-build-fails-on-master-branch-for-unknown-reasons) That said, some stuff did get added around that work. We now have support for more Magic Motion devices, as well as some other code fix-ups. I'm also working on C# code examples now (for anyone interested, the branch is at [https://github.com/buttplugio/buttplug-csharp/tree/client-examples](https://github.com/buttplugio/buttplug-csharp/tree/client-examples) ) which will hopefully get new developers up to speed on using Buttplug C# somewhat faster, with the main interest there being more Unity work. I'm trying to dig out of infrastructure and maintenance work, but it's a pretty big pile. I'm really hoping that once the C# 0.3.0 release is ready (hopefully within the next month) and in line with the JS library, I'll be able to work quicker across both of them, and these letters will be more about things like new apps and syncydink feature work. :) Thanks for sticking with me through the boring parts! :) qDot --- ## What's qDot Up To This Week? (2018-09-07 Edition) Being in pain, mostly. But in a good way. But not in THAT good way.When I started working on Buttplug in earnest back in April 2017,  I kinda figured that I'd get a little obsessed with working on it and maybe go slightly off my workout schedule. I proceeded to basically not leave my computer chair for like 16 months. Luckily we just got a new gym right near where I live so I'm trying to actually leave the house and be healthy, but that's kinda fucked up my coding schedule since I'm kinda busy being exhausted and complaining about how everything hurts and I want to die. BUT. That doesn't mean nothing got done! Since I rewrote the C# client code, I'm now seeing how the changes feel via writing examples for it. This gives me a chance to refine the code and document it at the same time. Most of this work is happening at [https://github.com/buttplugio/buttplug-csharp/tree/client-examples.](https://github.com/buttplugio/buttplug-csharp/tree/client-examples.) There is now a Buttplug.Examples namespace, where I'm adding example CLI executables with heavily commented code. Like, multiple paragraphs per line. My hope is that once I get these finished, I can use the comments as frameworks for writing examples in other languages, and compile all of these examples into a new, actually useful version of the Buttplug Developer Guide. Once that's done, I have multiple people asking for new Serial Port code, so that they can connect homebrew hardware to Buttplug. This will also allow us to support other estim controllers like the 2B (I have one sitting on my desk right now!), and USB serial connectors like the lovense and vorze dongles. After that, I'm hoping to call v0.3.0 of the C# done and maybe move up the stack a bit to looking at GUI issues and apps. Thanks again for your continued support! --- ## What's qDot Up To This Week? (2018-09-21 Edition) Wow. Completely flaked on an update last week. I blame Yakuza 0.The good news is, I have finished Yakuza 0 and resumed doing other things with my life. Buttplug related things even! I just merged the new client examples into Buttplug C#'s mainline: [https://github.com/buttplugio/buttplug-csharp](https://github.com/buttplugio/buttplug-csharp) The hope is that these examples will help developers learn how to use Buttplug, 'cause otherwise it's been fairly opaque so far. Writing these took quite a while because it was also the first major usage test of the new Client API I've been working on over the past couple of months. I found some problems with this code while I was building the examples, so this became half documentation half bug fixing. I'll be working with some other developers to refine these tutorials, as well as continuing to clean up the Client API and prepare for the C# 0.3.0 release. Exciting times ahead! I hope! 'cause damn if this work ain't needed but kinda boring, heh. In other news: - I just finished giving a remote talk at Teasecraft Boston! This is the first presentation on Buttplug I've ever done, went really well! - I'll be in Toronto in November, speaking at SLSA 2018 ([https://litsciarts.org/slsa18/](https://litsciarts.org/slsa18/) )! My presentation is entitled "Caressing the Tower of Babel: Communicating and Translating Intimate Touch in the Digital Realm", which will be part of the "Quantifying the Body and Its Extensions" panel (this is a media/literary theory/critique conference, hence the titles like this). I have less than 2 months to make something worthy of that title, so I should probably get on that. - Things are pretty quiet otherwise. Got a new piece of hardware in (SenseMax Sense Band) that I'll be checking out at some point. As always, thanks for your on-going support! --- ## What's qDot Up To This Week? (2018-09-28 Edition) Well I've got one hell of a code katamari going on here.Buttplug C# 0.3.0 continues to trudge slowly toward release, gaining more features and fixes all the time. Last week was mostly spend hammering the Serial Port support into a better state, so we can support something other than the Erostek ET-312B. This will include: - EStim System 2b - Erostek ET-232 - Lovense USB Keys - Vorze USB Keys As well as machines people are building themselves, which will be super exciting! Now I'm hopefully down to bug fixes, writing more tests, and code cleanup before pushing this out into the world and getting on with life. (Sex toy development is the least sexy thing) - qDot --- ## What's qDot Up To This Week? (2018-10-12 Edition) Yeah ok at this point it's just time to admit I didn't know what I was doing with C# a year ago and now I'm basically rewriting half of the project to make it actually work like actual C# programmers would actually expect.There. Done. Brutal honesty. Finding all sorts of potential bugs in buttplug-c# as I continue on this deep scrubbing, which is good! There's been messages doing wrong things, unexpected ways to break the system, etc etc etc. It's all good cleanup that will hopefully lead to a glorious future with zero technical debt so I'll never have to do this again. Yup. That will totally happen. Anyways, in other news, took a bit of a side trip last weekend into reverse engineering the EStim Systems 2B unit. Pulled the firmware by just watching the USB line during an upgrade, and some of the electrical engineers I work with are now doing circuit analysis. Not sure where this will actually go, but we'll at least have a better idea of how the 2B functions. Also now looking at the Powerdot exercise unit ([https://powerdot.com),](https://powerdot.com),) which could be interesting since it sticks to the body and is bluetooth. Back to the refactoring mines for now. I've gotten the C# Core and Server done, now it's on to the Client, then hopefully I can start considering releasing v0.3.0. --- ## What's qDot Up To This Week? (2018-10-26 Edition) Being an old man that yells at clouds, mostly.For some reason I decided to go all "IT'S TIME FOR SOME GAME THEORY" on twitter this weekend which ended up as 2 threads about machine learning and blowjobs on twitter: [https://twitter.com/qDot/status/1055865846726152192](https://twitter.com/qDot/status/1055865846726152192) [https://twitter.com/qDot/status/1056377347245465600](https://twitter.com/qDot/status/1056377347245465600) I guess this is what I do instead of blogging now. Other than that, the beginning of the end is almost in sight for Buttplug C# v0.3.0. Now have a couple of developers working with alpha releases of the library to figure out things I missed, hoping that'll be done soon and I can move on to literally anything else. --- ## Buttplug C 030 Released You ever see someone do something dumb and be all "oh yeah I'd never do that thing" then you totally do that thing?I did that thing. Buttplug C# 0.3.0 has been 5 months in the making. For what is basically a one-person project now (I'm working on the core alone at this point, after realizing most of the design for this is in my head and I'm not real great at writing that design down yet so it's hard to ask for help), that is kinda ridiculous. It's been a massive overhaul that could've maybe been done in smaller chunks, but there comes that problem of "what if someone uses it in the middle and I break them with the constant changes". Going silent for 5 months isn't super helpful either though. Anyways, Buttplug C# 0.3.0 is done now, released on Nuget so other developers can get to it. If you're wondering what this means: For Developers: - The whole API is now WAY more friendly to developers. Before 0.3.0 everything was very... raw because I was still figuring out what things should look like. Since that was solidified earlier this year, I could spend a lot of time thinking about how to make life easier on everyone, versus on how the system should even work in the first place. - There are now tutorials in the repo, so people have example code to work from. This is a huge deal, as before this the only examples were the Server/GVR/etc, and those are... not pretty. For Users: - Um. This release don't mean much for users, yet. This is ONLY a release of the library, not the Server/GVR/etc apps. The hope is that since life will be easier on developers now, there may be more apps made using the library soon, which means more stuff for users. That make take a bit though. As for what I plan on doing next, the problem is now too many directions and too little me, heh. - Upgrading the Server and GVR to 0.3.0 (this is priority #1) - While the C# library is out, it's not exactly well tested. There's tests in the library itself, but the real QA happens from other people using it and telling me what they like and don't. So that'll be on-going work. - I am now confident enough in the C# library to really start thinking about Unity work. Luckily I also have Unity knowledgeable devs available to help with that. - More hardware support in C#, including Nintendo Joycons, RealTouch, etc... - I need to bring the JS library up to date with the C# library. Hopefully that won't take NEARLY as long as bringing the C# up to (and past) the JS library, which is what most of this was. - Probably going to write a Python client, because I get LOTS of python requests and already own the Buttplug PyPi package. - I really, really need to get bug fixes out for Playground and Syncydink. For some reason, the Launch won't connect for me on Chrome WebBluetooth anymore, which is a big problem. - More youtube videos! Obviously, if you have stuff you'd like to see me work on, now is also the time to speak up. :) Thanks again for supporting the project through what has been a somewhat content-dry period. I really do hope things pick up after this, both for the sake of that you're all giving me money, and because I could use a bit of excitement myself now. --- ## What's qDot Up To This Week? (2018-11-09 Edition) Well, after releasing Buttplug C# 0.3.0, someone found a bug, so I released 0.3.1 this week! Yay releases that take less than 5 months!I'm also talking to the author of ScriptPlayer about starting to port it to Buttplug C# 0.3 at some point. This would remove the Websocket requirement (as we now have other, more direct ways to connect. If you're wondering, it's IPC over Named Pipes), making connection much easier. We've also identified a Bluetooth chipset that none of our software seems to work with. Qualcomm Atheros Bluetooth (usually built into motherboards on laptops) doesn't seem to work with Buttplug *at all*. I'm not sure what's up, but I've been doing a lot of support on that lately. With that plus the neverending wails of Win 7 users in mind, I've come up with a new, possibly really stupid idea for being able to connect desktops to phones directly. I call it the "Web Relay". Since it ended up being Buttplug Issue #69, it's actually the "Nice Web Relay". You can read more on this [https://github.com/buttplugio/buttplug/issues/69.](https://github.com/buttplugio/buttplug/issues/69.) I'm not sure when I'll get around to it, but if it works, it could solve quite a few problems for people with Android phones and Win7 desktops. Outside of that, I've been trying to put together some general project-wide goals to work on next. I'd really like to get out of the library development side for a bit before the year's end and actually build some apps, but want to make sure I've got the project direction laid out well before I get off on to that. Finally, this week I'm off to Toronto to do my first speaking gig about Buttplug ever! I'll be speaking at the Society for Literature, Science, and the Arts annual conference about Buttplug as a research tool for remote interfaces and communication of intimate information. There's more info on the conference at [https://litsciarts.org/slsa18/.](https://litsciarts.org/slsa18/.) This probably means things will be quiet on the code front for the week, but I'm off for the US Thanksgiving week afterward, so hopefully I'll have some time to work then.  As always, thanks for your continued patronage! --- ## What's qDot Up To This Week? (2018-11-23 Edition) Surviving. Barely.SLSA in Toronto went great. It was my first humanities conferences and I only barely embarrassed myself like, 3 or 4 times, max. I'll be doing a youtube version soon, not that the information will be new to anyone here. Since I got back, I've mostly been back to patching software. Both Buttplug C# and JS got point releases this week to fix yet another schema issue that new versions of JSON schema parsers seem to be picking up now. Yay more strictness, boo having it wrong in the first place. I've now moved to working on the JS libraries again, once again trying to get them in line with where the C# ended up. This should be far less work than the C# library was, like, weeks, not months. After that, plan is to bring the C# GUI applications up to date, then playground/syncydink, then maybe, god, MAYBE do something new, as this year has been a serious grind on just getting things I've already done working right. In other news, I started testing out JoyFunScripter, a free (tho not open source) movie synchronization script builder that showed up on RealTouchScripts a while ago: [http://www.realtouchscripts.com/viewtopic.php?f=59&t=6565](http://www.realtouchscripts.com/viewtopic.php?f=59&t=6565) It's pretty neat! Does a lot of stuff I was/am hoping to do in Syncydink, and the best part is they're testing all sorts of encoding mechanisms, which means I can skip over what they've done that hasn't worked out. I definitely recommend checking it out, as there's a lot of interesting interfaces in the program. Really exciting to see development like this happening. That's it for now. Hope everyone that was having holidays had good ones. --- ## What's qDot Up To This Week? (2018-11-30 Edition) The end of the maintenance period is in sight! I think! Maybe!buttplug-js 0.9.0 went out this weekend, putting the JS codebase in line with Buttplug C#, which now means I can hopefully start on a new version of the Buttplug Developer Guide (the document I'd like to be able to point new developers to on how to use this project) with reasonable expectations of the C#/JS APIs looking mostly the same. This also means I can move on to upgrading the C# and JS user applications (Server, GVR, Syncydink, Playground, etc...), and maybe, just maybe, working on something new. Of course, I'm hemorrhaging Patreon members for reasons I'm not real sure of (I figure probably boredom at the months of my yak-shaving the library), so thanks to those of you still sticking with me. I'd really like to spend December getting more hardware support in, getting applications up to date, and figuring out some new small projects to work on that won't eat months. Hope everyone is braced for whatever holidays you may have to endure. --- ## Where the Hell is qDot? (2018-12-14 Edition) Burnt out, apparently.Not a lot to update on at the moment. I seem to have hit a burnout wall pretty hard a couple of weeks ago and am working my way out of that now. My brain can't seem to make code come out for anything other than my dayjob, so Buttplug dev is going slow. I'm mostly resting (and playing Red Dead Redemption 2) and doing little things here and there, but I don't foresee any major development happening until Christmas week, when I've got lots of time off. In the time when I am productive, I'm doing some video work at the moment to try and get more content on the Youtube channel, and I would really like to have at least 1 or 2 tutorial chapters of the Buttplug Developer Guide up by the end of the year. I'm also stocking up on circuit boards for the MK-312, Nogasm, Venus 2k controller, and other sex hardware projects. If you don't know what those are, well, I'm also trying to make youtube videos about them, so there will be more info on that soon (including a new Tier perk!). That's it for now. Hope everyone is having a less burnt-out time than me. :D - qDot --- ## Buttpluggin With Qdot Qdot Speaks Arse Elektronika 2007 One of the things I've been horrible about is archiving my past presentation work. Now that I've got a youtube channel, I'm aiming to both fix that and also get easy content together that doesn't require much new work on my end. With that in mind, here's a remaster of a sex tech overview presentation I did in 2007. This youtube version is censored in a few places because this is back when I thought it was edgy to throw porn in my slides, but I may have an uncensored version up elsewhere soon. --- ## Buttpluggin With Qdot Live Mk312 Build I'm trying to build an MK312 on livestream. Come check it out! I will probably burn myself on live video! --- ## More Mk312 Bt Building Live Populating board with capacitors. Come check it out! --- ## Mk312 Construction Streaming Live More MK-312 Builds happening now! --- ## Does qDot Even Still Post Weekly Updates? (2019-01-04 Edition) Ostensibly, yes. The holiday break was surprisingly productive. I got a good bit of the "how to write a buttplug application" section of the Developer Guide written, did a few livestreams, posted an old presentation I did on youtube, and started cleaning up the MK312 repo to make it more accessible for people who want to build the board. Not much happened in the way of code, mostly because I'm apparently still a little more burnt out than I thought after the huge C# push through the end of last year. I did start playing with a new version of what will become the Buttplug Server though. Also spec'd out a new idea around using phones as device servers, similar to something like FeelConnect for those of you that are familiar with it, but for local use instead of having to ping through a server. So what's on for 2019? - For those that haven't heard, I'm doing a Buttplug/sex tech related art residency at Carnegie Mellon Univ in March. This will include a lecture and workshop. The first quarter of the year will be dedicated to getting my shit together for that, which means documenting what we've currently got running and figuring out how to make it presentable to students. More info on this at [http://studioforcreativeinquiry.org/events/spring-2019-steiner-lectures-in-creative-inquiry](http://studioforcreativeinquiry.org/events/spring-2019-steiner-lectures-in-creative-inquiry) - Writing stuff other than client/server code. I still very much want to get back to making Buttplug apps myself. Our native support story still blows on anything not Windows (i.e. mac/linux don't have an easy device server to use outside of the browser), which is definitely a problem, but I can't keep throwing all of my time at that or I'm gonna go nuts. - Merchandise! Finally! Damnit! (I've been trying to get around to stickers/shirts for many many years. I will make it happen this year and hopefully they will be donation tier gifts!) - Finally starting on the networking/teledildonics side of this project. This encompasses a lot more than "just control someone else's toy". I'll be writing about it more soon. - Ramping up more video/streaming presence. Streaming is kinda fun, it turns out. - Trying to restore some sort of blog activity. It's been way too quiet for too long over there. Not sure what this is going to look like yet though. That's a rough list, at least. Who knows where this year will end up taking me. I've stopped trying to predict, and instead just put out some vague hopes and we'll see what gets done. Hope everyone is having a good 2019 so far! Keep Buttpluggin'! --- ## What's qDot Up To This Week? (2019-01-21 Edition) New year, new post day because I do most of my work on weekends so doing updates on Mondays seems a little better. New year, new application architecture too! Right now, Buttplug looks like this: - There's a library, but that's only for developers. - There's a "server" application, but it's windows 10 only really (windows 7 isn't worth much). - There's only Chrome web browser support for Mac/Linux/Android. - Nothing for iOS. - Application and Web support have different hardware support. - There's no RPi or other embedded system support, which a lot of people want. - It's all kind of a nightmare to manage. In order to make life suck less for myself AND everyone else, I'm now trying to build a single app on top of web technologies + some native processes that will run on windows/mac/linux/mobile/web. This will replace the "Buttplug Server" on windows, and make it usable even on things like the Raspberry Pi and Windows 7 (though Win 7 will probably require a cell phone too, as my solution is similar to FeelConnect but less reliant on remote services).  To achieve the "Buttplug should only be the name of the library" goal that I've had for a while, this new project is called "Intiface", a name which it shares with the new set of services I'll be putting up to handle things like teledildonics. In the future, "Buttplug" will only refer to the library that accesses sex toys, and applications and services will be under the "Intiface" name. I got the core of this application structure working over the past week, and am now moving on to basic UI. Once I have something that's installable and replicates the Buttplug Server functionality (which doesn't take much, honestly), I'll be posting an announcement here so you can check it out. The Buttplug Developer Guide also had quite a bit of work done on it. I finished the first draft of the "Writing Buttplug Applications" section, and have been working with various people to tighten up the "Ethics" section as it's currently WAY too long. It's feeling really good to be back to writing applications instead of stuck in libraries again, and I'm looking forward to sharing initial work soon! Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-01-28 Edition) Ok yeah Monday works out much better for newsletters. Less panicking about what I'll get done on the weekend after writing it, more panicking about what I got done on the weekend not being worth writing about. Work continues on the new server app, though things have moved slightly farther back into the library yet again. Throughout the past year, I've gotten some requests in relation to how people use the library, and some of these match issues that've cropped up during my own development: - People building their own hardware want an easy way to add simple access without changing code - A cam studio using the software that was having problems with every computer running Buttplug trying to claim every toy it could find in the studio. - Companies releasing new toys with no changes other than identifiers, so all we really needed to do was add new addresses for the hardware but this required changing code and releasing new libraries. - Removing serial scanning because it was screwing with other serial devices, which means we need a way for people to say "I have [this device] on [this serial port]" With *all* of those things in mind, I'm now working on configuration files so that these things can be set up outside the libraries, and possibly changed by users savvy enough to have a text editor and know how YAML works. This is yet another internal library change that I was hoping to avoid, but this will hopefully kill many birds with one stone. C# is 80% done already, I have a feeling Buttplug JS won't take too long either. In application related news, a game using Buttplug was just announced and did their crowdfunding launch! [https://patreon.com/viroclub](https://patreon.com/viroclub) This is a VR game/experience that, when it launches, hopes to have cam models doing real-time mo-cap. Right now they have demos with a couple of pre-recorded scenes. It's using Buttplug for the sex toy interaction, and the devs are on our Discord. That's it for now, back to the YAML mines. Keep Buttpluggin'. - qDot --- ## What's qDot Up To This Week? (2019-02-04 Edition) BUTT SABER So someone popped up in the discord yesterday and was all "Hey could you make the Game Vibration Router work with Beat Saber" and I was like "I'll take look" and well that blew the past 24 hours pretty nicely. The good news is that not only will this be possible, but I should be able to mod most Unity VR games to work with the GVR with the method I've found. This means you can route VR controller haptics to sex toys via Buttplug. The bad news is that it's going to take me a bit more work to get it done and I'm in the middle of finishing up the next C# library release, so it'll be a week or two. Exciting though! For those curious about technical details: I'm just using Illusion Plugin Architecture to patch a hook into the rumble functions that can call out to Buttplug. This is mostly piggybacking off the work of the Beat Saber mod community. The repo is at [https://github.com/buttplug/buttsaber,](https://github.com/buttplug/buttsaber,) but there's not a lot there at the moment 'cause my initial idea of "Try to port the whole buttplug library into the mod" was a total failure. New idea is to just hook haptics and pipe them out to a local network host. Outside of that, the major work throughout the past week was finishing up configuration file implementation, which is now up and running. This should speed up the rate at which we can add protocols and devices to the libraries. So for everyone that's been waiting for Switch JoyCon/RealTouch/etc support, hopefully that wait will be coming to an end soon. I'm now trying to finish up that work by cleaning up the many, many things I broke along the way. No real ETA on that but god I hope it's soon 'cause I can't wait to get back to public facing work yet again. --- ## What's qDot Up To This Week? (2019-02-11 Edition) I wish I had another Butt Saber to talk about here but nope, we're back to library updates. I haven't even gotten to finish writing Butt Saber yet. :( But! Having just finished the Erostek ET-312 protocol fixes in Buttplug C# 0.4.0 alpha this evening, we're close to getting that shipped. We're down to 1-2 more issues, then hopefully shipping that this week and getting back to work on our new Server software to replace the old Buttplug Server. Now that Buttplug C# can load configuration files, this will make updating devices much easier, as well as opening up new ways for people to implement their own hardware to use buttplug. Exciting times! Other than that, the discord has been getting busier lately, with new people showing up and working on things with Buttplug. Hoping to see some new applications showing up soon. Anyways, this has been a bit of a non-update this time around 'cause we're in that awkward pre-release stage, but hopefully more news soon! Keep Buttpluggin', qDot --- ## What's qDot Up To This Week? (2019-02-25 Edition) Being sick for at least half of it. :( But, that doesn't mean work isn't happening! There's been a ton of work on bringing Buttplug JS inline with Buttplug C#, with the end goal of being able to use either engine under the new GUI frontend. Finished up lots of work on that this week, and Buttplug JS is now far more resilient and easier to build than it has been in the past. This means we now have "native" servers on Windows/Mac/Linux, versus requiring using sometimes flaky WebBluetooth support on mac/linux. Throughout the lifetime of the project, I've also had people asking to get Buttplug servers running on a Raspberry Pi. As of last Friday, that's now officially a thing! I got a buttplug-js server up and running on an RPi Zero W, which is a little $10 board with Wifi and Bluetooth. This is pretty huge, as it means we're getting closer to cheap/easy solutions for people who don't have desktops capable for running Bluetooth LE (like the masses out there still running Windows 7). There's also lots of neat embedded projects that could come out of this. The project is still mostly proof of concept right now, but it seems to run pretty well and I have a couple of people testing it out. The end goal is to ship a small embedded box with a web frontend that will hopefully act as an appliance, but there's still a lot of work to get there. If anyone else is interested in trying out the RPi build, either get at me on the comments or on discord ([https://discord.buttplug.io).](https://discord.buttplug.io).) Goal for this week is finishing up the Buttplug JS release, then finally getting back to the main GUI so I can start redistributing all of this work and people can finally move off the old C# GUI. I'm also headed out to Carnegie Melon University to do an art residency, and give a lecture and workshop on Buttplug in 3 weeks, so I'll be working on my material for that. Thanks for the ongoing support, and keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-03-04 Edition) AHHHH I LEAVE FOR CMU IN 2 WEEKS AHHHHHHHHHHH So yeah that's pretty much the inside of my head right now. **Intiface Update** I'm doing a final push to try to put together the first version of Intiface (the new Buttplug Server GUI application) before I leave, in the hopes that I can ship a beta to Patrons and also use it in my workshop at CMU. Things are going mostly well in that respect, though there's lots of weird little bits and pieces that have to be put together (release pipelines, settings dialogs, etc) to make the whole thing work. For anyone curious: The first version of Intiface will mostly do the exact same thing as the current Buttplug Server GUI. The main difference will be that it'll run on Windows/Mac/Linux (and RPi soon after) instead of just Windows. It'll also use our new device configuration system, meaning that I can add devices quickly and easily without having to change a bunch of code and have everyone redownload everything. **Possible Windows 7 Support** Speaking of platform support, I've got some possible good news for those of you who've been waiting for Bluetooth LE Hardware Windows 7 support for the past, uh, 2 years. It may possibly happen! Companies like Lovense and Vorze have put out USB keys for their devices in the past to make them work on anything that supports USB Serial Class devices (Which goes back to WinXP if not before). Thanks to someone on discord earlier this week, I was pointed at a generic USB Serial BLE dongle by BlueGiga with an Open SDK! [https://www.silabs.com/products/wireless/bluetooth/bluetooth-low-energy-modules/bled112-bluetooth-smart-dongle](https://www.silabs.com/products/wireless/bluetooth/bluetooth-low-energy-modules/bled112-bluetooth-smart-dongle) These dongles are available from $10-20 depending on where you buy them from, which is totally reasonable. I have a few on the way now, and will be trying to implement Buttplug device subtype manager support on them ASAP (which doesn't mean a ton since my schedule is nuts through late March), as having this available means we can cover BLE hardware support on platforms where an OS API might not work out. **Everything Else** Once Intiface is at least into Beta, I'm hoping to get back to the GVR, Syncydink, and other applications. It's been hard to work on those since I was hamstrung by my own server software and libraries, but I think we're almost out of the woods on that. Thanks again for your continued support, and Keep Buttpluggin'! - qDot --- ## Intiface Desktop 001 Welp. Here we go: [https://github.com/intiface/intiface-desktop/releases/tag/0.0.1](https://github.com/intiface/intiface-desktop/releases/tag/0.0.1) The first user focused (versus developer focused) release in something like 10 months. Intiface is the new brand for the desktop and mobile apps I'm building on top of Buttplug. Buttplug was originally supposed to just be a library, but as many of you have heard me repeat too many times already, I moved slightly too fast and just started calling the server software Buttplug also. This poses 2 problems: - People don't like actually *installing* a thing named Buttplug - There's no way we're getting a product named Buttplug into app stores, ever. Intiface isn't quite as catchy as Buttplug, but you can rest assured, Intiface has Buttplug in it. As for Intiface Desktop 0.0.1: Intiface Desktop is the new Buttplug Server. The major difference is that it's violently cross platform, meaning that it can run on Windows/Mac/Linux, and soon even RPi.  Right now this is pulled off via Electron, meaning the executables are... large. Like 25x the size of the Buttplug Server. Such is life in Electron. :| For those of you that are already cursing me for using Electron but happen to be still reading: There's another solution coming. I'm building another version of Desktop that will run on a local webserver, so you can access it through a browser. This is also the version that will run on an RPi, so you can set it up to be dedicated listening hardware.  If you hate GUIs of *any* kind, all Intiface does is run a command line program in the background, so you can just write your own scripts to do that too. Those executables are downloadable as releases from buttplug C# ([https://github.com/buttplugio/buttplug-csharp/releases)](https://github.com/buttplugio/buttplug-csharp/releases)) and buttplug-js ([https://github.com/buttplugio/buttplug-js/releases).](https://github.com/buttplugio/buttplug-js/releases).) It's recommended to use C# on windows, JS on anything else. Right now, Intiface Desktop 0.0.1 has almost all of the functionality of the Buttplug Server: - Can listen on insecure/secure websocket ports (On Windows/Linux/Mac) - Can listen on IPC (windows only for now, and really not even sure if it works) New features include: - Can update the Buttplug Engine (the part that actually talks to hardware) separate from the app. - Runs on the latest version of Buttplug JS or C# (depending on platform), which I released last night. - Has a setup flow, including secure cert acceptance, though you may not need it (see Secure Cert Update section below). Future plans include: - Ability to list supported devices (YES REALLY) - Ability to run a Proxy Server (connect from desktop to android phone, similar to FeelConnect, but local) - One day, connect to and act as a gateway for online services that still need to be written. >.> The UI is still an absolute mess, but that's due to be fixed as soon as I have time. This release is mostly because I'm teaching a workshop using this next week and so I need something *now*. On this point, the app current starts in "Advanced Mode". I'm trying to make a "Simple Mode" where setup of the whole server is done in sentence form, versus random checkboxes and lists, but that's not quite ready yet. If you've worked with the old Buttplug Server, Advanced Mode will be basically familiar. The app also lacks self update capabilities. A preliminary version of this that just tells you to download the new version is coming soon (possibly next few days), with a full version that can update itself in place coming once I figure out how code signing certificates work (possibly next few weeks). While 0.0.1 is out, I'm not really announcing it publicly yet because I expect there to be an absolute ton of bugs. If you decide to try it and find any issues, please let me know by commenting here, poking me on twitter/discord, etc... While I could totally use a break after this release, it's not gonna happen. I leave for CMU tomorrow, will be posting updates from there! Keep Buttpluggin' (hopefully with Intiface now)! - qDot --- ## Intiface Desktop 001 Maybe Wait On That Ok well it turns out the code signing thing is going to be a bigger problem than I thought on Mac and Windows. My initial tests worked because I was running against a locally built server and didn't realize it. As soon as I cleared my config and downloaded the server through the app (as everyone else is doing), almost nothing works due to downloaded app privilege restrictions. I'm trying to figure out some workarounds for this now, but until then, if you're experiencing issues on Mac and Windows, that's (part of) why, and the errors being thrown aren't caught, so things fail very silently. If you're running Linux, Intiface may still work depending on which distro you're on. More updates once I figure this out. :| --- ## What's qDot Up To This Week? (2019-03-18 Edition) I'm in Pittsburgh! Got in on Sunday. Spending the week working on my new sex tech workshop curriculum, then getting back to unfucking Intiface once I get back. Super busy so a short update this week, but lots of exciting things happening! Keep Buttpluggin'! - qDot --- ## Apologies To Everyone Who Just Got Force Joined On Discord I was updating the tiers for this patreon campaign and didn't realize that if I change the patreon rewards, the bot will force-join everyone currently signed up that has a discord account linked. I totally didn't mean for this to happen, so apologies. Now headed to the patreon creators forums to send a strongly worded letter about this. :| --- ## What's qDot Up To This Week? (2019-03-25 Edition) Survived Pittsburgh. Now back at home and trying to make body adjust back to my normal timezone. # Stickers! Yes! Actual physical tier rewards! I'll be adjusting it this week, but from now on, anyone who donates $3/month or more will get 2 stickers mailed to them after their first successful payment (assuming they want them)! Images of the stickers are attached at [https://pbs.twimg.com/media/D2Y5TpnU8AUJ01R.jpg:large](https://pbs.twimg.com/media/D2Y5TpnU8AUJ01R.jpg:large) because patreon is being weird. Of course, I wouldn't want to forget the rest of you who've already been donating forever with little to show for it other than getting to read my personal updates (well ok and getting to use the software it funds). I'll be sending notices to everyone who's donated >= $3 over their patronage to me. Yes, this includes $1/month people who've been donating for a while! Consider it a perk of getting on the qDot train early. This first batch of stickers was a last minute deal, and I do plan on having more printed soon with different designs. But I'm still pretty happy with how these came out. # What Happened In Pittsburgh Almost all of my time in Pittsburgh was spent writing my presentation slides and workshop materials, as well as talking to a ton of people. There will be a recording of the talk up sometime in the future, though it may take a couple of months due to lack of resources on CMU's end. I'm hoping to do the talk more often though, so it may get either recorded again or else I may just end up doing it in other places. Or both. Workshop was the first time I've presented Buttplug in public, and it went decently, all things considered. Only had about 30 minutes about code, most of the workshop was focused on familiarizing attendees with different hardware types and interfaces. Everyone seemed to enjoy it though. There's some photos from the talk and workshop up at [https://www.flickr.com/photos/creativeinquiry/albums/72157690345973723.](https://www.flickr.com/photos/creativeinquiry/albums/72157690345973723.) If you'd like to have me speak or host a workshop where you are, please let me know! Now that I have some material written this is actually an option. # Intiface I tried releasing Intiface before I left and that turned into a major clusterfuck. No code work happened last week, so I'm going to try to get this back on track over the next week or two. The code itself *works, *the problem is that when it's built on CI and uploaded to github, it's not cryptographically signed, and Mac/Windows require that. I've got solutions for both Mac and Windows, they're just different and take some time to set up, which I didn't have before I left. I'll be posting updates about this as it happens, as I'd really like to get everyone moved off the Windows Buttplug Server ASAP. # Other Stuff Since Intiface is at least close to shipping, I'm hoping I can start dividing work between getting the GUI updated, starting to update Playground/Syncydink, and maybe starting to implement new features like input messages in Buttplug. Lots of exciting stuff ahead! Just gotta shake this jet lag first. Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-04-01 Edition) Another week of Buttpluggin' updates! # Stickers Ok, well, I put out a call for stickers as tier rewards, and... 8 people replied! So that's less than I was planning on, heh. For those that did update your addresses, thanks. For those that haven't yet and are on the $3 or higher tier: - Yes I will ship stickers internationally. No it will not cost you extra. - If you don't want to put your mailing address into your Patreon account, you can either message me with it, or just email it (kyle@nonpolynomial.com) or DM it to me on twitter ([https://twitter.com/qdot)](https://twitter.com/qdot)) or something.  - For those of you who are on the $1 tier but have donated for 3 months or more, you're gonna have to send me your address manually using one of the above methods. - If you haven't entered your address because you're just not interested in tier rewards, that's also fine, please continue ignoring this. :) I'm probably going to print another round of stickers soon. May post a poll on what stickers patrons would like, 'cause I've got way too many options as is. # Intiface Now that I'm done with presentation and workshop preparation, I'm back to working on Intiface.  The good news is, my code signing certificate came through, so now all of my Windows binaries and nuget packages are code-signed! Basically this just means that it's harder to spoof them. Not that I really plan on people doing that, but with the context of Buttplug, it's something nice to have covered anyways. Intiface Desktop is now at v2, but I'm still not sure I'd recommend running it yet unless you like being on the absolute questionable-sanity bleeding edge of things. It only works on Windows at the moment (Linux support should be fixed again soon, Mac is... gonna take work, due to more code signing issues with node.), but it does at least basically sorta kinda work. I'm still hammering out basic UI problems right now, so there's lots of things that can lock up UI wise. Now that all of the build crap is done, it's coming along pretty fast though. Once I feel it's like, actually usable, I'll be sending out a post specifically telling people to start banging on it. # Buttplug Buttplug is also getting updates as Intiface gets built. Just released a new version of the C# library with more LiBo hardware support, as well as some fixes to rather serious bugs involving device reconnection. Javascript will hopefully get some catch-up patches soon, I just want to get Intiface shipping on at least one platform first. # Possible New Exciting Hardware Soon! A really neat sex tech hardware project I've been watching for a couple of years is finally coming to fruition. I'm hoping I'll have more to say on this in the next few weeks, but for now teasers are all I've got. :) # Everything Else - I actually updated Playground right before Pittsburgh, it's now running on Buttplug 0.11, which supported the hardware I was using in the workshop there. - Once Intiface Desktop is shipping (aiming for end of April for all platforms running at least something on Electron), hoping to update Syncydink, Playground, and the components they use. Those were written in the early days of the project, and really need an upgrade - Kinda not sure what to do about Metafetish these days. I have like zero time to write at the moment. I'm also not really getting information out efficiently, so blogging seems like it'd be a good idea. Can we add 6-8 more hours to the day? - I have a pile of Youtube videos I'd also like to get started on, but see prior comment. That's it for now. Until next week, Keep Buttpluggin'! qDot --- ## Intiface V7 Win 10 Only Released And Updates On Projects The newest version of Intiface for Windows 10 is now ready to download at [https://github.com/intiface/intiface-desktop/releases/tag/v7.0.0](https://github.com/intiface/intiface-desktop/releases/tag/v7.0.0) For those of you that downloaded an earlier version: Do not try to use the application update system inside Intiface. It won't work (and still doesn't in v7). I'll hopefully have that fixed once and for all in v8. This is basically a fully functional replacement for the old Buttplug Server at this point, but it's really not much more than that. Now that I've at least got the base done, I'd like to have testing happening while I work on new features. Here's the status of some upcoming features. # Linux Support Linux support should be back pretty soon for Intiface Desktop. I've gotta fix up the node.js buttplug engine and figure out how to have the user allow the proper caps for bluetooth, but otherwise it should be ready to go. # Mac Support Mac support on the other hand... ugh. Apple has done their best to make it really, really hard to release software for macOS that was not built solely in XCode (which none of mine is). I'm trying to figure out a solution for signed binaries right now, but am hitting multiple blocks that may take a bit to figure out. # Express (HTTP Server instead of Electron) Support For everyone that hates electron or wants all of this to run on a Raspberry Pi, I've built the system so it should run in a web browser backed by a specially built web server. This is still extremely proof of concept, but once we have desktop linux compatibility up and running, that'll get us most of the way to being able to run Intiface on a local web server. This should work across all platforms, but probably won't be the way I'd recommend running Intiface on desktop unless you know what you're doing. # Proxy (aka Win 7 Support, Assuming You Also Have An Android Phone) The first new feature I'll be adding to Intiface is known as the Proxy. This is to give people with an android phone a way to talk to bluetooth LE toys from a desktop. The workflow will look something like: - Load a special webpage on your android phone that looks pretty much like the Buttplug connection sidebar for Buttplug Playground ([https://playground.buttplug.world).](https://playground.buttplug.world).) Connect to Intiface Desktop through this using websockets. - Now you can use any Buttplug desktop app (Syncydink, Scriptplayer, etc...) to connect to Intiface also, and it'll forward device commands to the phone. Still not quite a elegant as having an actual mobile app, and you'll need your phone and the desktop on the same network for all of this to work, but it's a decent stop gap for now that can allow sex hardware to work with no app store downloads required. # Simple Movie Hosting This will just be a way to host movies and script files on a desktop so they can be accessed on a phone or standalone VR headset in Syncydink without having to move the huge files to the phone/headset. Trying to remove the barriers to watching hardware sync'd VR for those that don't have a full VR rig available. # GVR v2 The first application I'm planning to build outside Intiface is v2 of the Game Vibration Router. It'll mostly be v1 with a shiny new skin, plus a couple of extra features for dealing with the VR game mods (like Beat Saber) I've been working on. # Syncydink and Playground I've learned a LOT more about Vue and app development while building Intiface, so I'm hoping to circle back and update Playground and Syncydink with those skills at some point within all of this. # Mobile Apps Since Intiface is built on web tech, I'm hoping I can take the frontend work I've done, scale it for mobile screens, and maybe integrate it with something like NativeScript to make mobile apps. I highly doubt this will Just Work, but it'd be nice if it did. # Intiface Online Yes actual teledildonics are coming, especially now that I have a flexible desktop app to connect thru. This may take a while tho, as there's a lot of unfun stuff like server images and user systems to build first. That's it for now. I've been doing Intiface releases every few days at the moment but have been waiting to get to a stable point to announce things here, so I'll probably start making update posts here more often. Lemme know what you think! qDot --- ## What's qDot Up To This Week? (2019-04-08 Edition) Ok, well, I'm a day late this time, but I have a good excuse because... # Intiface is ready to try again! At least, assuming you're on Windows 10. I'll be sending out the announcement post after this one, but I just finished Intiface v7, which basically puts Intiface at feature parity with the old Buttplug Server application. I'm still not announcing the release publicly quite yet because I've got more features and testing I'd like to have happen first, but we're creeping that direction at least! Anyways, will leave the rest of that info for the update post after this one. # Sticker Shipping After some issues involving patreon payouts, I think I've gotten everything sorted, so stickers should be shipping to those of you who's address I have either via patreon entry or patreon message by the end of the week. Anyways, since most of my work has been happening on Intiface, and I'll be sending another message about that in a sec, I don't have a lot to say in this weekly update.  Until next week, Keep Buttpluggin'! qDot --- ## Intiface V11 Win10 Only Released [https://github.com/intiface/intiface-desktop/releases/tag/v11.0.0](https://github.com/intiface/intiface-desktop/releases/tag/v11.0.0) Ok so you may have noticed that last night I made a "Intiface v7 Released" post and it's 22 hours later and we're already to v11. Yeah, that sucked. After fighting with the installer builder, as of v11 application updating now actually, mostly, sometimes works. No more having to download binaries from github. That's basically the only change, but it's a big one. Also, the updater uses differential based downloading, which is a fancy way of saying it'll only download the parts different from what it already has. This means you may download like, 2-3mb instead of 90mb (yay electron). That's it. Hopefully at least a day or two between this and v12 now. --- ## Intiface V13 Released Mac Linux Support Returns After much wailing and gnashing of teeth, I got Mac/Linux support back into Intiface. MacOS seems to work fine, Linux takes a little extra work (see the README: [https://github.com/intiface/intiface-desktop](https://github.com/intiface/intiface-desktop)#linux-issues). Releases for all platforms can be downloaded at [https://github.com/intiface/intiface-desktop/releases/tag/v13.0.0](https://github.com/intiface/intiface-desktop/releases/tag/v13.0.0) Now that I've got all the platforms building and basically sort of working, time to add some new features (oh and probably finish the UI since there's things that are still missing, like the explanation of cert setup, and the whole about page, etc...) --- ## Buttplug Put To Good Use This is what happens when I get bored. Connected a bluetooth bouncy ball to Buttplug. Youtube video (and update email that I missed yesterday) coming soon. --- ## Buttplug Ios Sorta Dont Get Too Excited Someone poked me on twitter about trying Buttplug using an iOS app that polyfills WebBluetooth: [https://twitter.com/mathemagie/status/1122211992197128192](https://twitter.com/mathemagie/status/1122211992197128192) This of course spun me off into actually trying to get this to work, and now it kinda does. If you have an iPhone or iPad, you'll need this app (which is annoying $1.99, mostly to help the developer pay for their $99 annual apple license): [https://itunes.apple.com/us/app/webble/id1193531073](https://itunes.apple.com/us/app/webble/id1193531073) then, in that app, check out: [https://5cc621823514cb8231ad0282--buttplug-playground.netlify.com/](https://5cc621823514cb8231ad0282--buttplug-playground.netlify.com/) I've tested it with the Fleshlight Launch and Lovense toys, they both seem to work, assuming you can ignore parts of the UI not working because in-app WebKit is horrible. This means that Playground and Syncydink could work right now, which is nice for demos, at least. More importantly, now the new Proxy app I'm working on (that allows you to pair desktop and mobile devices so you can use your phone as a bluetooth relay) now works on both Android and iOS. --- ## What's qDot Up To This Week? (2019-04-29 Edition) Been a while since I've given a weekly update, mostly because I've been giving piecemeal project updates, so, without further ado... # Stickers Getting reports that people around the world are receiving their stickers now! If you haven't either added your address to your patreon account, or messaged it to me through Patreon messaging, and you're donating at the $3/month or higher level, get at me! # Buttplug Things have been busy on the library side of the project. - Due to many, many requests, I've started a python version of the client library. It's now mostly together, and can enumerate devices, send commands, etc, though there's not a lot of error checking/handling. The repo is at [https://github.com/buttplugio/buttplug-py,](https://github.com/buttplugio/buttplug-py,) and I have the "buttplug" Pypi package squatted currently. I'll hopefully be publishing a full version of the package soon. It's currently VERY heavy on the py3.7 features, I'm going to look at trying to backport to 3.6 if enough people yell at me about it. - I'm finally starting to add new messages to the protocol, including our first shot at input messages! This means we'll be able to receive information from devices as well as send it now. The first two input messages will be for BatteryLevel and RSSILevel, so we can check for battery power and signal quality on bluetooth toys. Future messages will include accelerometer data, squeezing sensors (for kegelcizers), etc... - Buttplug iOS is now, oddly, a thing, though not in any easy sort of way. There's a special browser you can get from the app store (for $1.99 [https://itunes.apple.com/us/app/webble/id1193531073)](https://itunes.apple.com/us/app/webble/id1193531073)) that implements WebBluetooth. I made a couple of patches to buttplug-js to make things mostly work with it, and sure enough, I've managed to control Lovense toys and the Fleshlight Launch from it. It's mostly on par with what we can pull off in Android Chrome for now, so if you've wanted to control sex toys from an iPhone or iPad, we can now do that! - I have patches from a contributor to support the Lovense USB dongle in the C# library. It's going to take some work to get those added, but once that's done, we'll be able to support Lovense toys on any machine that can do USB -> Serial and use the C# libs. # Intiface Things have been similarly busy over in Intiface, the user facing portion of the project: - As I mentioned last week, we can now ship on all platforms. Windows was already working, Mac somehow miraculously works, and Linux works as long as you're cool setting some capabilities on the engine executable in the file system (which, if you're running linux, you should be) - All work now is mostly related to getting things publicly releasable, as I have to have Intiface shipping in place of the old Buttplug Server before I can start shipping the new features like Battery Levels. This mostly involves lots and lots of UI polish. - The last feature I'm adding before release is the Proxy server, which will allow users to bridge from a desktop to a mobile phone in order to use the bluetooth on the phone to talk to toys. This means you can use something like ScriptPlayer on the desktop, which will connect to Intiface Desktop, then have the Buttplug Server running in a webpage on your phone, which will also be bridge into Intiface Desktop, so ScriptPlayer can control toys connected to your phone. Now that Buttplug works on iOS and Android, I'm hoping this will be the bridge we need for remaining Win7 users, as well as users that are just having problems with desktop bluetooth otherwise. Setup for this is... not trivial, but people seem to be motivated by the goal of having control of their toy. :) # Other Projects - I already posted the stupid bluetooth bouncy ball project. That was so amazingly dumb. I really need to do more stuff like that. ([https://www.patreon.com/posts/26324105](https://www.patreon.com/posts/26324105) if you missed it) New youtube video coming about this project as soon as I can get some time to film. - I tried an experiment with week with embedding Buttplug in bookmarklets, meaning you can have a button on your bookmarks bar that allows you to inject Buttplug into certain pages. This would allow you to do silly things like sending stock/bitcoin prices as vibration commands based on dynamically updating pages. More on this project soon. - I'm also working with the author of the Overwatch Healslutting software in order to integrate Buttplug into it. They currently only run with Lovense toys, so this will allow them to branch into the 100 or so pieces of hardware we support now. - I'm hoping to get back to porting the Game Vibration Router and integrating BeatSaber support again soon. Oof. Things are busy around here! Thanks again for your support, and until next week, Keep Buttpluggin'! --- ## What's qDot Up To This Week? (2019-05-06 Edition) Getting a new job! And thus, fuck-all happened on the project this week, codewise, because engineering interviews are the fucking worst. Anyways, yes, I'm changing dayjobs, which is going to possibly cause a bit of upheaval and slowdown in project progress for the next month or two as I readjust to a new schedule and new ways to spend 8 hours a day after being at the same company for 7.5 years. That said, I'm going back into the firmware/embedded world, with a focus on CV/ML, so that'll be super exciting! However, I'm also going back into the startup world, which is scary af, so we'll see how this turns out. # Buttplug Despite the insanity of the past couple of weeks, I did manage to get another version of buttplug-js out, with support for the iOS BLE app. We now at least have *some* foothold on every major desktop and mobile platform.  # Other That library upgrade is about all I've been able to manage at the moment. Main goal for now is still to get Intiface (the new Desktop Buttplug Server app) shippable to everyone. In closing, check out this new project that uses Buttplug! [https://www.youtube.com/watch?v=mHtRNL8itHI](https://www.youtube.com/watch?v=mHtRNL8itHI)  'til next week, Keep Buttpluggin'! - qDot --- ## Intiface Desktop V14 Released Managed to break through my coding block a bit to get the new version of Intiface Desktop out. [https://github.com/intiface/intiface-desktop/releases/tag/v14.0.0](https://github.com/intiface/intiface-desktop/releases/tag/v14.0.0) Nothing real groundbreaking in this release, mostly just some insignificant UI updates and fixes. Mostly wanted to get the Home panel in, and the About panel populated a bit. Hoping that we're near the end of private alpha and can start looking at a public alpha soon. Mostly I just need to update the tutorial, and possibly add some documentation/tutorials to the program itself. Been working on the features for Proxy alongside this, so I'd like to get that integrated soon too, so we can start supporting things like standalone VR headsets via having them connect to laptops/desktops (and later, phones) for bluetooth access. --- ## What's qDot Up To This Week? (2019-05-20 Edition) I'm jobless! Now working on Buttplug/Intiface full time! For a whole week! Then I have another job! Unfortunately, it turns out I may be a little obsessed with game modding now. # Game Vibration (Haptics?) Router A couple of months ago, someone contacted me about modding VR games for Buttplug, similar to how the old GVR project worked for non-VR games. They're specifically interested in Beat Saber. I created a "Butt Saber" repo, and got a good bit of the way there, until I hit some roadblocks with the Buttplug libraries and the old Buttplug Server. That put things on hold until I could finish those up. Now that those are working ok, I decided to revisit the project. My original project was aimed specifically at Beat Saber, but I realized that the functions I was looking for were actually Unity functions, not specific to Beat Saber. That meant I could possibly generalize the mod to work with ANY Unity VR game. I've spent the past week reworking things and it looks like the solution I've come up with may be viable. It'll attach to both older and newer unity games, and doesn't require replacing executables or putting files in the game install directories, everything is done cleanly via remote process hooking. I'm hoping to have a first version out by the end of this week! Also, as the header for this section says, the title may end up changing. This could easily grow into a full game mod engine versus just vibration rerouting, meaning we could also trigger linear movement in things like the Fleshlight Launch, rotation in the Vorze A10, etc. # Intiface Desktop Proxy mode in Intiface Desktop is coming along, it's now mostly down to fixing some breakage in the JS/Node libraries. Hoping that'll be following on the heels of me finishing the GVR. This will also come along with the actual release of Intiface, which mostly means I'll be redirecting people from download the old Buttplug Server to using Intiface Desktop. # Buttplug And of course, now Buttplug is stuck behind both of these. The next major upgrades to Buttplug deal with new messages, which means the old Buttplug Server will become obsolete and unusable. Everyone needs to be moved or moving to Intiface Desktop before then, so I gotta have that done first. The joy of Yak Shaving Factories. :| Anyways, that's it for this week. I'll hopefully have a GVR installer announcement out soon.  Until then, Keep Buttpluggin'! qDot --- ## Intiface Game Haptics Router V0 Released It... basically works. Sometimes. And only for certain games, and only via steam games right now. But it worked enough to make a video! [https://ghr.intiface.io](https://ghr.intiface.io) to download. --- ## Qdots Cmu Lecture Is Now Online My artist lecture as part of my March 2019 residency at Carnegie Mellon University is now online (and captioned)!  If you weren't able to make it there to see it, now you can watch it at your leisure. --- ## What's qDot Up To This Week? (2019-05-27 Edition) Well, I'm definitely not jobless anymore. More just energyless now. But before we get to that, let's go over what happened while I was funemployed last week. # Intiface Game Haptics Router I finished up the redo of the Game Vibration Router, now called the Game Haptics Router. The currently posted version works with both VR and XInput again. It still needs some cleaning up, and I still want to get Linear movement support (for things like the Fleshlight Launch) in, but all in all it had a pretty successful release, and I was just happy to play with some applications using Buttplug again versus just writing the library. # Buttplug Buttplug itself got a couple of updates, mostly related to Hardware support. After many pokings and demands from users, I finally got Kiiroo Onyx 2.1 support into the library. It's not perfect, but Kiiroo makes it REALLY hard to interact with their toys, and it's a good enough stop gap for now. # Intiface Desktop Weirdly enough, I didn't really touch Intiface Desktop at all during the past week or so. It just kinda continues to chug along, doing what it's supposed to. The Buttplug updates were releases as new engines that it just downloads and updates for users automatically, which is pretty awesome. The new goal is to finally deprecate the old Buttplug Server 0.2.3 completely and move everyone to Intiface Desktop. Major blocker on this is rewriting the Buttplug Tutorial into an Intiface Tutorial, and bringing up the Intiface domain as a landing page for the new software (so users no longer go to buttplug.io and it can be a developer focused site). This will happen... someday. # The Now And The Future So, now we get to the big question: WTF is the future gonna look like now that I've got a new dayjob? Honestly, I dunno. I mean, I'm not dropping Buttplug or any of my other projects (I even worked this out with my new job as part of my discussions with them). But I'm also not sure how long on-boarding and schedule readjustment is going to take. I've been working from home for the past 6+ years, so this whole going to an office again thing is new, and I'm now involved in a lot more hardware work, which means not as much time sitting in front of machines. I'm sure things will even out at some point, but things may slow down a bit for the next few weeks while I figure all of this out. What I'm hoping for and trying to plan on is a realignment of priorities for Buttplug and Intiface. I kinda had a *lot* of time to work on shit over the past couple of years, which meant I could kinda meander around and maybe take too long in order to get things just right. With a reduced amount of development time/energy, I'm going to be forced to focus on the important things and getting releases done as I can. So who knows, this may work out better in the end. But good god I just need to sleep for like 14 hours right now. Anyways, thanks for your continued support, and until next time, Keep Buttpluggin'! - qDot --- ## June 2019 Qa 3 Tier Perk I haven't done a Q&A in a while, so if you've got any questions, ask away in the comments to this post! --- ## What's qDot Up To This Week? (2019-06-10 Edition) Somehow still managing to work on shit! New job is definitely busy, but I'm still managing to keep up on Buttplug/Intiface dev around it, which I'm pretty happy about. I figured I'd get nothing done over here in the first month or two, but things seem to be chugging along nicely. # Intiface Desktop As of June 1st or thereabouts, Intiface Desktop is now the official platform for Buttplug users. I went ahead and deprecated the old Buttplug Server, though I haven't completely removed downloads. I may just leave it there for history sake, but once I start adding new messages to the protocol, it'll stop working altogether. This did come at the cost of having a tutorial that's now out of date, so I'm trying to work quickly to replace the old Buttplug tutorial with a new shiny, simpler Intiface tutorial. I'll no longer be using Twine, since our platform story is a little more unified than it was when I put that together, but I'll still be updating the Twine library for use in games. # Buttplug Web Apps (Playground/Syncydink) Since Intiface Desktop can host on multiple ports at the same time (versus the binary ssl/no-ssl thing we used to have in Buttplug Server), I'm also now working on simplifying the connection dialog for Playground/Syncydink, and will be using that as a UI example for app developers. I've learned that most of the time, users will just be using localhost and default ports. It's easy to try to connect to all of those and just pick the first one that works, so we shouldn't require users to know IPs and port numbers unless they're trying some sort of special setup. Not only that, usually the first thing you want to do after connecting is scan for devices, so connecting will now automatically start scanning (this can be turned off via settings in the applications). The goal is to make getting started actually USING a buttplug application quicker and easier.  This new UI will also make it easier to extend functionality on applications, for instance, making it easier to build a playlist mechanism into Syncydink. Expect to see this new UI in Playground and Syncydink sometime in the next couple of weeks. # Buttplug and Unity A couple of weeks back I worked with someone to test feasibility of Buttplug on Unity. Right now the biggest barrier is NJsonSchema, the library we use for message structure parsing. It's more of a nice to have than a requirement, so I'm now working on dividing out all of the Json stuff into its own library, into a new library type I'm calling "serializers". Alongside that, I'll be adding another serializer specifically for Unity's built-in JSON serializer, so hopefully we can integrate Buttplug Clients with Unity, with no outside dependencies. That'd be pretty sweet. I've also started discussions with a few VR game devs/communities like: - Virt-A-Mate - Besti - Dominatrix Simulator So that once the Unity capabilities are up and running, we can start looking at integration. Exciting! That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## Early Access Youou Av Vibrator Unboxing Video Hey I finally remembered to do early access on a video for once! Here's the new Youou AV Vibrator Unboxing video I just made, completely with spiffy new After Effects Lower Third animations because I'm a dork. This doesn't go public until tomorrow, so you can all rush to buy a crappy cheap bluetooth vibrator before the masses find out! --- ## Video Prepost Apathetic Handjob Part 1 Before the world gets to see it! Whether this is a good thing, I don't know. Posted context free because THIS IS WHAT YOU ARE PAYING ME FOR. (Ok a little bit of context. After years of threatening, I'm finally putting together a video series on hardware sync with... video. I needed a demo video to start with, so this happened.) --- ## What's qDot Up To This Week? (2019-06-24 Edition) So remember when I was all "Wow I can still code during new job! I can't believe I haven't hit a wall yet!" Guess who hit the wall. # Software (Intiface/Buttplug/Etc) Yeah there's almost nothing to say here. I've done a tiny bit of cleanup and maintenance but nothing much to speak of. Schedule changes finally caught up with me and it's been hard for me to get in the coding groove for the past couple of weeks. This means a lot of stuff like the new Intiface Tutorial, new web app widgets, etc... are sitting half done currently. That said... # Buttpluggin' With qDot Videos When God closes a buttplug shaped door, they open a buttplug shaped window. For some reason I decided it was time to make videos, which is why the Youou AV Vibrator video happened last week, and now I'm in the middle of production on the first of what is going to be a very long series on hardware video sync. I consider this project documentation, so it's nice to feel like I'm still getting stuff done, even if it's not code. # New Pornhub Account Since Youtube has also been rather scattershot in their regulation of content lately, I'm trying to set up some insurance just in case my YT account gets axed. While it's not a place I'm super fond of due to lots of reasons, I've caved on my ethics and created a Pornhub account, and am uploading Buttpluggin' With qDot videos there. Please subscribe/friend if you've got an account! [https://pornhub.buttplug.io](https://pornhub.buttplug.io) # Upcoming Tier Reward Changes Also of note, next month I'll be announcing some tier reward changes, including at the rather popular $1/$3 levels. Don't worry, I'm not going to yank rewards that anyone currently enjoys, but I've needed to redo stuff for a while (a lot of the rewards go unclaimed/unused) and it's finally time to refine things a bit. I'll be announcing this sometime after the July rollover, so it won't take effect until August. # Discord I've been getting reports that the Patreon discord bot is acting up, so if you join the discord and don't get a Patron role, please poke me. If you haven't joined the discord yet, well, you should join! [https://discord.buttplug.io](https://discord.buttplug.io) That's it for now. Hopefully the Video Sync Intro will be done in the next few days, and as patrons, you'll be the first to get a peek at it! Until next update, Keep Buttpluggin'! - qDot --- ## Apathetic Handjob Video Preview With Correct Link (Sent the wrong link in the last post, sorry about that) I cannot believe I am posting this. Still unlisted, as I gotta finish up the funscript for it tomorrow. And also figure out how much of a career limiting move this is going to be. --- ## Sex Toy Video Sync 101 Video Preview I've still gotta finish up the funscript for Apathetic Handjob, but here's the version of the Sex Toy Video Sync 101 episode. It's 22 minutes and... probably *too* dense with information. Please let me know what you think! --- ## Video Sync Tutorial Episodes Are Live With Funscript Tutorial Video: [https://www.youtube.com/watch?v=qgdk77C5SFc](https://www.youtube.com/watch?v=qgdk77C5SFc) Apathetic Handjob Video: [https://www.youtube.com/watch?v=aNFVpmfJLNs](https://www.youtube.com/watch?v=aNFVpmfJLNs) Apathetic Handjob Funscript: [https://github.com/metafetish/video-sync-scripts](https://github.com/metafetish/video-sync-scripts) --- ## Intiface Mobile More Likely Than You Or I Think Earlier this weekend, someone submitted a pull request to Buttplug C# to add Xamarin support for Bluetooth. Xamarin is basically a way to run C# code on phones (versus having to write Java for Android and Swift/ObjC for iPhone).  While the core (non-device handling parts) of Buttplug run on pretty much all platforms, Bluetooth has been what's blocking us from running on phones and actually being useful. I'd originally planned on trying to make a Buttplug JS mobile application (via either reactNative or NativeScript) 'cause I'd heard Bad Things about Xamarin, but since someone was just handing me the code, I figured "why not" and build the included demo app for Android and iOS. Turns out, it... works? Pretty decently? I've tested both scanning for the devices from an app UI, and actually putting a websocket server (?!?) on the phone and using it similar to Intiface Desktop. Both of these choices work surprisingly well. I've managed control through both ScriptPlayer and Playground using both phone OS's. Not only that, the new Xamarin code (minus examples) is only about 60 lines of code. That's all that was required to get it working with Buttplug. Yay architectural choices that facilitate additions! Where this goes from here, I'm... not real sure yet. This was absolutely not in the near-term plans, so I'm kinda overwhelmed at the moment, but there's a pretty real chance I could throw together a basic UI and have Intiface Mobile on Google Play/Apple App Store in a month or two. There's still some online services that need to exist to make connected all of this stuff smooth, but I'm still super stoked this works at all. If you write C# and are interested in making your own mobile apps with this, I should have the Xamarin Bluetooth library in the Buttplug C# mainline and nuget packages up later this weekend. More news as I figure it out. - qDot --- ## Buttpluggin With Qdot Vamlaunch Demo I've been getting requests to get hardware support into VirtAMate ([https://patreon.com/meshvr)](https://patreon.com/meshvr)) for a long time, but it's a complicated program with a lot going on, so I've never really gotten a foothold to figure out how to do that. Luckily, someone else did! [https://github.com/zengineervam/vamlaunch](https://github.com/zengineervam/vamlaunch) I've been working with the VAMLaunch creator over the past couple of days to get their device system ported to Buttplug, as well as adding a GUI, installer, and other nice polish stuff around their VAM scripts. It all works rather well! Sorry about this video not being a pre-release, but I was running on other people's deadlines this time so it was an ASAP sorta thing (which you can tell by the ad-lib'd video where I make "youtube-safe" jokes no less than 10 times, heh.). --- ## Buttpluggin With Qdot Virtamate Vamlaunch Demo Nsfw Pornhub Edition New NSFW version of the VAMLaunch demo video! I actually refilmed the last portion of the VAMLaunch demo since I didn't have to put the work into censoring it. It's about 10 minutes longer, has more info about how VAMLaunch works and how to hook it up to scenes, as well as me generally being an idiot 'cause, well, what else do you do when you have VR and physics. --- ## What's qDot Up To This Week? (2019-07-08 Edition) Dear god why do people keep coming to me with interesting projects when I have so much boring work to do! # Buttplug Anyways let's start with the boring. The library work. For the core libraries, I put out Buttplug C# 0.4.7 last week. Big feature there was the Xamarin module which now gives us the possibility of Android/iOS apps. There was also some toy additions and fixes (Cyclone SA should work again!) and a few development things (you can build from source zips again and don't require the full git repo). That was also released as intiface-cli-csharp 0.4.7, so if you're running Intiface Desktop on windows you probably got an update notification for that. On the JS side, I rewrote the vue-buttplug-material-component to make life easier on all of us. The code is now much simpler, and also has a better UI that doesn't require users to know all of their IP addresses! Which leads us to... # Applications (Playground, Syncydink, Tutorial, etc...) The all new Playground! [https://playground.buttplug.world](https://playground.buttplug.world) This uses the new connector widget as well as getting a slight usability overhaul.  I'll be porting Syncydink to this next. Also, I'm rebuilding the tutorial from scratch because it has been broken for a while now, which has new users bouncing off Buttplug completely. This is now my top priority, assuming other shiny things stop showing up, like... # VAMLaunch As you probably saw from the multiple youtube/pornhub video posts... This past 4 day weekend was going to be spent on the aforementioned tutorial and widget work, but then VAMLaunch showed up on Friday and completely blew my schedule. I ripped the GUI and installer from GHR to help VAMLaunch have a bit more polish than just having a command line with a readline interface, and working with Zengineer (the VAMLaunch author) was a great experience. I even got *2* demo videos done in a weekend! I'm really glad VAM finally has hardware support and was happy to help out to make it better, as people have been asking me about it for over a year and it was just never gonna happen for me due to lack of time. I'm hoping to get back to the tutorial and syncydink updates this week, then finish out buttplug-py and maybe get a Intiface Desktop revision out next week. # Patreon Tiers I mentioned last month that there would be patreon tier updates. I'm still planning on doing that, but at this rate it may be August now. That's it for now. Until next week, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-07-22 Edition) Organization, and even more new projects! # Buttplug After realizing that I had no idea what all projects I had in flight right now, and not really having an ability to deal with that plus new job, the past week/weekend have been dealing with trying to get everything logged and organized. It's getting there, slowly. I'm hoping once I have this system in place, I can keep at it and this won't happen again until it happens again. Current projects in flight include: - New Intiface Tutorial - buttplug-py first release - Intiface Desktop bugfixing/updates - Device bugfixing/updates - Adding input messages - Decoupling JSON parsers (makes the core library a little more flexible) - Unity bindings (blocked by prior decoupling task) - And.... While doing all this organizing I of course had to wander off and work on some new proof of concept. # Teledildonics So now we have teledildonics. Sort of. *Technically*, teledildonics has been available in Buttplug since almost day one. If you knew how to chain together ports and websockets in the right way, you could have people remotely access your Buttplug Server. It was not easy though, and very few people pulled it off. With the introduction of Intiface Desktop, I managed to break that somewhat too, due to the way self-signed secure certificates work. Enter WebRTC. WebRTC is a technology that's been built into web browsers over the past 7 or so years. Without getting to deep in the technical parts, it basically allows you to do audio/video conferencing in a peer-to-peer manner, similar to Skype/Zoom/etc. You and the person you want to communicate with are matched by an outside server, then you're linked up and talk directly over the internet to each other from there. Turns out there's also ways to fling arbitrary data over WebRTC, including Buttplug commands. I ran a small test of this using a modified version of our buttplug-js Glitch.com tutorial, and sure enough, someone on the other side of the US could press a button and make my Lovense Lush vibrate. Wheee. For now, my plan is to make a connector class for these that you can integrate easily. It'll only be in buttplug-js (using WebRTC outside of browsers is... an issue), but if you're working on the web or in something like electron (since it's basically chrome), this will allow you to connect to other people remotely, albeit with zero limitations on what they can do, so, uh, be careful with it. I'll be posting more information about that once the project is cleaned up. # Intiface, Etc... Not a lot happening otherwise on Intiface at the moment. Logging quite a few bugs and fixes for Intiface Desktop once I can get to it, as well as starting to think about utilities that could be added, like local device testing (so you can just make sure your devices work while you're in Intiface without connecting to anything else! I cannot believe we've lived without this feature for like 2 years). No complaints about the new Playground so far, but that's because there's been almost nothing in the way of comments about it, period, heh. That's it for the past, uh, 2 weeks. Until next week, keep buttpluggin'! - qDot --- ## Intiface Game Haptics Router In Model Content It's no longer just me using the GHR in videos! A model I've been working with for a while, Riley Nicks, recently posted a clip of her using the GHR with Bayonetta! AFAIK this is the first time Buttplug/Intiface has been used in content. The Pornhub preview of the full video is at [https://www.pornhub.com/view_video.php?viewkey=ph5d37e6727d989](https://www.pornhub.com/view_video.php?viewkey=ph5d37e6727d989) --- ## Intiface Game Haptics Router V3 Released [https://github.com/intiface/intiface-game-haptics-router/releases](https://github.com/intiface/intiface-game-haptics-router/releases)  In yet another pivot to a random product (for reasons that will be shown in the next post), I've just upgraded the Game Haptics Router to v3. This puts it back at feature parity with the Game Vibration Router, meaning: - Baseline vibration works again - Vibration Multiplier works again - Autoupdate annoyer works again That's pretty much it for now. I've scoped some work for getting the Fleshlight Launch and other toys working with this too, but that's still fairly far down the priority chain. --- ## What's qDot Up To This Week? (2019-08-05 Edition) You get a release, and you get a release, and everybody gets a release! Except Syncydink. Again. # Buttplug / Intiface / Web Components Most of the work over the past couple of weeks has been finishing up the device configuration work I started earlier this year. To make a short story long: We started getting requests for support for the WeVibe Vector. Now, we already support WeVibe stuff, and AFAIK the Vector would have the same protocol as the rest of it. With the new device configuration work I'd done, this was supposed to mean I could just change a text file, Intiface Desktop/Javascript would update, and everything would "just work". Except that I like half-finished it. I figured out the file format, made the file, built it into our code libraries, but never got to the point where you could load a file from outside the library. The past couple of weeks have been spent fixing that. Now, everything can load an external device config file. Hell, YOU can load it if you want! It's at [https://buttplug-device-config.buttplug.io](https://buttplug-device-config.buttplug.io) This means that, if companies add new toys that use a protocol we've already implemented, we can hopefully just add some info to this file and web apps, intiface desktop, etc will "just work" with no code changes required. Of course, if it's a new toy that we've never seen before, then code is still required, but there are a lot of brands that rarely if ever change their firmware, so this makes life easier in that case. I've made releases of Buttplug C#/JS, Intiface Desktop, and the Vue Components (updated Buttplug Playground too) that all incorporate this. Syncydink still needs to be brought up to the new Vue Component, so that'll still take a bit. Soon tho. I hope. # What's Next - Still need to finish the Intiface Tutorial - Titan 1.1 owners are yelling at me for support (gotta figure out protocol changes) - People building their own hardware are yelling at me for support (via building a generic protocol so DIY integration with buttplug is easy, but this is still a rather complex deal overall from my development side) - Still need to finish buttplug-py - Wanna finish up first round of WebRTC connectors soon because TELEDILDONICS Unfortunately I'm also rather addicted to Hollow Knight right now which is eating a lot of my time, so we'll see how much actually gets done. :) Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-08-12 Edition) Writing tweets that should really be blog posts, apparently. # Intiface/Buttplug/Etc Nothing to say here. No code written this week. New job is throwing a lot at me right now and I think my brain needed a break, which is why I basically played through the whole of Hollow Knight in the span of a week. Hopefully recovered and back to it soon. Good news is, I'm learnin' lots about ML, so maybe that knowledge will end up around here soon. Who wants to do linear regression about sex? # Writing I apparently miss blogging, though. For those of you not following the Buttplug twitter account, here's a quick catch-up. Defcon, the security conference, was last week. There were 2 sex tech presentations!  The first one was Friday, a panel on Cyber Sexurity (ow ow ow it even hurts to type that) with awesome people from SexTechSpace ([https://www.sextechspace.com/),](https://www.sextechspace.com/),) Lora DeCarlo, and BadAssArmy. I somehow was not even aware this was happening? So most of my content was about the one that I did know about. On Sunday, a console hacker presented a really interested exploit chain involving Lovense toys. Basically, there's ways to reflash both the firmware of a Lovense toy, AND run code on the lovense dongle, AND cause remote execution in the Lovense desktop app. It's pretty impressive (and the app part has been patched at least, so the exploit chain is partially broken). Slides are here: [https://media.defcon.org/DEF%20CON%2027/DEF%20CON%2027%20presentations/DEFCON-27-smea-Adventures-in-smart-buttplug-penetration-testing.pdf](https://media.defcon.org/DEF%20CON%2027/DEF%20CON%2027%20presentations/DEFCON-27-smea-Adventures-in-smart-buttplug-penetration-testing.pdf) The slides are rather technical, so if people would like a gentler explanation of what's going on in the hack versus lots of memory diagrams and acronyms, please comment on this post and if enough people are interested, I'll write up an Patreon-Exclusive explainer. :) Anyways, I was rather worried that someone was using sex toys for yet another FUD talk, but honestly, this talk was in depth enough on the tech side that it didn't really use sex toys as a crutch. It really did need the specific product for the presentation, which just so happened to be a buttplug. However, I did see lots of "WHY DOES THIS EVEN EXIST DOWN WITH IOT" replies, so I wrote up an incredibly long thread on how the current Lovense technology stack came to be: [https://twitter.com/buttplugio/status/1160624147505934336](https://twitter.com/buttplugio/status/1160624147505934336) It's been getting some fairly good feedback.  So far, the media has been fairly quiet on the talk as a whole, which is a little surprising, they usually jump right on this stuff. Really though, twitter is a horrible place for this kind of long form writing, so I'm hoping to get back to having an actual blog soon too. Whether that will be on Metafetish is up in the air (playing around with some ideas for pivoting Metafetish a little, may talk about this next week), but hopefully it'll be somewhere, because dividing thoughts into 280 characters sucks. Anyways, that's it for this week. Until next week, keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-08-26 Edition) PENS. SO MANY PENS. (I was at the San Francisco Pen Show last weekend. Many pens were... written with.) # Intiface In between pen fondling, I managed to get a good portion of the new Intiface Tutorial done. The pure-web version is done, now it's mostly down to finishing up Intiface Desktop setup/install/check steps. Hoping to have this out in the next week or two. The major problem now is figuring out where it goes. When I wrote the original Buttplug tutorial, we had a crappy, hard-to-extend GUI. Intiface Desktop is basically a full web browser (thanks, electron), so I've got a lot more room to work. Trying to decide if I want to integrate it into Intiface AND have it on the web or what. I have given myself way too many options here. After this, it's back to finishing buttplug-py, then hopefully getting to implementing new messages and maybe rolling all libraries to v1 before the end of the year. # FFXIV Buttplugs For those of you watching twitter, the Final Fantasy XIV ACT plugins made the rounds again after a redditor updated ButtplACT ([https://github.com/crnlskn/ButtplACT/](https://github.com/crnlskn/ButtplACT/)) and posted about it there. It got some traction this time, making it to a couple of gaming blogs. Pretty awesome! Though weirdly enough, there's now like, 3-4 FFXIV ACT plugins using Buttplug. It's possibly the most implementations of something using Buttplug at the moment. Unexpected. Like, we only have 2 movie players right now (3 if you could the Kodi work done in 2017). Anyways, I'm gonna try to make a video about this soon. I just gotta figure out how to play FFXIV first. If anyone is interested and plays, lemme know. # Other Buttplug Stuff The FFXIV thing sent me on a vanity search of github, and I managed to find some other projects using Buttplug, including: - [https://github.com/hottail/HotTail](https://github.com/hottail/HotTail) - One of the other ACT plugins I mentioned - [https://github.com/BytewaveMLP/DGButtPlugin](https://github.com/BytewaveMLP/DGButtPlugin) - A Duck Game Buttplug Mod?! - [https://github.com/Inari-Whitebear/KSPButtplug](https://github.com/Inari-Whitebear/KSPButtplug) - A Kerbal Space Program mod I had forgotten about It's really neat finding projects that use buttplug that I didn't even know about! Gonna work toward featuring more of these on Metafetish. # Businessy Stuff While I'm not sure anyone cares, work on the Nonpolynomial website continues apace. Once this is done, I'll be doing more blogging about the technical side of Buttplug/Intiface, while keeping content related posts (like the mod announcements above) to Metafetish. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-09-02 Edition) OMFG. I AM ACTUALLY CAPABLE OF FINISHING THINGS. # Intiface Tutorial The new Intiface tutorial is done! [https://tutorial.intiface.com/](https://tutorial.intiface.com/) This time it's written using vue.js instead of twine, but still has basically the same interface. There's still a lot of debugging to do and a lot more information to add, but for now it seems to be up and running ok. If you're already using Intiface Desktop, there's not much to see here, but once I start adding new features (Like WebRTC connections and what not), I'll probably be recommending users walk through the tutorial again with the new methods. # Zendesk Support This is kinda weird for an open source project, but I've started a support account on Zendesk. This allows me to receive trouble tickets whenever people are having problems with Intiface or apps like Playground and Syncydink. Not everyone has a github account or knows how to use github issues, so this seemed like a better match. Right now, support requests are only implemented in the Intiface tutorial. To see what it looks like, go to the Intiface Tutorial, go past the intro screen, then hit the "Need Help" button. One of the nice things that comes with the Zenhub account is a Knowledge Base, aka a FAQ: [https://nonpolynomial.zendesk.com/hc/en-us](https://nonpolynomial.zendesk.com/hc/en-us) It's going to take me a while to get this filled out, but I'm hoping it'll serve as the central place to answer questions about the various projects. # Hardware Support Lists blackspherefollower, one of the longest tenured community members and contributors to the project, has put together a nice list of computer controlled sex hardware, including information on devices supported by Buttplug: [https://iost-index.netlify.com/](https://iost-index.netlify.com/) I'm hoping to put together a simpler version of this for the buttplug.io and intiface front pages, so we can finally start answering the question "but will this work with my hardware?".  Which seems like it should've been the first question the project answered. Oops. # Buttplug Now that the tutorial is up, I'm gonna try to get back to a round of Buttplug updates (even though I found a TON of Intiface Desktop bugs while building the tutorial). This includes: - Kiiroo Titan 2.1 Support - Finishing up the Buttplug Python Client Library - Starting work toward a v1.0 release, including new messages for Battery Levels, RSSI Levels, Raw commands, etc... # Everything Else - Still doing design work on the Nonpolynomial brand. - I'd like to get Playground updated with links to Zendesk Support in case people need it. - Syncydink still needs to be ported forward to the new Intiface Web widget. And also needs to have Zendesk support. And also need to be completely rewritten. - WebRTC is still blocked on me getting a basic user system together and figuring out EULAs and other boring legal requirements. I've been trying to quickly glue some Django experiments together for this, but it's been slow going. - Unity. Ugh. This is just a constantly shifting problem now. Still need to strip down the core library to remove dependencies so we can make an easier-to-embed client, which may happen as part of the v1.0 work. - No video work planned for the near future but who knows. I just randomly decide to make videos sometimes. I think that covers everything for now. Until next week, Keep Buttpluggin'! - qDot --- ## Buttplug Python 002 [https://pypi.org/project/buttplug/](https://pypi.org/project/buttplug/) I just posted the most minimal implementation possible of a buttplug client to PyPi, meaning the buttplug-py package now actually at least does something. The package is HEAVILY py3.7 based internally, so you're either using py3.7 or you're out of luck right now. It's asyncio based, and also uses some non-standard python idioms like events ('cause I just wanted to make it look like the C#/Typescript impls, and both of those languages have first class events), but those are mostly just a matter of callback passing. There's almost no documentation currently, as I haven't dealt with sphinx in years and forgot how much I hate it (fuck restructedText so much), and just wanted to get code up. I'll be spending the next few days wrestling with sphinx to try to get a better manual together, at which point I'll probably post more about this publicly. But since ya'll are paying me, you get the raw goods first. :) If you're absolutely jonesing to try this, there's an example that basically shows how it works: [https://github.com/buttplugio/buttplug-py/blob/master/examples/test.py](https://github.com/buttplugio/buttplug-py/blob/master/examples/test.py) As usual, you can message me if you have any questions, too. --- ## Buttplug Py 010 Released [https://pypi.org/project/buttplug](https://pypi.org/project/buttplug) [https://buttplug-py.docs.buttplug.io](https://buttplug-py.docs.buttplug.io) Buttplug Python 0.1.0 is out, and is now something I don't feel quite so bad about pushing to public package repos. There's way more documentation, and it actually throws errors and what not now. With the tutorial and python library out of the way, I'm now hopefully free to work on protocol level upgrades for the first time in, uh... wow, 18+ months? --- ## Buttplug Python Documentation By no means complete, but getting there: [https://buttplug-py.docs.buttplug.io](https://buttplug-py.docs.buttplug.io) --- ## What's qDot Up To This Week? (2019-09-16 Edition) More than usual, less than I want. # Buttplug Managed to get buttplug-py 0.1.0 out the door. With that and the tutorial being done, I'm hoping to get back to low level protocol development. This will including adding new features to the base system, like: - Battery Level Reporting - RSSI (radio strength) Reporting - Raw Data Commands (useful for developers, for debugging and bringing up new devices) - Pattern Commands (for playback of built in patterns on hardware) - Step Attributes (so we can say things like "This toy supports 20 steps of vibration") Overall, this should make developing and interacting with applications that use buttplug a nicer experience for everyone. I hope. For hardware, here's what we've got coming up: - Vibease Support (wow this protocol was a mess) - Kiiroo Titan 2.1 (Someday) - Nintendo Joycon - The Handy (more about this later in this update) - Motorbunny # Intiface Not a lot happening here at the moment, though I'm considering adding a file hosting mechanism to Intiface Desktop, so that it's easier to access movies/haptic files on desktop from phones or standalone VR Headsets. This would make Syncydink much more useful. Might chuck that together as a weekend project or something. # Games I'm in talks with a few more game developers, hopefully looking at more game integration soon! Will actually announce which games these are once things are solidified.  # Hardware I don't usually advertise hardware, but The Handy is back on sale after being off the market for 5 months, and at a new $149 price point. [https://thehandy.com](https://thehandy.com) It's an interesting device. I've got some fairly serious design grumps about it (it was built to be used lying down, and it shows), but it's well built and capable of a lot. Also, I mentioned this in the last email, but if you're interested in the hardware we support as well as what's out there in general, blackspherefollower has been continuing to update IoSTIndex and it's looking great. [https://iost-index.netlify.com](https://iostindex.netlify.com) That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-09-30 Edition) Crap when did it become Tuesday. # Buttplug Buttplug C# 0.5.1 went out last week with support for the Motorbunny. Buttplug JS will be getting an upgrade pretty soon, also with Motorbunny support as well as a couple of fixes to some rather serious bugs. With that out of the way... What I'm about to say is gonna get pretty violently technical and deep into Buttplug development internals really quick, so the tl;dr for those that don't want to wade through this: I'm doing some experimental work to hopefully make Buttplug easier to update and port to new platforms and languages. It's a big project and it may not work, but if it does, it will make life easier for everyone. The long, technical version: I'm writing a version of Buttplug in Rust. Again. For those of you that've been around for the long haul, you'll remember that I started the current version of Buttplug in Rust in August 2016. This quickly went south due to multiple reasons: - Lack of Windows device API support (WinAPI 0.3 wasn't out yet, no UWP support) - Flux in the language (Tokio/Futures had just come out) - Unclear how it would port other places I started the C# version in April 2017, and the Typescript version in June 2017, which leads us to where we are today. The issue here is that both C# and Typescript/Javascript require their own runtime. C# needs .Net, Javascript needs a JS engine like Spidermonkey or V8. This is less than great when I want to port to other platforms. There's ways to do that, and we're partially doing that now with Xamarin, but they all have their issues. On top of that, when people want client libraries in other languages, it means reimplementing all of the client and core API of Buttplug in that language. I just did this for Python. It was agonizing, and it only works on Python 3.7+, which can be an issue for some people. Similarly, we have older Unity games, written on Mono 2/.Net 3.5, that would like to support Buttplug. This would mean backporting the C# to .Net 3.5. Basically a completely rewrite of the core and client API. Again. Finally, there's a *new* set of Microsoft technologies out (.Net Core 3.0/.Net Standard 2.1/C# 8) that are all really cool and awesome, but no longer backward compatible with .Net Framework, which is what most windows applications are written in. So, if we wanted to move to the new spiffy stuff (which I desperately wish I could), we'd have to fork AGAIN, possibly maintaining 3 version of C# code. As I am not an enterprise company, this does not sound fun. The new goal is rewriting the core logic in Rust, a systems language. The core logic consists of: - The messages and protocol - The client and server APIs - The device protocols and configuration file loaders Things outside of the core logic will be: - Client API implementations - Device Subtype Manager implementations This means that, in a perfect world where this project works out, Buttplug C# will consists of: - A C# Client API that talks to a Rust core via C style FFI calls. - A Rust core that's easily upgradable - C# Device Subtype Managers (USB, Bluetooth, etc.) that Rust talks to in order to access devices Implementations for new languages will look mostly the same, 'cause damn near everything can do C binds (remember SWIG?). Just switch out C# for your favorite language in the above list. For the Web, the hope is to compile this to WASM and wrap it in JS APIs. In terms of user value adds, whenever we add new hardware protocols, they only need to be written once, in Rust, then we can recompile all of the wrapper libraries, and everything stays in sync, unlike the huge split in C#/JS right now. Also, features will only need to be implemented once, then APIs updated around them. Hopefully. The biggest problem to this approach is going to be debugging. For instance, with C#, if a subtype manager throws an exception, this will have to be caught before it hits the C#/Rust border, converted into something we can flow through Rust, then rethrown once it hits the C# Client API side. This is a difficult situation to say the least, but other companies like Sentry and Mozilla are doing this already and have written up nice guides on how to do it. Building is less of a concern, because I've been a build engineer before and done far, far worse things than this. :| Another big reason to do this: Thanks to my time at Mozilla, I know a bunch of Rust compiler engineers. I cannot say this about any of the other languages I'm working. I have way more people to poke and complain at if things go wrong. Anyways, that's the dream. Whether this will actually work, I have no fucking clue. I did the core implementation work last weekend, and we have a basic library that can do in-process client/server comms via ButtplugMessage objects right now (see [https://github.com/buttplugio/buttplug-rs](https://github.com/buttplugio/buttplug-rs) if you're interested in progress), but there's a long, long way to go from here. Goal for the moment is to get a minimal system up and running that proves out both the core library and the FFI setup (so probably a very simple Lovense implementation with vibration only), then go back and fill in protocols and everything else. While this is in development, I'll still be working on the C#/JS libraries. There's bugs to fix and features to add, and in the end, nothing should really look too much different to developers using those libraries. The core will just be a little more opaque. There's also a chance this experiment doesn't work, and we stick with C#/JS/Whatever else. I'd really like to avoid that, but it's something I'm keeping in view. May god have mercy on us all. # Game Haptics Router I released v4 of the GHR last week, mostly for Motorbunny support. Hearing some initial reports of bugs that I'm going to check on this evening, so possibly expect v5 this week also. Ok, well, a longer update than usual with less interesting content for those of you that aren't developers, but explaining the Rust work was a lot, and I'm trying to stay transparent here. Hopefully more fun news soon. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-10-07 Edition) Rust. That's it. Just rust. # Buttplug Ok, well, not quite. I did actually take the time to do a couple of other things: - Buttplug C# 0.5.1 was released, adding Motorbunny support - Buttplug JS 0.12.1 was released, adding Motorbunny support and fixing a serious bug in the JSON parser that had been there for a whole year. :( - Vue Components and Buttplug Playground got quick releases to integrate that JSON parser fix and also fix another bug on Intiface Desktop connection because Promise.all() does not work like I thought it did (I apparently wanted an equivalent to Promise.allSettled(), which is not in most browsers yet. I'm just so ahead of my time.) Outside of that, RUST. RUST ALL THE TIME. For some reason I've really managed to get a grasp of the language this time and the implementation is going surprisingly well (even though I'm on Rust 1.39 using beta features that won't be in stable for another month >.>). As of tonight I have a client that can connect to the node/C# server implementations via websockets. Still a lot of work to do, but it's coming along really well and I'm fairly convinced this is going to make life way easier for everyone going forward, and by everyone I mean me. That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## Github Sponsors Patreon And The Basically Same Future tl;dr: I'm now using 2 funding platforms, but there will be no fundamental changes due to this. Unless you want the gritty details of what it's like to be a creator with multiple patron streams, you can skip this post. :) For anyone that follows me on twitter, you may've noticed that I was accepted to the Github Sponsors program. Github Sponsors is basically Patreon with a bit more of a development/corporate/open source focus. [https://github.com/users/qdot/sponsorship](https://github.com/users/qdot/sponsorship) I just wanted everyone to know that nothing will be changing on this patreon, outside of the tier levels. I discussed that topic here back in July, and I'll be aligning the patreon levels with what I now have on Github at some point in the future, but that shouldn't affect anyone already signed up here. I'll still be advertising support for my projects through both Patreon and Github sponsorships, though admittedly I'll be marketing the Github side a bit harder at first because Github provides $5000 in matching funds for your first year of sponsorships, and that's a lot of Buttplugs. In the future, I see the divide working this way: - Patreon will most likely be funding from users of applications, fans of my youtube channel, etc... It'll be handy for non-github-using people. - Github will become where I get money from developers I'm supporting, do consulting, etc... Basically a good way to get funding from people who already have github accounts, but having non-coders sign up to github would be silly. Both of these demographics are equally important and I won't be dropping one or the other. In fact the content will basically be mirrored between the two places, which is more work for me than anything. :) If you have any questions or concerns (or also just have questions about how running these kinda services works), please feel free to message me directly. Just want to keep everything as transparent as possible. - qDot --- ## New Patreon Perk Qdot Reviews Sex Tech Porn Earlier this week, someone sent me some furry porn that involved the use of VR (as in the character in the picture was using VR. This is surprisingly difficult to state for some reason.). The spirit moved me to savagely critique it from my perspective as a sex tech engineer. That review is what you see above, assuming Patreon didn't compress it to hell and back. For reference, the picture in question is at [https://e621.net/post/show/2010923](https://e621.net/post/show/2010923) I ended up tweeting about it here: [https://twitter.com/qDot/status/1183967710704586752](https://twitter.com/qDot/status/1183967710704586752) Someone ([https://patreon.com/foone](https://patreon.com/foone) who does fantastic retro reverse engineering stuff so go give them your money) said that they'd sign up to the Patreon if I kept doing this for patrons. So, here's the new tier reward (for all tiers) since that whole "Youtube Blooper Reel" one never really worked out. Once every couple of weeks I'll go find some porn that features technology or VR in some way and will be horrible about it in text. Doesn't particularly have to be furry, though e621 is just a putrid fountain of this particular kind of filth (and I'm also furry trash) so I may lean that direction anyways. If you have any requests, please feel free to message them to me. I may post some of these publicly after I post them here, but they'll be Patron/Github Sponsor only for the first week if not more. May god have mercy on us all. --- ## What's qDot Up To This Week? (2019-10-28 Edition) Enjoying having electricity again! My power went out as part of the California wildfire outages that've been all over the new. We were out for just under 48 hours. That sucked. Anyways, on to updates. # Buttplug The Rust implementation of Buttplug continues to be the headline news here. It's still coming along quite well, with the client implementation now working completely. Sure, it's a mess, but it's a working mess! We can connect to Intiface Node/C# CLIs, enumerate and control devices. The next order of business will be lots of cleanup and documentation, all well as starting work on the FFI layer for C#, just to figure out how that's going to work. Once Client for both Rust and C# are solidified (which will put us in a very good position to start considering **Unity plugins!**), then it'll be on to reimplementing the server side of things. The Buttplug Rust Crate is still using lots of beta features, and may possibly use unstable features of the async-std library soon (for async MPMC channels to deal with events/observables easier), so I'm not sure when I'll be getting a new version of it up on crates.io. I'm gonna try to get at least something up when Rust 1.39 comes out a week from Friday (Nov 7) tho. # Intiface Game Haptics Router I don't have any specific updates on the GHR at the moment, but wanted to talk about some possible upcoming changes, as I'm getting a lot of questions about/interest in it. One of the big gaps in the GHR at the moment is the lack of ability to use it with anti-cheat enabled games like OverWatch, LoL, etc... Apparently a LOT of people really want to do naughty stuff in OW, so I'm looking at ways around this right now, including: - USB/BT hijacking to watch HID packets - ML/CV implementations The ML/CV idea (i.e. train models/use classical CV methods to process real time screen captures) is interesting in that we could possibly parse context versus just "rumble happened therefore we make things vibrate". This would give us a better foothold in places like the Healslutting community, though figuring out how to extract the context we need for this to be useful will be a LOT of work. I'm talking to some other developers who run games services based on this idea now, just to see what's possible. Anyways, that's it for now. A fairly technical update this week, but all good stuff! Hopefully more to show for it soon. :) 'til next time, Keep Buttpluggin'! - qDot --- ## Buttpluggin With Qdot Lelo F1s Unboxing After a year of waiting my Lelo F1s showed up today. I did a super quick unboxing video because, well, it comes with masturbation racing gloves! How could I not! --- ## What's qDot Up To This Week? (2019-11-04 Edition) Scrambling to finish my SLSA presentation on hidden haptics spaces in online games (aka using the GHR in online games) that I have to give on Friday! Did you know proxemics is a thing? I didn't until like, yesterday. So I've got a lot of reading to do now. :| Anyways. # Buttplug The Rust version of Buttplug is almost possibly maybe usable sorta. The client can make things vibrate, but is still missing important functionality like "Being able to disconnect from the server", which is something people probably want to do. There's documentation up now too:  [https://docs.rs/buttplug/0.0.2-beta.1/buttplug/](https://docs.rs/buttplug/0.0.2-beta.1/buttplug/) Probably gonna be a pretty quiet week on development since I'm in Irvine for most of the week. # Hardware I have a Lelo F1s now, and other project members are getting them soon, so expect support there. Also, while it's not my project, the IoST Index site now has its own domain that you can pass to people who want to marvel at exactly how much hardware is out there: [https://iostindex.com](https://iostindex.com) Ok, that's it. The Rust work, for the little blurb it got, actually took most of my week. But hopefully more movement soon. 'til next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-11-11 Edition) Recovering. # SLSA Most of my life for the past week was attending the Society for Literature, Science, and the Arts (SLSA) conference in Irvine, CA. Conference went quite well, I did a talk on the Game Haptics Router as a tool for creating new haptic spaces for communication, analyzing the strategy via proxemics. Reception was surprisingly good. I should have a version of the talk filmed and up on Youtube by the end of the week. # Buttplug Rust 1.39 is out, which means async/await is now stable. This should accelerate library updates, which means it'll hopefully be easier to build stuff soon. No real code work otherwise, didn't have time with conference and all. And that's pretty much it for the past week. Once I'm rested up, hoping to get back to work on buttplug-rs, as well as merging a lot of new device support code in C#, including the Lelo F1s. Until next week, Keep Buttpluggin'! - qDot --- ## Buttplug Rs V002 Released Buttplug Rust is actually kinda sorta maybe a thing now! The Client API has been implemented in Rust, using the new async/await system. It seems to be working pretty well so far, though I haven't gotten to do a ton of testing yet. Now that the release is out, I'm hoping to start testing FFI for writing a C# layer on top of it (which would then mean hopefully simple Unity support!), as well as starting to implement the Server side in it. Exciting times ahead! --- ## What's qDot Up To This Week? (2019-11-25 Edition) Being a day late, but I hate missing more than 1 week in a row of these. # Buttplug 2 releases in the past week! - Buttplug Rust 0.2, with a fully functioning Client! This is a huge step forward on the systems side. I'm now working on a server implementation as well as FFI to get bindings to other languages (C#/Python/C first, then hopefully JS via WASM at some point once I figure out the bindgen part) working. - Buttplug C# 0.5.4, which includes new hardware support for the Lelo F1s, WeVibe Vector, Lovehoney Desire, Aneros Vivi, and a few LiBo toys. Most development is still happening on Rust for right now. I'd really like to get a full server setup together, and I don't think getting the server/device manager set up should be too difficult. Most of the work will be in getting the platform specific device subtype managers going. Luckily there's already cross platform libraries for serial/usb/hid, and scattered implementations for Bluetooth LE I can crib from. I've already gotten some toy implementation of C#-to-Rust FFI working so we can FINALLY start looking at things like Unity access without having to fight with dependencies. Exciting times! That's... actually it for right now because all of the above is actually a ton of work that's taking all of my time. Expect more of the same for a bit, though there may be a YouTube video popping up over the Thanksgiving break, as I'm planning on redoing my SLSA conference talk as a video. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-12-02 Edition) Tuesday is the new Monday. # Hardware For some reason, shocking seems to be the name of the game at Buttplug HQ lately. I just reversed a Dog Training Collar ([https://twitter.com/buttplugio/status/1200882638086537216)](https://twitter.com/buttplugio/status/1200882638086537216)) and am now working on the Pavlok ([https://twitter.com/buttplugio/status/1202070730638102528)](https://twitter.com/buttplugio/status/1202070730638102528)) as well as some knock-off bluetooth TENS unit for a friend. This is mostly a matter of timing and coincidence, but still, lots of shocky shit on my desk right now, and probably finally getting a shock message in Buttplug soon. Which brings me to my next topic... # Buttplug Now that the Rust client is done, things have slowed down a bit in the land of Buttplug as I try to figure out what all of the next steps I need to take are. I had originally been planning on finishing porting the library (the device protocols and server code) to Rust, then starting to add new messages, but it's feeling like I may need to switch the order of that. The new messages/capabilities I'm looking at bringing in are: - Raw Messages - A way to send raw uint8 byte arrays to devices. This will mostly be for development and internal use, but it means that if you want to try to access something that doesn't have a protocol built into Buttplug yet, you could technically do it. - Battery/RSSI - Our first 2 reads! Battery power (for bluetooth plus anything else that might have battery, like the ET-312) and RSSI (for bluetooth). This will start us on our way to sensor retrieval messages in the next version. - Shock - Yeah this is coming from the shock device work. Will have strength and duration parameters. - StaticTone - Another one for shock collars specifically. Probably the most niche generic message I've made so far. Just has duration. - Pattern - And going the other direction, the ability to select patterns on any toys that have them. This message will come with a selection of patterns, and in the future, you'll be able to make your own patterns and expose them via this message. Message will take the pattern index, as well as a strength, just in case you can scale the pattern amplitude. I will try to explain this in more human terms at some point in the future too. - Steps - This isn't a message, but rather an attribute to other messages. Right now with Buttplug, if you want to make something vibrate, you're given a range of 0.0-1.0. That's an (sorta) infinite range of possible values. However, most toys have like, maybe 255 vibration levels if you're lucky, some have 20, some have 3. How do you know which toy has what levels? You don't! So you just have to guess and it kind of sucks. The Steps attribute to messages like VibrateCmd, RotateCmd, LinearCmd, etc will allow you to know exactly what your control range is, so you can make your calculations accordingly. This will be the first time new messages and capabilities have been added to Buttplug in *2 years*. Yes, the past 2 years have mostly been spent futzing with the APIs, adding new hardware protocols, and rearchitecting the whole thing like, twice. So it'll be nice to move forward instead of sideways-with-a-slight-lean-forward. # Intiface Intiface is still kinda on hold until I get the above stuff done. Hoping it will see more work in January. I'm probably going to make some quick YouTube videos this week about the shocky shit, as well as finally filming a version of my SLSA talk, so expect updates when those are done. Until next time, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-12-16 Edition) A continuous stream of questionable choices. (Warning: extremely developer/tech heavy update ahead) # Buttplug After lots and lots and lots of bikeshedding and hemming and hawing and refactoring and discussion, I've gotten the Buttplug v2 spec to a point where I can start playing with test implementations. As a refresher, here is what's getting adding to the system: - Raw Messages - Allows us to communicate directly with devices, makes life easier for testing/implementing new things in the system, as well as lots of internal architecture/communication stuff - BatteryLevelCmd/RSSILevelCmd - Our first "sensor" messages! We'll be able to read battery/RSSI levels from devices that support queries for those. - PatternPlaybackCmd - Ability to play patterns built into toys, and at some point, ability to make your own patterns and expose them for playback! - ShockCmd/ToneEmitterCmd - A surprising amount of people have been begging for shock collar/pavlok/etc support over the past few years, so adding some basics for that. Will be interesting to balance against the other hardware types we support. Implementing this is going to take a while, as there will still be refinement while we figure out exactly what works and what doesn't, before exposing it for everyone to use. I wouldn't expect this to be done before mid-January. As part of the work, we're also reworking how and where we define devices. This time last year, we implemented our device config file ([https://buttplug-device-config.buttplug.io).](https://buttplug-device-config.buttplug.io).) Now we're moving even more information out into that, including device names and capabilities. This will make it even easier for us to add new toys to already existing protocols. The first implementation is happening in C#, even though I'd been working on Rust lately. Rust just doesn't have the server pieces in to test this with yet, where C# is more mature. The hope is that this is the last time I have to update server libraries in 3 languages (C#/TypeScript/Rust), and any major changes after this will happen in rust then propagate through FFI bindings elsewhere. # Everything Else Not much to say on other projects right now, as this is the main focus. I did update Syncydink to the latest version of Buttplug, so now it can support a few more toys, but it still needs a massive overhaul. Also updated the Intiface Game Haptics router, once again just a library version roll for more toys. Until next week, keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2019-12-23 Edition) Holy shit. Rust Bluetooth works. # Buttplug Ok well I said back in like, October/November that it was gonna be spec and Rust updates for a while, and I apparently meant it. After realizing exactly how much work it was going to be to overhaul C#, I decided to pivot back to Rust for a bit just to see how far we were off there. As of last week, Rust only had the barest implementation of a Buttplug Server possible, so I decided to try building up some device interfaces.  Without Bluetooth LE access, the library isn't really worth much, so that was the first order of business. There's been multiple shots at implementing Bluetooth LE in rust, most of which are Bluez or Servo (Mozilla's experimental browser) focused. I decided to try Rumble ([https://github.com/mwylde/rumble),](https://github.com/mwylde/rumble),) another Bluez focused library with a finished Linux impl and a mostly done Windows UWP Pull Request from 18 months ago. Linux worked pretty much off the bat, which was great. I had to spend most of the weekend patching up the UWP implementation, but by Sunday, I had windows talking to bluetooth via Rust. So, that's a HUGE worry out of the way. Even if the library isn't async and feels kinda messy (Bluez's device model is weird), it works enough to probably get an alpha version of the server out now. This means that I'm back to full focus on Rust, which will get us a Windows and Linux implementation, with Mac possible (blurmac exists so we can possibly port the code from that or may just use it wholesale? [https://github.com/akosthekiss/blurmac).](https://github.com/akosthekiss/blurmac).) HID and Serial libraries already exist and are cross platform, so that should get us most of the way to the major desktop platforms. Mobile is still going to be interesting, but somehow there's already an Android Rust version of Blurz ([https://github.com/szeged/blurdroid),](https://github.com/szeged/blurdroid),) so we may even be able to support Mobile via Rust, with a Java/Swift FFI layer on top of it, meaning we can still centralize all of the logic. I'm as shocked as anyone at how quickly this is coming along, but I suppose there's been so much work on design over the past couple of years and now it's just a matter of wedging it into a new language. So, that's pretty much it for now. I realize this isn't exactly a feature filled email, but if we can settle down to a single implementation, that means I can concentrate on apps in the future versus updating 3 different implementations and figuring out which one might work where. Until next week, Keep buttpluggin'! - qDot --- ## What's qDot Up To This Decade? (2020-01-06 Edition) Same thing we do every decade, Pinky. Try to buttplug the world. # Buttplug Same shit, different year. Development on buttplug-rs continues, and is going well. As of this past weekend, I can now build a single rust executable with the client/server API that will control bluetooth toys. This is a very specific flow so I've still got a lot of work to do, but it's the first end-to-end test of the new code, so I'm super excited about that. Other developers on Discord are starting to look at the code, and there may be some protocol work being done by someone who is not me soon. I'm still trying to get a full, working server out of this, so I've got a ton of small things to implement or fix (like, say, being able to detect when devices disconnect >.> ), as well as some Large Things (like implementing a CoreBluetooth backend for MacOS so buttplug-rs can become the single engine behind all 3 platforms in intiface desktop). Times continue to be exciting though! Really looking forward to being able to centralize on this across all of our platforms and not have to implement everything multiple times. :D # Upcoming Travel/Speaking Engagements For anyone in the Bay Area, I'm part of a sex tech panel at OutInTech San Francisco on February 12th. More info on that soon. I'll be speaking and mentoring at OOOHack in Chicago in late February: [http://commiserate.life/sthack](http://commiserate.life/sthack) I'm also speaking at GDC in March: [https://schedule.gdconf.com/session/sexy-microtalks-designing-sex-and-emotions/868910](https://schedule.gdconf.com/session/sexy-microtalks-designing-sex-and-emotions/868910) That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-01-13 Edition) Oops I accidentally another library # BtlePlug Yup, you're reading that right. Not Buttplug, BtlePlug. :( One of the things Buttplug needs to function is a Bluetooth LE library. This library ideally needs to support: - Windows 10 - MacOS/iOS (these are mostly similar) - Linux - Android In C#, we had a library that could support Win10 and Mac. That was about as far as we could get. If we used WebBluetooth we could get everything but iOS easily, but it required use of Google Chrome or Electron, so it wasn't really a great choice. Now that I'm trying to get the core logic on Rust, I decided to see what Bluetooth LE libraries were available around the Rust ecosystem. Surprisingly enough, all of those platforms are supported in Rust. Unfortunately, that support comes from 3 separate libraries. I've now taken it upon myself to try to glue these libraries together into some sort of frankenstein to get buttplug-rs up and running on Win10/Mac/Linux for now. That library is BtlePlug. [https://github.com/deviceplug/btleplug](https://github.com/deviceplug/btleplug) iOS may "just work" with the macOS side, and Android will come later. There also needs to be basically a complete overhaul of the API, as no one working on the Rust libs was considering how this needed to work on all platforms (there were technical reasons for that which I won't go into here). Anyways, we already had Win10 and Linux working, so this is mostly for Mac. I've already got Mac scanning for devices, so progress is happening, and once this is all working, we'll be able to use the same code on all versions of Intiface Desktop! No more guessing which platform supports which devices! Unfortunately, that's been pretty much it for my week. Getting this together took a while, and I'm trying to get other people on the project to help fill things out. I don't really *want* to maintain a bluetooth library, but it doesn't look like anyone else does either, so here we are. Until next week (which will hopefully have more sex tech and less bluetooth news), Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-11-20 Edition) AGH IT'S DONE IT'S FINALLY DONE # **btleplug** After busting ass for the past week, btleplug 0.4.0 with macOS support is done. This means buttplug-rs now works with bluetooth toys on Win10, MacOS, Linux, and possibly even iOS once I figure out how to test that. This is the first time we'll have had reliable bluetooth running on all 3 desktop platforms under the same Buttplug library in the 2.75 years the project has existed. This is a HUGE help for me going forward, as it really does look like we'll be able to use rust for almost everything. Still figuring out that whole WASM/Web angle on this so we can replace buttplug-js with this too, but we'll get there. # Buttplug I'll now be returning to Buttplug work. I've got some patches to bring in from other developers who've been working on porting toy protocols over to rust, and I need to sweep through and see what else needs to be implemented or fixed before we can release v0.1.0. My goal is to have v0.1.0 also working under a CLI, so we can maybe start using it under Intiface (even though it's going to be super buggy for the next while, I figure). Unfortunately that's all the news for the week, as I just did the btleplug release about 30 minutes ago, so I haven't exactly had time to do much else. Getting closer to having things to talk about actually related to things people use soon, though! Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-01-27 Edition) Being late to the update and not having much to say because I'm sick. Respiratory infections suck. # **Buttplug** Work continues on getting buttplug-rs inline with C#. Getting lots of protocols ported and tested, looking good for a next release soon. Annnd that's it. Until next week (when I will hopefully have more news and less illness), Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-02-10 Edition) AND WE'RE BACK # Buttplug Finally hit the end of my respiratory infection, so to celebrate I sat in front of the computer all weekend and worked on buttplug-rs. Do I know how to party or what? The good news is, we're down to the boring parts! Which means things like writing tests to make sure the system as a whole basically works before shipping the next version of the library. It's nice to be at this point, as it means the system is vaguely usable and now just needs to be verified. # Upcoming Events The next month is pretty packed with speaking gigs. - Feb 12: Out in Tech panel on Sex Tech in San Francisco - [https://www.eventbrite.com/e/out-in-tech-sf-lets-talk-about-sex-baby-tickets-88574531809](https://www.eventbrite.com/e/out-in-tech-sf-lets-talk-about-sex-baby-tickets-88574531809) - Feb 28-Mar 2: OOOHack in Chicago - [http://commiserate.life/sthack](http://commiserate.life/sthack) - Mar 18-20: Game Developers Conference in San Francisco - [https://schedule.gdconf.com/session/sexy-microtalks-designing-sex-and-emotions/868910](https://schedule.gdconf.com/session/sexy-microtalks-designing-sex-and-emotions/868910) # After that, I have absolutely nothing. I've been trying to keep the back 3/4ths of the year clear to work on project development. # Upcoming Youtube Videos I'll have some new Youtube Videos coming up in the next couple of months! There's been quite a few DIY projects that've been taking off, and I've also got some new hardware incoming that I'll be showing off. That's it for now! Thanks again for your support, and until next week, keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-02-17 Edition) Yesterday was a US Holiday so this update is happening a day late. :) # Buttplug Releases! So many releases! - buttplug-rs 0.1.0 - Finally released a new version of the rust buttplug library, with the new server code. It's not completely done, but I was at the point where there were more new commits in the dev branch than there were in all of master, so I needed to merge and start making smaller updates. From here on out, hopefully it'll be smaller, more frequent releases - buttplug-twine - Finally finished it! I was working on my GDC slides, needed a quick Twine demo, and realized that buttplug-twine didn't work at all now. After about an hour of fixing, it's ready to go and seems vaguely usable. Could definitely use more documentation, but hopefully I'll get to that post GDC - intiface-cli-rs v0.0.1 - Same as intiface-cli for js and C#, but in rust. Will be our testing platform for buttplug-rs for now, but at some point will be the server implementation that Intiface Desktop uses for all platforms. - systray-rs v0.4.0 - Doesn't have anything to do directly with Buttplug, but allows users to create applications that just show an icon in the icon tray of win/mac/linux. I'll be using it for a easy GUI for intiface-cli-rs I've got a lot of travel/talks coming up so I imagine things will be quiet on the code front for the next couple of weeks, but it's been good to actually release stuff! Next plans include: - Getting buttplug-rs to feature parity with C#/JS - Adding v2 spec to buttplug-rs (battery! rssi! patterns!) - Lots of documentation for everything # Travel and Conferences I'll be in Chicago next week for OOOHack ([http://commiserate.life/sthack),](http://commiserate.life/sthack),) then I'll be at GDC in SF March 18-20, and will be speaking at 3pm on the 20th. That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-03-02 Edition) Watching all of my speaking gigs disappear. # Travel (Or Not) So ignore all of those "come see me at OOOHack/GDC!" posts I was making. I ended up having to cancel on OOOHack in Chicago last weekend due to life just kinda sucking right now, and GDC has been cancelled. I'll be submitting a filmed version of my talk to GDC, so it'll be up on GDC Vault, and I'll probably post it to YouTube (and therefore you'll see it here first!). # Buttplug With all of that out of the way, I've had some time to get back to working on Buttplug. The goal is still to get buttplug-rs to a point of replacing intiface-cli-csharp/intiface-cli-node in Intiface Desktop, and that's going pretty well. Been doing a lot of work to bring up testing interfaces, so we can know that we're maybe actually doing the right thing some of the time. Also starting to work on backward compatibility, one of the most important parts of the system, since we want to keep applications that use Buttplug working until the End Of Time (Or Until I Get Sick Of Supporting Them). # Everything Else I ordered a 3D printer (A Prusa i3 MK3)! I've had enough people coming to me with neat 3D printed projects (some for integration with Buttplug) and I've felt bad about having to constantly ask people to print stuff for me. I'll be printing more nogasm parts, there's a ESP32 vibrator someone has been working on that I wanna try making, and also planning on building an OSR2+ ([https://patreon.com/tempestvr).](https://patreon.com/tempestvr).) If there's any projects you'd like to see build on my YouTube channel, lemme know. That's it for now. Hoping that things will stay calm and I can ramp back up on work (and therefore have more newsletter content)! Until next week, Keep Buttpluggin'! - qDot --- ## Covid 19 Avoidance At Buttplug Hq Stay safe everyone! --- ## Nobras Silicone Dreams Twin Charger Unboxing So what's worse than me forgetting to post about one live stream? Me forgetting to post about *2* livestreams! After the Teledildonics 101 session, I checked my mail and found that I'd received my Nobra's Silicone Dreams Twin Charger! It's... a hell of a thing. Violently powerful, but also super pretty! Watch me be overexcited to receive a toy I first started talking about 15 years ago. --- ## Teledildonics 101 Part 1 Intro To Teledildonics Ok, well, somehow I managed to do a livestream and forgot to notify the people paying me to let them know when I do things. Sorry about that. :( So, yeah. I'm working on a series of livestreams to build a simple teledildonics application from scratch (think playground but with remote control). This first one covers a quick history of teledildonics, followed by a discussion of how I analyze and design teledildonics applications. There will be 4-5 parts for this first series, followed by a second series that will be kinda formless, where I just cover different topics on top of what was built in 101 (how to mod games, sync with movies, etc...). I'll try to remember to post when I'm streaming next, should be sometime in the next few days, just gotta write up the next slide deck. --- ## Teledildonics 101 Part 2 Livestream Tomorrow The next in the Teledildonics 101 series is tomorrow, Sunday, March 22nd, at 12pm Pacific! Hopefully this will be European viewers a chance to see it live. --- ## Teledildonics 101 Part 2 Livestreaming In 10 Min Talking about how we scope the design of a teledildonics app, and also doing an quick intro to the architecture of Buttplug! --- ## Whats Qdot Up To This Week 2020 03 23 Quarantine Edition Not leavin' the house. That's what. # Buttpluggin' With qDot My original plan was to hunker down and work on buttplug-rs in order to get it done enough to replace C#/JS in intiface desktop. Then I put a search watch on "teledildonics" on twitter. Turns out, a more people are talking about the topic than usual. I decided to jump on that interest and have been working on livestreams of how to design and build a teledildonics app. The first two episodes are up now: [https://www.youtube.com/watch?v=MVvbARjOwac](https://www.youtube.com/watch?v=MVvbARjOwac)  [https://www.youtube.com/watch?v=VM_2YB_GdLA](https://www.youtube.com/watch?v=VM_2YB_GdLA)  And the next will be later this week (I'll announce here the day before it happens). So far, that's going pretty well. Once I get a very basic app up and running, I'm going to livestream building little experiments on top of it, including interfacing with games, chat clients, etc. Basically just trying to lay down more video content while there are bored people out there to watch it. If you've got any requests, lemme know! # Buttplug Buttplug itself is coming along well. The backward compatibility system is mostly done, which is a huge step toward getting this distributed as part of Intiface Desktop. After that, I just need to finish up v2 message implementations (battery, rssi, patterns, etc) and it'll hopefully be ready to go. Once all that's finished, I'm going to start looking at building C# and other libraries on top of it, so all languages will use the same code underneath. Debugging that will be "fun", but it's becoming a more common pattern and there are tools out there to make it suck less. # Game Haptics Router Been getting some bug reports in on the GHR, so I put out v6 a week ago. Just changes load order of the XInput hijack DLLs, but seems to fix a few issues people were having. # Coming Up I have a 3D Printer on the way that should show up any day now, so I'll be doing some project/toy prints on that around printing face shields for donation. Other than that, who knows. Things have been wild enough over the past week that it's kinda hard to predict where things will be when I write the next update. I'm kinda addicted to NeosVR ( [https://neosvr.com/](https://neosvr.com/) ) right now too, so I suspect there will be a Buttplug implementation happening for that soon too. Until next week, Keep Buttpluggin'! - qDot --- ## Teledildonics 101 Part 3 Tomorrow 2020 03 26 5pm Pacific Time for another livestream! Finally getting into the code side of things, I'll be implementing a simple toy control app in pure HTML and Javascript, using buttplug-js, live on stream! This will be the platform that I use in Part 4 to build the final networked version for teledildonics. See you tomorrow! --- ## Teledildonics 101 Part 3 Going Live In 5 Minutes Come watch me code badly on stream! --- ## Whats Qdot Up To This Week 2020 03 30 Isolation Edition Well this first header is not something I would've expected to be writing last week. # Buttplug Teledildonics So, as you have probably been aware from my incessant posting about it, I'm doing a Iivestream series on how to build a simple teledildonics service. The first 3 parts are done and up on youtube, here's the playlist link: [https://www.youtube.com/playlist?list=PLDZBOOe-bdwNAjm018ql9KDzu5SEV_XwX](https://www.youtube.com/playlist?list=PLDZBOOe-bdwNAjm018ql9KDzu5SEV_XwX) The 4th and final part is coming up, where I actually code a teledildonics system with the app I built in part 3. I'd been figuring I'd just write a new simple protocol system to make instances of the app talk to each other. I've usually claimed that Buttplug itself wouldn't work as a good teledildonics protocol, so I was just going to make something that basically worked but probably wouldn't be worth much. Then last Friday I realized that I was completely wrong and actually I could build teledildonics with full permissions assignment/sharing from within Buttplug itself. I spent most of the weekend coding it into buttplug-js, since I'm doing the livestreams in js, but these structures will also be built into buttplug-rs, and hopefully usable from all implementations in the near-to-medium future), and sure enough, it works. I released buttplug-js v0.13.0 last night, with the structures needed to build a simple many-to-one Teledildonics system. Tested it using Buttplug Playground (yes, Buttplug apps "just work" with this, you basically connect to another server instead of the intiface desktop one), and it worked! By many-to-one, that's many controllees, one controller. Multiple people can share their toys for one front-end to control (or just one-on-one too). This just has to do with how the architecture comes together inside of Buttplug. There's still some fiddly network and permissions bits to work out, mostly in UI, but I'm hoping to have something online by next week that will allow people to have their own teledildonics control via forking a glitch.com project, or just downloading the git repo and running their own server. As patrons, you'll all get first crack at that, and I'll be posting info about it here throughout the week as I get more done.  I'm now trying to figure out how to present this in Part 4 of the livestream, as this could get pretty deep into the weeds on the Buttplug library, and I'd like to keep things as accessible as possible for that series. But this makes a lot of new options (twitch-plays-sex-toys, telegram/discord bots, etc) basically trivial from the controls routing side, so we'll see where this ends up. If you're really curious about the internals, hit me up on twitter or discord, happy to explain, but you may get firehosed. That's pretty much it for this week. The livestream then the teledildonics projects ate all my time. Until next post, which I'm guessing will be before next Monday: Stay home, stay safe, and keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-04-13 Edition) Coming at you a day late because... # Buttplug I just released buttplug-rs v0.2.1 (v0.2.0 was missing an updated README so I had to do a quick point release after)! This includes: - XInput access on windows - Test devices/manager for building self contained tests - More server functionality, including backward compat - The start of user device configuration, which puts us one step closer to being able to integrate DIY toys and making serial port hardware usable again Now that that's done, I'm hoping to start getting intiface-cli-rs building regularly, and will add a "beta" option to Intiface Desktop so people can try it out. I suspect it'll be crashy as hell for a while, as there's still WAY more panics in the library than there should be, but we're getting closer to me only having to update one codebase for new features! Yay! If you're curious about what's coming up soon, I've created a feature tracking board that's a little more readable than the Zenhub I had been pointing people to: [https://github.com/orgs/buttplugio/projects/1](https://github.com/orgs/buttplugio/projects/1) # Teledildonics Livestream I'm hoping to finish up the Teledildonics Livestream with Part 4 sometime later this week. It'll be an overview of the 1:1 teledildonics system I built on Glitch, which is available on glitch and github now: [https://glitch.com/edit/](https://glitch.com/edit/)#!/qdot-simple-teledildonics-app [https://github.com/qdot/simple-teledildonics-app](https://github.com/qdot/simple-teledildonics-app) I've had a few testers so far, and it seems to be working decently for people! That's it for now, as the Buttplug v0.2.1 release has eaten most of my past week. Until next time, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-04-20 Edition) Well, I just had a weed mint, so I guess celebrating the holiday? # Intiface CLI/Desktop Leading off with something other than Buttplug for once! After getting buttplug-rs 0.2 out the door last week, I moved on to getting intiface-cli-rs (for those of you that use Intiface Desktop, that's what's referred to as the "engine" there) working with the new library.  As of about 5 minutes ago, I have intiface-cli-rs running in what will be Intiface Desktop v17! The ultimate goal is to have Intiface Desktop running only on top of intiface-cli-rs, instead of the C#/JS split it currently has. I suspect this goal is still a bit of a ways off, as I'm still getting Rust device support to the same point as C#, but once that happens, it'll make life MUCH easier for me once that's done. And yes, this does mean I'm still developing Intiface Desktop! It's been almost a year since it's been updated. >.> # Buttplug I've made 3 unannounced Buttplug-rs releases after the initial v0.2.0 release. Most of these are small bugfixes and updates that allowed intiface-cli-rs to come together, but those should start calming down soon. Next up for Buttplug is implementing serial port access, as I get constant questions about Buttplug work for the OSR2  ([https://patreon.com/tempestvr/)](https://patreon.com/tempestvr/)) as well as the ET-312, ET-232,  and 2B estim systems. There are also quite a few people building their own hardware that would like to use serial, so it'll hopefully help them too.  Alongside that I'm hoping to start adding new messages to the system to round out v2 support in Rust. Batteries! RSSI! Toy Patterns! # Intiface Game Haptics Router If you didn't see on twitter, someone tried the GHR with emulators, and it works! So far Project64 and Dolphin have been tried and seem to work with any game that has rumble. # Teledildonics 101 Part 4 I would very much like to wrap up the livestream series this weekend, showing off the teledildonics app on glitch (which now has a few testers even!). Things have been pandemicly busy the past few weeks, which hasn't left me with much energy for trying to livestream, but I'm hoping to bounce back from that over this week. That's it for this week. Until next week, keep buttpluggin'! - qDot --- ## What Would You Like Me To Be Working On It's been a while since I've asked this and I'm curious whether my plans line up with what others are looking for from my work. I'm running this poll over on twitter right now too ([https://twitter.com/buttplugio/status/1252769543560196096](https://twitter.com/buttplugio/status/1252769543560196096)), but since y'all give me money I might actually listen to the results here. :) I definitely have some feelings on what I should be working on, but I'll reserve those for after the poll. If you'd like to point out something specific, you can leave a reply to this poll, or feel free to message me with it directly. Lib Features/Toy Support: add more hardware support to library or missing features Project Docs: dev guide, buttplug-rs book, stpihkal Apps/Games: syncydink, unity/unreal support, playground, vue/react components. Videos: toy teardowns, game reviews, etc --- ## Teledildonics 101 Part 4 Livestream April 26 12pm Pacific Tomorrow! Noon Pacific! Hopefully an ok time for those not in the Americas! Join me as I finally finish this out then go back to just doing recorded work on my own time because it works way better for me that way! I'll be recapping the last 3 parts and demoing the Teledildonics app I've built, as well as explaining the new architecture I added in Buttplug to make it happen, that will allow for all sorts of new interfaces! --- ## What's qDot Up To This Week? (2020-05-04 Edition) 3D Printing all the things! # New Hardware My Prusa i3 MK3S arrived a couple of weeks ago, so I've been pretty busy working with it over the past week or so. First order of business was printing parts for the OSR2+ ([https://patreon.com/tempestvr),](https://patreon.com/tempestvr),) which is now all done and working! You can see video at [https://twitter.com/buttplugio/status/1256682208938438662](https://twitter.com/buttplugio/status/1256682208938438662)  I'll be doing a youtube video series on this very soon, as it's a super intriguing project with an extremely lively community. It's also making me have to consider how to support multi-axis, realtime control in Buttplug, which is a good thing! Just not something I'd expected to have to do quite so soon. :) # Buttplug On the programming side, work continues on Buttplug-rs. I'm now implementing serial port support, which will hopefully mean the return of estim controls (ET-312/MK-312, ET-232, 2B), as well as controls for the aforementioned OSR2+. The biggest thing that will fall out of that is support for the fucking Lovense Dongle, which we are now getting support questions about *daily*. Lovense's website has people convinced they can't use regular bluetooth, and honestly the dongle does handle things like Windows 7, so trying to get that done ASAP. # Intiface Desktop Of course, getting new Buttplug stuff done doesn't mean much if no one but developers can use it, so I'm also working on Intiface Desktop again to add support for downloading the Rust engine on all platforms. There have been quite a few issues with Intiface Desktop and engine installation recently (apologies to those of you that have had support issues and haven't heard much back from me), so I'm hoping to take care of those while fixing this. # The Poll As you may remember, a couple of weeks ago I posted a poll both here and on twitter about what people would like to see. On here, library features came in first, follow by apps, then project documentation. On twitter, It was documentation, then library features, then apps (and a few people wanted more youtube videos!). My plans right now are: - Finish the next version of the library/CLI/Intiface Desktop. - Document things, because what's out there now is old enough to be wrong and it's starting to confuse people. - Revisit apps (playground, syncydink, Unity Support) while continuing to iterate on library. That's it for now. Unfortunately, due to the pandemic situation and my day job things are moving a bit slower than I'd like, but I'm trying to keep things as productive as I can. Hope everyone is staying safe! Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-05-11 Edition) Dear sweet mother of god # Media So Buttplug had a big week in the media last week! We were on Hacker News and r/linux. [https://news.ycombinator.com/item?id=23094477](https://news.ycombinator.com/item?id=23094477)  [https://www.reddit.com/r/linux/comments/gelmk5/buttplug_an_opensource_software_suite_for/](https://www.reddit.com/r/linux/comments/gelmk5/buttplug_an_opensource_software_suite_for/)  Between the two, the Buttplug website ended up with somewhere around 400x its normal traffic the first day, and 5 days later, I'm still at around 10x normal. Both threads were *overwhelmingly* positive, which is not really what I expect from either venue. On HN I even got a shot out from the mods and a user about how well things went! [https://news.ycombinator.com/item?id=23100615](https://news.ycombinator.com/item?id=23100615)  Super positive results overall, and lots of new people on the discord! Yay! # Buttplug On the software side, a super busy weekend of getting things running for people who'd really like to start using buttplug-rs. This meant new releases of: - buttplug-py, with lots of bugfixes - buttplug-rs, with the ability to reuse ButtplugServer (handy for our CLI) - intiface-cli-rs, which can now reuse servers (handy for dropped connections) I've also been working on Serial Port and Lovense Dongle support in buttplug-rs, though those are going a bit slow because buttplug-rs is turning into a big messy pile of code. My plan is to take a small break from those implementations to get some cleanup and documentation efforts going, then return when I don't feel like I'm building a fireplace in the middle of a fire. # Everything Else - Still wanna make a OSR2+ video or 5 soon - May make a Lovense Dongle video because I get SO MANY QUESTIONS - I'm gonna be on Australian Radio today, will post the podcast when it's up I think that's it for now! Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-05-26 Edition) Coming in a day late because yesterday was a US holiday. Not really sure I *want* talk to about what I'm up to because it's kind of embarrassing but... # Buttplug I'd been planning on working on documentation in Buttplug for most of May. At the end of April, I was tackling serial port dev, but it was getting mired in eccentricities which were taking longer than I expected to resolve, so midway thru May I did actually switch over to documenting code. *Then the trouble began.* I decided to start with the Buttplug Client code, the first code written in buttplug-rs back in October of last year, before async was even in mainline Rust. It turns out that trying to explain your code to an imaginary general audience is a fantastic way to figure out what's wrong with... pretty much all of it. Issues so far: - Client wasn't actually async (would block per message) - Server isn't actually async (no way to clone base object, so it also blocks per message) - Client event loop was a complete mess - Connector system far too integrated with serializers and Client code, can't really have server connectors easily. The list goes on. So far I've done a ton of cleanup and simplification on the Client, as well as documenting it. This has also turned into extracting Connectors, to make adding things other than our current choice of websockets easier.  Unfortunately, cleanup is not all that much fun to talk about, but my hope is that this will make everything more robust and testable, as we've had some people using intiface-cli-rs (intiface-cli is what's behind Intiface Desktop) and it's, uh, kinda crashy. Having the code documented will also hopefully make it more usable for others, and quicker to fix for me, because untangling whatever I was thinking last October when I first put this together was... different than my understanding now. # Nonpolynomial Nonpolynomial, the startup I founded that backs Buttplug, Intiface, and some other projects, is getting some branding! I've been working with a design studio on this since last August, and the new company identity is almost ready for preview! I'll also be setting up a company blog there so I can stop just making twitter threads constantly. :| So, that's unfortunately it. Not a ton of sex toy talk this week, more meta stuff. Looking forward to getting out of the cleanup/documentation weeds and back to more fun (or at least flashy) stuff soon. Until next week, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-06-01 Edition) A day late but with a good excuse. (and fair warning: the Buttplug Section will be EXTREMELY engineering heavy but there's a couple of things after it) # Buttplug Buttplug-rs ate my brain. So some of you might remember this point I made last week: - Buttplug Server isn't actually async (no way to clone base object, so it also blocks per message) As of about 5 minutes ago, the Buttplug Server is now actually async! And doesn't require cloning to be that way! Basically, I was misunderstanding how async library APIs in rust should work, and that was causing ownership and lifetime issues that basically bound the whole system to one task running at a time. Buttplug is *now* looking far more like a lazily evaluated future builder. For any call made into the server, we basically just roll up the state we need into a future, along with whatever call will leave the current task/thread context, then hand that back for you to execute whenever you like. This means every single message can be spawned into its own task.  In the end, we're still beholden unto at least some threads, because a lot of the hardware APIs I use aren't async yet. But we're getting there! And the system outside of those threads is much easier to reason about. At least, to me. So, why does this matter? For local usage, it... honestly really doesn't. This is such violent overkill as to be ridiculous. However, this now makes the library scalable from a single local server accessing hardware to being a full, 100s (probably way more but I haven't profiled it so I'm being conservative) of sessions at once teledildonics server. All in the same damn library, with a fairly clean, (what I think is) easy to use API. # Why Are You Being So Nerdy? Not gonna lie: The current dive into extremely, extremely deep architecture is a coping mechanism. Shit's pretty fucked in the US right now (I live in the San Francisco Bay Area, it's been pretty active around here), and it's a lot to deal with, even from my completely reclusive place in it all. I'm supporting protestors how I can, am donating (personal funds) to causes, and support the uprising that's showing how systematic racism has hosed this place on so many levels. Anyways, turns out, refactoring Buttplug is apparently my self care around dealing with the constant news of protests, COVID-19, and everything else. So that's why there's this sudden push. It'll end up in a cleaner library, and a hopefully sane me.  Back to your regularly scheduled Buttplugs. # Why Can't I Buy A Fleshlight Launch? Thanks to some info from people that work with Kiiroo, I've heard that the Launch is now out of stock for at least the next 3 months. Not sure if I've mentioned it here before, but Fleshlight has yanked their name from the Launch. If/when it returns, it will be the Kiiroo Launch. Whether anything else will change is a good question. Kiiroo has been changing their processing platform to ESP32 lately, so it could be that we end up with a different Launch, though I'm not expecting a better one. # Other Stuff I still keep wanting to get back to videos, but code is still my top priority for the moment. I've got a huge list of topics to make videos on once I can finally get some time though. The discord server has been more lively lately also, especially around the Game Haptics Router, with people starting to request some new and really interesting features. Looking forward to implementing some of those soon! Anyways, that's it for now. Until next time, stay safe, and Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-06-08 Edition) It's possible to feel like you're living in the future even when time has lost all meaning, I guess. # Buttplug Thanks to the obsessive refactoring and cleanup work I've been doing over the past couple of weeks, this weekend I got to a point where I could try one of the big goals of the rust rewrite of Buttplug: compiling to WASM. And it* just worked.* For those not familiar, I'll try to do an explainer here, but feel free to ask questions if this doesn't make sense:  Usually, when we write programs for the web, we use the javascript programming language, in one way or another. This can mean writing javascript by hand, or writing in another programming language that can be turned into javascript (typescript, elm, coffeescript, there's tons of languages come and gone now that do this). However, there's now a new standard that lets us compile to a format that is way faster and more optimized than javascript, called WebAssembly, or WASM. Rust has compiled to WASM for a while, but building Buttplug for it was going to require cleanup that I'd been putting off until the last couple of weeks. While it can't access websockets or bluetooth quite yet, both of those features are probably like, another weekend of work away. So what does this mean for Buttplug and it's users? Basically, buttplug-js will no longer lag behind other implementations. I can write Rust, compile to both native and WASM, and whoever wants to use it on the web will be using the same implementation that's on desktop (outside of a few things like the aforementioned websockets and bluetooth, which will have their own specific web implementations). There are drawbacks here, though.  For users, it's mostly about download size. Buttplug-js, which is typescript compiled to minified JS, is around 300k uncompressed. Buttplug-wasm is 2.1mb optimized but  uncompressed. gzip'ing gets those down to 80k/600k respectively, so I'm looking at a 9x size growth here. That said, this library isn't exactly going to be used everywhere, so I'm just going to say "deal with it" because it makes my life SO much easier. For developers, debugging this will be a little more difficult since the code isn't going to be available in the browser all the time. If the rust crashes, it'll print its stack, but it'll require writing more rust and recompiling to fix. Still though, the dream of having a single Buttplug implementation is one step closer. I thought buttplug-wasm was still a couple of months away at least, so this is super exciting. # **Game Haptics Router** Got a couple of pieces of GHR news! ROCKET LEAGUE WORKS AGAIN! I don't know how, but it does! For some reason, only in windowed mode, but still! This doesn't even require a GHR upgrade. It seems to just work. Also, someone on our discord server threw out a really interesting idea: What if your toy activated whenever you hit a button as well as whenever the game made the gamepad rumble? We could even do things like mapping buttons to different vibrators/toys, having certain buttons or directions be pattern playback, etc... It's a really intriguing idea. I'm gonna be looking at expanding the GHR to handle this in the near-to-intermediate future. Anyways, that's it for now. I'm hopefully winding down on the hardcore refactoring on Buttplug and can get back to adding features and stablizing for the next release in the next week or two, after which I can also start tackling the C# (and Unity) work. It's nice to have some light at the end of the tunnel. Until next week, Keep Buttplugin! - qDot --- ## Buttplug Unity Is A Thing Whats Qdot Up To This Week 2020 06 15 Edition AN ACTUAL PATREON PERK: I HAVEN'T ANNOUNCED THIS ANYWHERE (BUT DISCORD) YET # Buttplug Unity I've had people prodding me for Buttplug support in Unity pretty much since Buttplug began. Of course, when Buttplug began, Unity didn't really support .Net Framework 4 yet, and packaging for it wasn't something I was familiar with. Fast forward to 2020, and someone bugged me about it today and I finally found the "Custom Packages" documentation. One hand built version of Buttplug C# (had to remove our JSON Schema parser, which doesn't play well with Unity) and a package.json file later, Buttplug Unity is a thing. [https://github.com/buttplugio/buttplug-unity](https://github.com/buttplugio/buttplug-unity) This is an EXTREMELY raw version of Buttplug Unity. Basically it just brings in my handbuilt library so you can use it in scripts. You'll still need to connect to Intiface Desktop or Intiface CLI, which you'll currently have to get yourself. I'm going to make a version that comes with those, but that'll be a few days at least. If you've got questions, please hop on the #unity channel on discord, happy to help. Exciting times ahead! # Buttplug Rust Ok back to talking about stuff only I care about. Buttplug Rust continues to get the rough edges sanded off of it. This week I made it possible for mere mortals to add new protocols (It was using a macro setup that was WAY too complex for what was needed), add the new all new shiny Raw Protocol (so you can just fling byte arrays at endpoints and do things like reflashing firmware. I'm sure I won't regret this :| ), fixed some huge bugs in order of operations for protocols, and continued on general cleanup. Big problem right now is that I now need to figure out when to cut the next release and move on. This will probably entail: - Finishing up the new logging system - Making sure the Raw protocol is off by default And that's about it! Hopefully by next week. After buttplug-rs 0.5 is out, I'm probably gonna move back to btleplug for a couple of weeks to make sure the windows core can do what it needs (like, say, firing an event when a device disconnects >.>). Once that's done, I can start looking at moving the C# library on top of rust, which is the last major unification piece before Buttplug v1.0.  The end of the (3 years of) beginning is in sight! That's it for now. Until next week, Keep Buttpluggin'! - qdot --- ## Sneak Preview Buttpluggin With Qdot Console Ghr And Animal Crossing See, sometimes being a patron pays off! Access to my latest video and project, 12 hours before everyone else! --- ## What's qDot Up To This Week? (2020-06-29 Edition) Day late but HEY YOU GOT EXCLUSIVE CONTENT so I'll call it a fair trade. # Intiface Console Game Haptics Router Yet another flight of my ADHD, yet another proof-of-concept project that I won't have time to finish any time soon. For those of you that didn't see the youtube video a couple of days ago, it's now gotten a writeup in Vice: [https://www.vice.com/en_us/article/pkyk9y/animal-crossing-connected-buttplug-vibrator](https://www.vice.com/en_us/article/pkyk9y/animal-crossing-connected-buttplug-vibrator) The Console Game Haptics Router is basically the GHR for consoles. Instead of hooking into game software, the goal is to MITM the controller/console connection and siphon off rumble from that to control a sex toy. I went with Switch for this because it was the easiest thing to deal with. XBox gets fiddly depending on what version controller you have. and PS4 has a really annoying authentication scheme that is already handled in other projects, but may require hardware intervention. At some point the CGHR will support all of these, but I just wanted to get the idea and a proof of concept out, which I've managed now. In the end, the CGHR will probably be a RPi linux distro, maybe a little premade box or something that I'll sell (though obvs you can build your own too, it'll still be open source), not real sure. # Buttplug Work on Buttplug continues. I got buttplug-rs 0.4.0 out the door, which I found out is still a buggy mess during the implementation of the CGHR, so that's something to work on. Right now I'm working on overhauling the error system to... actually throw helpful-ish errors. There's a lot of debate on how to do this in Rust, and I think this will end up requiring multiple passes, but it'll still be exponentially better after the first pass is done. After that, I'm hoping I'm done with architecture fiddling for a bit and can get back to hardware support, like serial ports and more device protocols. # Everything Else Getting lots of feature requests and bugs filed for the regular GHR, which I may look into soon. Syncydink continues to exist on life support, not quite sure what to do with it. Intiface Desktop will be getting a new release at some point soon, just to handle the new Rust binary, then will probably be stripped down to something WAY simpler than it is right now and rebuilt from there, as it is way too much code for not doing a whole hell of a lot. And maybe more videos. Making the ACNH vid was fun. Until next week, Keep Buttpluggin'! - qDot --- ## Intiface Game Haptics Router V7 Released [https://intiface.com/ghr](https://intiface.com/ghr) Enough people yelled at me that I spent 5 minutes looking at the GHR and realized it wasn't handling Unity games using .Net Standard (versus Mono) correctly. All fixed, GHR should now work with Beat Saber and other games again! --- ## What's qDot Up To This Week? (2020-07-06 Edition) Being my own social media intern. # Animal Crossing New Horizons / CGHR Most of last week was spent tracking the media spread of the Animal Crossing/CGHR project. It managed to hit Vice, DailyDot, Kotaku, AVClub, and a ton of European, South American, and Chinese outlets too. Still seeing posts here and there today, but it's mostly died down now. Overall, reaction was neutral. Lots of confusion, lots of misreporting about how the system worked, but Youtube traffic bumped 100% over the past 2 weeks, got about a 10% follower increase on Twitter, and Buttplug website traffic is up 2-4x. I expect all of those numbers to fall off pretty quick. Luckily I also had a 4 day weekend, which means I'm finally rested up enough to start coding again on... # Buttplug I hadn't touched buttplug-rs in about 2.5-3 weeks, and last I'd left it there were about 200 compile errors 'cause I was ripping out and replacing the error system. Good news is, that's all done, and the error system is now far more usable in terms of typing. Before this, there were just 5 types of errors and some string descriptors for those, which were impossible to really catch and do much with. We now have many, many error types, meaning that we're now on the other end of the spectrum where you can drill down to the type of error thrown but figuring out whether it's useful is difficult. I'm going to continue ironing this out, but it's still better than it was. My hope is to now get back to a combination of hardware implementations (serial ports, lovense dongle, etc), protocols (basically everything still missing from C#), and tests. Next "fun" project outside of that will probably be looking at the FFI layers so we can start running C# on top of rust. # Everything Else We're quickly approaching the point where I'm going to have to switch off and work on other non-buttplug libraries for a bit. This includes: - btleplug, which needs both async APIs and lots of cleanup on windows/mac, but the first job is really just making sure we get device disconnects on windows - Intiface Desktop, as I need to start integrating functionality to use the rust executable in it - systray-rs, a little utility I wrote back in 2016 to make tray icon apps in rust. I'd like to have a version of Intiface CLI that uses this, so people can run it without having to bring in all of Electron. Getting to the point of working on this stuff means that the Rust library will have stablized enough to really be considered the core logic of Buttplug. It'll still be a while before it's ALL we're using, but that's at least looking like near-to-medium term versus long term work now! I'm also considering trying to make more short Youtube videos, but if that happens I'll be making another post about it soon. That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## The New Buttplug Project Logo Say hello to the new Buttplug project logo! Complete with our domain name which I'm sure we'll never get kicked off of or lose registration on. >.> It's going to take a bit to get this around to everywhere it needs to be, but you're seeing it here (ok and on the discord server because I changed the logo there) first! --- ## What's qDot Up To This Week? (2020-07-13 Edition) Gloriously boring shit! # Stickers But first, merch! Those of you that signed up at the >= $3 level in the past, uh, 7 or so months might've noticed the severe lack of stickers being sent your way. I ran out in January and hadn't ordered a new batch yet 'cause I was trying to figure out the branding stuff. The good news is, I'm fixing that! We'll have new stickers in for the new logo soon, at which point I'll be getting the backlog taken care of. Maybe those handwritten letters will happen someday too. Only 3 years behind on that one. >.> # Branding There's gonna be more new Buttplug logos soon, and I'm hoping to do the full announcement and switch over this week. Expect more previews soon. Then it's on to Intiface! :D # Buttplug In tech news, buttplug-rs is making some great progress! Back in April, I was working on serial port access for the OSR2, Lovense Dongle, etc. Things felt weird and just generally "not quite right" while adding those features, so I decided to take a break and do a little bit of cleanup. Which ended up in me rebuilding the async strategy and error system for the whole library 'cause I had made some bad decisions earlier. After 2.5 months of "break" (oops), all of these things are now much cleaner and working far better than they did before, which means I'm back to serial port work! I got Lovense Dongles causing toys to vibrate last night, and I'll be trying to figure out how to at least get the OSR2 to run with stroking commands as a start ASAP. Alongside this, I'm now to the point of writing integration tests for buttplug-rs! Now that features are mostly in, they can be tested together, and the new error system is there to make sure I fail in ways I expect. This is putting me closer to feeling ok with distributing buttplug-rs in Intiface Desktop! That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## New Buttplug Rust Logo Ain't it pretty? :D --- ## Sticker Update THEY'RE FINALLY ORDERED. I'm getting stickers of the new logo, the rust logo, and since they were on special this week, some hologram stickers of the logo too! You can put them up next to your collection of Upper Deck Team Logo Holos! Stickers should arrive here July 27th, I'll email people as I get them mailed out. --- ## What's qDot Up To This Week? (2020-07-20 Edition) Learning that begging for patrons WORKS! My twitter shall now be insufferable! # New Patrons As an experiment over the weekend (and since stickers are on the way so I don't feel quite so guilty about advertising), I decided to be slightly more aggressive on Patreon advertising on twitter. And it worked! I'm up 10 Patrons this month, putting me at over 100 for the first time since I started on patreon 3 years ago! Thanks to everyone who signed up, as well as everyone who continues to support the project. It really means a lot, and I'm looking forward to having more than stickers and updates on library implementations to offer soon (like actually getting back to updating Intiface Desktop and other applications). Remember, everyone that donates also gets a special role on our discord server! [https://discord.buttplug.io](https://discord.buttplug.io) If you join and aren't promoted, lemme know and I'll get it fixed. # Buttplug Anyways, back to updates on library implementations! Having finished the error work on Buttplug, I started back on the Serial Port device work I was doing in April. This ended up sidetracking me yet again over into Lovense Dongle handling (there's a version of the dongle that basically looks like a USB serial port), which is one of the biggest reasons people end up not using Buttplug. The dongle sucks, but Lovense pushes it so hard that a TON of people have it. I ended up spending a few days getting the Lovense Dongle working in buttplug-rs, and it now seems pretty stable. This is for both versions of the dongle (USB Serial and USB HID) on all USB supporting platforms (Win 7/Win 10/Mac/Linux). It also means that our serial and HID device support in buttplug-rs basically work, so I can get on to adding OSR2, RealTouch, Cyclone X, ET-312/ET-232, 2B, etc. (OSR2 is the only priority there).  buttplug-rs is now down to some really random missing features and bugs: - Can't tell when bluetooth devices disconnect on Mac/Windows - Can't tell when devices disconnect on Lovense Dongle (any platform) - Still missing protocols for Kiiroo toys (Fleshlight Launch, Onyx+, etc...) Once these are done (next couple of weeks maybe?), I'm hoping buttplug-rs will be at a "good enough" point to start adding FFI, so we can replace the C#/JS/Python libraries with it. But if you're wondering how this is important to you... # Intiface Desktop I'm also starting to work on updating Intiface Desktop for the first time in *14 months* (engines and config files have updated since then, this is the app itself). This is unfortunately making me realize that Electron wasn't the best idea for this, as I'd planned to update more often but kinda got stuck on buttplug-rs. However, for people to start using the new buttplug-rs engine, I'm going to have to add some new features to allow engine selection and downloading. I imagine this is going to be a complete mess, as Electron, Vue, Vuetify, and pretty much all the other libraries the project depends on have had 14 months to change, but we'll see where things end up. I also think Intiface Desktop in its current form is WAY more than it needs to be, so once buttplug-rs and a few FFI layers are stable, I'm hoping to loop back and take a look at it again.  If you're an Intiface Desktop users and have opinions, please yell them at me, definitely looking for input. While there's other news on the Buttplug Tutorial (which doesn't work), Intiface Game Haptics Router (which has new features lined up), etc, I'll end here for now 'cause those are things I doubt I'll get to in the next 7 days. I may also start announcing the new project logos over the next week as stickers arrive, there will be more posts when that happens. Until next week, Keep Buttpluggin'! - qDot --- ## Stickers New stickers just arrived! I'm still waiting on the hologram buttplug logo stickers, then I'll be shipping tier rewards out to everyone who has been waiting on them! (Sorry to everyone getting this post multiple times in their email, Patreon's mobile app was refusing to attach the image) --- ## What's qDot Up To This Week? (2020-07-27 Edition) SO MUCH STUFF OMFG # Stickers Fucking UPS lost my hologram stickers, so I'm not sure how long that's going to take to resolve. Rather than wait for the new shipment, I'm just gonna start shipping out what I've got now. For anyone waiting for stickers, expect messages saying I shipped them sometime in the next week I hope. # Lovense Toys If you have updated the firmware on your Lovense toys in the last 2 weeks, and are having problems connecting them to Buttplug or other non-Lovense apps, please let me know! There's been reports that the latest firmware update causes issues with toys. I'm gonna work on diagnosing on my end, but more reports are always helpful. # Buttplug and BtlePlug I released Buttplug-rs v0.5.0 and BtlePlug v0.5.0 yesterday! BtlePlug is the cross-platform bluetooth library that Buttplug uses to access toys. I'm currently just patching it to the point of getting Buttplug working, after which I'll be doing an overhaul on the API to bring it up to modern async rust. It got some fixes to make device disconnection notifications more reliable, and the developer API a little more ergonomic. Buttplug-rs v0.5 has lovense dongle support, serial port support (which gets us nearer working with OSR2, ET312, etc), and updated to Btleplug v0.5 to use the aforementioned device disconnection fixes. # Intiface Now that Buttplug-rs v0.5 is out, and makes Buttplug mostly usable, I need a way to get that out to people to test. This means adding it to Intiface Desktop for people to use as an engine! I'm probably going to be spending the next couple of weeks on this, because I haven't updated Intiface Desktop in a year, and it's a typescript application using a web framework, which basically means it might as well be written in COBOL now. This may take a while. That's it for this week. Here's hoping the Intiface Desktop work goes faster than I think it will! Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-08-03 Edition) Making up excuses because I haven't shipped any # Stickers BUT. There's a good reason. Stickermule is replacing my lost hologram stickers and they get here tomorrow so I can send people hologram stickers! So that's just getting bumped up to this week. And if you don't understand my obsession with hologram stickers then obviously you were not a baseball card collector in the early 90s who had multiple Upper Deck hologram team logo sticker sets. This really means something. Back to the technical shit. # Buttplug So last week I was all like "Hey I released buttplug-rs v0.5!" and now I'm going to get to be all like "Hey I released 0.6!" 'cause I'll be releasing that after I get done typing this up. It turns out that all of the Intiface work I wanted to do relies on being able to connect to remote clients/servers, and I'd kinda forgotten to implement some server stuff to allow that in Buttplug-rs when I released v0.5. So I spent the weekend getting that fixed up, as well as fixing some bugs in other parts of the system. The good news is, I *think* Buttplug-rs is mostly feature complete "enough" now. That probably sounds a little weird since it's still missing like, Fleshlight Launch protocol controls (as well as the OSR2 compatibility that multiple people are asking me about weekly), so feature complete doesn't mean "done", more just "don't have any more large architecture pieces that need to happen currently". # Intiface Good news is, while building the new Buttplug-rs stuff this weekend I was testing against the new Intiface engine, so that's ready to go too. I'll be able to release that tonight, and then get to work on figuring out what the fuck to do about Intiface Desktop, which is still going to be a nightmare (I haven't touched the code since May 2019 :( ). Anyways, that's it for this week. I feel like this is a good update, because instead of "I have [random list of features only I care about] to implement" I'm now close to saying "You can actually use some of this shit". :D Until next week, Keep Buttpluggin'! - qDot --- ## Holo Stickers Have Arrived They’re so pretty! Will get tier rewards shipped out to those waiting! Expect messages soon! Stickers are available at the $3+ tier! --- ## What's qDot Up To This Week? (2020-08-10 Edition) Being a day late, but hey, at least there's # Stickers Stickers are on their way to quite a few people now! I've got about 50% of the backed up tier rewards sent, and after picking up more envelopes and stamps yesterday the rest should go out this week. Look for mail! # Buttplug FFI work has begun! [https://github.com/buttplugio/buttplug-rs-ffi](https://github.com/buttplugio/buttplug-rs-ffi) I figured I'd try to roll a proof of concept of the API bridging layer, and it turns out that it's not too bad? Memory/lifetime management are going to be a little weird but such is life in FFI work. I've got a C# library that can at least bring up a rust buttplug client and start scanning, so now I just need to get device access together and we'll be rolling. Love it when things come together faster than planned. However, due to my dayjob being SUPER busy, that's also it for this week. I didn't get much time to work on Buttplug this week and I expect things to be a little wild thru the end of the month, but I'll def keep the updates coming and can hopefully find more time to get things together. :) Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-08-24 Edition) Missing a week of updates, but for good reason I guess? # Intiface Desktop INTIFACE DESKTOP IS BACK BABY. It's good again. Awoouu (wolf Howl) Ok well dril quote shitposting out of the way: Intiface Desktop is finally getting an upgrade after 15 months.  It took me most of the past 1.5 weeks, but I've updated Electron (from v4 to v9 >.> ), as well as the vue packages it runs on. Other than that, it's pretty much the same thing... Except now it'll download the Rust engine! :D The plan now is to get a few UI fixes in, make the Rust Engine a beta choice on windows (it'll ship default on Mac/Linux, because I'm sick of node), and ship v17, possibly sometime this week. # Buttplug With Buttplug-rs being a usable engine, protocol implementations now become extremely important, because things like the Fleshlight Launch still aren't implemented there yet. On top of that, I expect buttplug-rs being available in Intiface Desktop will dredge up all sorts of bugs, so there's going to be a development loop between Desktop and the core library again that I expect to cause lots of minor version upgrade churn. This happened with C# also. # Lovense Protocol/Firmware Updates I'm getting more and more requests to fix Lovense firmware update issues that caused their toys to stop working with Buttplug. I need to get around to this soon, hopefully happening this week. This will necessitate a release of C#, JS, and Rust. :( # Stickers Stickers continue to ship! I've got all of the US domestic stickers mailed, working my way through international now, but should be completely caught up this week. The goal now is to keep up per-month with shipments. I hope. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-08-31 Edition) A surprisingly busy week! # Intiface Game Haptics Router A request to get the GHR working with Fall Guys yesterday meant a new release. Had to fix up some issues with DLL hooking, but I think they're now finally fixed once and for all. This may require retesting of some games that had haptics but didn't seem to work with the GHR initially. On top of that, I added simple rotation support! So if you've got a Lovense Nora, Vorze Cyclone or UFO, etc, the vibration speed will now translate to rotation speed. # Intiface Desktop The update of Intiface Desktop to support Rust is almost done! The new version of Intiface Desktop will support Rust and C#, making Rust default and dropping node support altogether (you didn't want to be using the node engine anyways, trust me). The C# support is only staying for windows users who I may have broken things for in Rust, but I'm hoping Intiface Desktop will only run one engine within the next 6-8 weeks. # ... But Why? The next and much bigger question is... What the fuck is Intiface Desktop *for*? Throughout the past few years I've managed to totally fracture the platform, between the availability of libraries on native/web, the ability to build them embedded or using ID, etc. So it's hard to say *why* people should use it. I'm starting work now to figure out how (for lack of a non-businessy term here) to realign all of the Buttplug/Intiface properties to make things a little more obvious and streamlined. More on this as I figure it out. Some of the things I'd like in Intiface Desktop: - Device setup/tests - Device simulators for developers - App library, maybe some sort of launcher/installer? - Web synced app updates? Thinking in the direction of a sort of games launcher (Steam, Epic, etc) for sex toy apps, probably closer to Itch than anything. And yes, if you just want something that will run a main server and gets rid of all that crap, I'll be making a stripped down version too. :P Feel free to comment if you have things you'd like to see in ID. Anyways, that's it for now. Long weekend coming up, so hopefully getting a lot done then! Until next time, keep buttpluggin'! - qDot --- ## Intiface Desktop V17 Released [https://intiface.com/desktop](https://intiface.com/desktop) And with that, a year of work hits its first release point. Intiface Desktop v17 now defaults to Rust on Win/Mac/Linux. Windows users can fall back to C# if needed. Mac/Linux users, well, report bugs as you find them. Weekly update post tomorrow, I'm exhausted. --- ## Condensed: What's qDot Up To This Week? (2020-09-07 Edition) The last 2 days have been a sprint to fix bugs introduced in Intiface Desktop v17, of which there were (and still are) many. The biggest issue was generation and usage of self signed secure certs (which many users have set up but few may actually need, something I need to figure out), which is now fixed as of about an hour ago.  Expect a new version of Intiface Desktop out in the next couple of days, and a full update next week. - qDot --- ## What's qDot Up To This Week? (2020-09-14 Edition) Trying to figure out what's next! # Intiface/Intiface Rust CLI/Buttplug For those of you that have joined since like, May 2019: Welcome to the normal development cycle! The work on buttplug-rs over the past year has been a bit anomalous, in that it was ONLY working on the library. As of last week, that library is now out and used by people running Intiface Desktop, so now instead of updating one piece of software at a time, I'm usually updating 3. I'll either find some issue in Intiface Desktop that traces all the way back to the core Buttplug library, or add something to Buttplug that needs UI threaded up through Desktop. If either happens, I have to go all the way down the stack and back up, so it's usually 2-3 releases happening at a time. As I sent a quick note about last week, I finally brought Intiface Desktop up to date. Almost all of its dependencies were 18+ months old, so it took a bit of work to get right, and this is also the first version where (at least on windows) you can switch between engines (Rust or C#, Rust is default). Things went... a little sideways with the first couple of releases last week, as I didn't test as throughly as I should've and had issues with certificates for people using SSL websockets, but everything seems to be fixed up now, as well as having a single new feature (connected device listing on the server status page). Along the way, I also fixed some bugs in Intiface CLI RS and buttplug-rs, so the hope is that things will be fairly stable for the next week or two. # What's Next? The image attached to this post is an exercise I do every so often when starting a new phase of a project. I'll sit down with a piece of paper and a pen, and write down everything I can think of that I still want/need to do that's been sitting in my head. No reference to bug databases, project logs, etc, just want to see what all I've been holding as important. Afterwards, I'll take that list and compare it to what's in the issues sections of repos, kanban boards, etc. In this case, I ended up with... a lot. This doesn't even cover missing toy protocol implementations, which I specifically left out because it's not really a project level thing. I'm gonna be working through turning all of these ideas into bigger epics this week, then comparing against what's in the system otherwise. My expectations is that the next goal is to reduce code surface, which means continuing to work on ports like C#, JS, and Python so I can shut down the full implementation repos and have everything sitting on rust. This will massively reduce the number of places I have to pay attention to new issues coming in, which was a big goal of the rust project anyways.  I'd also REALLY like to get a simple WebRTC teledildonics system built and hooked into Intiface Desktop. That's probably about a month's worth of work, but it'd mean user-to-user teledildonics capabilities for anyone who could hit a STUN server (and didn't have to deal with symmetric NAT). After that... not sure. I know people def want a new Syncydink (possibly with encoder since the death of JFS), but that's a big project that's not super toy related so I might see if I can just organize that instead of doing it myself. Also wanna get Unreal bindings done, as I have a couple of game developers poking me about it. If you have any feelings about what you'd like to see me work on, as usual, leave comments, or message me privately if you'd like. :) That's it for this week, back to planning! Until next week, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2020-09-21 Edition) All the things! # Stickers As of about 5 minutes ago I am officially caught up on stickers! Everyone that entered their address should now have them. If you've given at $3 or above before and haven't put in your address, either add it to Patreon, or DM it to me on here/twitter/discord, and we'll get you some stickers! # Buttplug With Intiface Desktop stable enough for testing right now, I'm back to finishing up the Buttplug FFI ports. Basically, this is trying to get us to the point of the same language compatibility we have currently.  - Buttplug-rs FFI to C# is done and working, I ported the GHR to it last week and it ran fine (will release that soon) - Buttplug-rs FFI to Web JS via WASM is mostly done. I can replicate some of the JS demos with it. - Buttplug-rs FFI to Java is happening! Via a community member who I'm working with. This is super exciting, people have been asking about this for years. - Buttplug-rs FFI to Python has yet to be started but should be pretty straightforward - Buttplug-rs FFI to Node JS has yet to be started but should be pretty straightforward via Neon (a Rust to Node library) I'm considering the first 2 bullet points the big releases, Python will be nice, and node has always been kinda iffy so getting that done will just make it... less iffy. The big question for ALL of these is going to be how to distribute them through package managers. With C#/JS/Python I could just go to NuGet/NPM/PyPi respectively, and I should still be able to, I'm just going to have to pack the library along with it. Luckily the library is 3-7mb depending on the platform, so it's not like it's huge, but this may still get complicated for a bit. # Everything Else - The plan after the 2 FFI layers are done is to work on DOCUMENTATION. Rewriting the dev guide and starting the rust buttplug and FFI books, so other people can actually start using this shit. - There may be a new GHR built on buttplug-rs soon. It'll look exactly/work the same, but will have Lovense dongle support/etc now via rust. - Trying to figure out what the future of things like Syncydink is going to be. I'm... a little enamoured with this whole idea of writing rust for the web, heh. That's it for this week's update. I'll be sending another post here in a bit about something different. Until next week, Keep Buttpluggin'! - qDot --- ## Questions For The Teledildonticist I Need Your Help In order to get more videos up on the Youtube channel, I'm starting a series of shorter videos (< 10 minutes) called "Questions For The Teledildonticist" where I just answer one question per video. I'd like to get some questions together about sex toys, the Buttplug/Intiface projects, etc that I can answer on there. These should be questions that will hold up over the long term, so more "Why did you do [x]" or "How is [x] built", less "When will [x] be released" or "What are you currently doing on [x]". Some current questions I'm using to start: - Why did you call the project Buttplug? - How did you get started in sex tech? - How does the Game Haptics Router work? - Why have you rewritten Buttplug so many times? - What's your favorite piece of hardware? So, if you've got questions you'd like to see answered that fit those, please throw them in the comments to this post or DM them to me! Also let me know if you'd like me to use your name when asking the question, or if I should make it anonymous. --- ## What's qDot Up To This Week? (2020-10-12 Edition) First newsletter in 3 weeks! I swear I have a good excuse! I was literally playing Hades the whole time. This excuse may not seem good but it actually is good. You just gotta trust me. # QIUI Hack As you may have seen, I spent most of last week spamming twitter with my thoughts on the QIUI hack (tl;dr a company that makes insecure IoT equipment got very throughly pwnd after refusing to secure their work and having a security deadline lapse. User database, someone hacking in and locking all of the equipment, etc...). That ended up being surprisingly time consuming, mostly because I just have a ton of thoughts on this subject and the QIUI hack was a very good, concrete event for Many Teaching Moments. [https://twitter.com/buttplugio/status/1314251571140587522](https://twitter.com/buttplugio/status/1314251571140587522) [https://twitter.com/buttplugio/status/1314622550194839552](https://twitter.com/buttplugio/status/1314622550194839552) # Buttplug Enough about things that aren't my projects though. What have I specifically been up to the past 3 weeks? A bunch! Buttplug is getting very close to v1. In the past few weeks I've: - Added Battery level readings - Added RSSI level reading capabilities (this will take longer because I have to do a bunch of Bluetooth work first) - Added Raw messages - Fixed quite a few bugs in the core library So the v2 message spec is pretty much implemented and ready to go in buttplug-rs. I'm planning to release v0.10 of the library, update Intiface CLI Rust to work with that, then it's on to updating the FFI layers and finishing out toy support (things like the Mysteryvibe, which I have some users asking about), and we can cut v1. I was hoping for October, but at the current rate things are going (dayjob keeping me VERY busy, and Hades being addictive af), I'm gonna now be conservative on that and say November. # Intiface Desktop I'm hoping to get more features into Intiface Desktop, including the beginnings of the device panel, which at first will just let you do some quick device checks, show battery if possible, etc... I also desperately need to get crash logging in, as apparently Intiface Desktop crashes a LOT for VR Chat users? I'm not sure why and I'm currently blind since I don't have logs or stacks. :( # Intiface Game Haptics Router Once the C# FFI layer is updated to v0.10, I will most likely completely port the GHR to buttplug-rs and make it the first shipping application to use that library. This will make many people with Lovense dongles very happy. :) So, that's it for now. The finish line is in sight! There's just shiny addictive video games off to the side of it that are really distracting! :) Until next week, Keep Buttpluggin'! - qDot --- ## New Buttpluggin With Qdot Video Satisfyer One Night Stand Teardown Ever wondered what's in a $9, one time use sex toy? I bought one to find out! Turns out it might actually make for a neat modding platform! --- ## What's qDot Up To This Week? (2020-11-09 Edition) Ugh. Combination of health issues and dayjob really slowing things down, but... # Buttplug Now in the home stretch for getting Buttplug to v1. This mostly involves porting Playground, Syncydink, and the GHR to their new respective base libraries. This is taking a while as I'm also trying to hammer out what the surface API should look like before rolling to major version updates. Playground has a WASM version up at [https://beta.playground.buttplug.world](https://beta.playground.buttplug.world) Which seems to work ok, and can access the Kiiroo Keon from the browser now! # Youtube A couple of weeks ago now, I posted a teardown of the single use Satisfyer sex toy. It went over pretty well, so after that I filmed an unboxing of the Kiiroo Keon, and a quick overview of the OSR-2. Those are in editing now, hopefully out sometime soon, just trying to balance that work against the code work and dayjob. # Other Stuff I have some new toys on the way, including an Edge-o-matic (a new, upgraded Nogasm) as well as some silly stuff from Ali Express for more teardown videos. That's it for now. Mostly trying to tread water here, hopefully more exciting things soon. Until next week, keep buttpluggin'! - qDot --- ## New Buttpluggin With Qdot Video Intro To The Osr 2 Finally made my OSR-2 video! Goes over what the project is and basic usage. --- ## What's qDot Up To This Week? (2020-11-16 Edition) Preparing for a whole week off! And otherwise doing some out of the ordinary stuff. # Youtube Finished up the OSR 2 overview last week, which currently is pulling somewhat disappointing numbers on youtube but it's been hard to drum up interest in it. I've got a Kiiroo Keon unboxing video that needs editing, hoping to have that up this week. After that, I've got a ton of new hardware in within the past few weeks, so probably filming lots more unboxings soon. I'm not sure how popular these are, but they're easy content. Also hoping to startup the "Ask A Buttplugger" series ASAP, so get your questions in if you've got them! # Buttplug Developer Guide Yes, I'm actually working on documentation again! I really don't want to release v1.0 without also letting people know how to use it, so I'm writing the dev guide as part of API polishing. Adding new examples and cleaning up old ones gives me a way to figure out what parts of the API need refinement. You can read the current version at [https://dev.buttplug-developer.guide.docs.buttplug.io](https://dev.buttplug-developer.guide.docs.buttplug.io) This is updated as I push to the repo, so there should be new stuff to read every day or two. Right now the Foreword and Intro are done, and I'm working on the Architecture section. Things will slow considerably after that, as most of the code examples are in the Writing Applications section that comes next, so getting all of those right will take a bit. # Syncydink Thanks to the release of the Kiiroo Keon, I'm finding out how many people use Syncydink on mobile. Mainly because they're all messaging me going "WHEN WILL SYNCYDINK WORK ON MOBILE" So, the answer is "Soon, hopefully?". I'm really hoping I can port syncydink to buttplug-wasm soon. Even if it's the same old crappy UI on top, it'll support new toys. Funny enough, I got my first contribution request for Syncydink on Github tonight too! Poor developer has no clue what they're getting into. # Buttplug As I mentioned, Buttplug is mostly down to polishing now. There are definitely still bugs, and the bluetooth core is still an absolute mess, but I'm more worried about getting to v1 then fixing things with an actually released library than I am trying to refine forever. I'm off work from my dayjob all of US Thanksgiving week, so I'm hoping to spend quite a bit of time working on code, docs, and videos! Until next week, Keep Buttpluggin'! - qDot --- ## Early Access Kiiroo Keon Unboxing And Analysis New video, released for patrons a day early! Watch me yammer for like 20 minutes about the Kiiroo Keon. I really gotta remember how to be entertaining at some point, but at least it's informative? --- ## What's qDot Up To This Week? (2020-11-23 Edition) I'm on vacation all week! Which means... I'm playing a lot of No Man's Sky, unexpectedly. I guess I find inventory shuffling fun? But also, there's... # Buttplug Developer Guide Still working on the developer guide! I've gone ahead and started editing the actual published site at [https://buttplug-developer-guide.docs.buttplug.io](https://buttplug-developer-guide.docs.buttplug.io) Because the old code/guide was going to be obsolete anyways, so might as well let people follow as I build the new stuff. The Rust and C# examples are mostly together, but there's still a lot of editing to do for the surrounding text, and I keep finding small things in the API I want to tweak. If you use Buttplug C# with Nuget, you'll see the 1.0.0 branch in development if you turn on pre-releases. These should be mostly stable, but may be missing functionality. I'm working to fill this in, and your best bet for updates is watching the CHANGELOGs at  [https://github.com/buttplugio/buttplug-rs-ffi](https://github.com/buttplugio/buttplug-rs-ffi) # Other Apps There's some really interesting new apps that are coming out lately. They don't have anything to do with Buttplug specifically, but I like supporting other people who are building toy control apps, so: - Xtoys - [https://xtoys.app](https://xtoys.app) - Really neat control web/mobile interface with all sorts of add-ons for remote control (using WebRTC!), sound reaction, web integration, etc. Not open source, but free and fun to play with! Also supports estim and hismith machines! - OpenFunscripter - [https://github.com/gagax1234/OpenFunscripter](https://github.com/gagax1234/OpenFunscripter) - Open source video scripting utility! JoyFunscripter isn't being updated anymore but still is distributed, OFS is aimed at being an open source alternative. Short newsletter this week because while I don't have much to say about the dev guide, it's taking up almost all of my time. Between writing the new content and iterating on the different language APIs, it's a ton of work, but I'm hoping in the end it'll make the library useful to someone other than me. Hoping to get back to making youtube videos this week too, have a swank 4k camera on loan that should be fun to try out. Prepare to see my horrible complexion in high resolution! Anyways, that's it for this week. Happy holiday to all of those having holidays this week, and until next week, Keep Buttpluggin'! - qdot --- ## End Of Syncydink Development Heads up in case anyone wants to jump ship before the subscription charge date (Dec 1). I'm dropping development of Syncydink, which is more to say I'm just going to admit defeat and not promise updates anymore. I'm going to archive the repo but leave it up just in case other people want to fork it. It might get updated in the future, but it won't be by me. Long story short, Syncydink needs a complete rewrite. The way that web app development works, if you don't keep up with the toolchains, things rot VERY quickly and you end up having to strip them down to the core and restart. Syncydink hasn't seen a significant update in over 2 years, and was originally written as a one-off to test some initial ideas about Buttplug. There are now many other players out there. I came to this decision after working with trying to get Playground going over the past week with the new WASM stuff. While WASM saves me a significant amount of time for my own development, I realized how much work updating old apps to use it will take. There's just no way I can say I can get Syncydink fixed anymore. It's just been too long, and I've got too much else going on with maintaining the core Buttplug library, Intiface Desktop/GHR, etc. Also, I just do not use or like video sync. I really have no interest in it as a platform and would much rather work on games and other interactive content. Does that make video sync bad? Not at all! Companies like SexLikeReal, Handy, and communities like Eroscripts ([https://eroscripts.com)](https://eroscripts.com)) are all doing quite well with video sync. I just personally don't care for it and don't want to spend my extremely limited time on it. There's already one dev that's been submitting patches to Syncydink lately, and I'm going to talk to them about possibly taking over maintenance. If that happens, I'll post here as well as on eroscripts. If you were/are supporting me in hopes of Syncydink updates, I totally understand if you unsub. Thanks for the support so far. - qDot --- ## What's qDot Up To This Week? (2020-12-07 Edition) Redoing shit. :( # Buttplug Most of the past 2 weeks has been spent working on the Buttplug Developer Guide. I've got the first 3 chapters (good enough for v1 release), with Rust and C# examples in. Pretty happy with that overall! [https://buttplug-developer-guide.docs.buttplug.io](https://buttplug-developer-guide.docs.buttplug.io) Also, there are now beta versions of both C# and JS/TS/WASM on nuget and npm, respectively. So if you're building apps, look for prerelease packages there if you want to play around and help test/debug. Late last week I started working on getting the Javascript/WASM examples together, and that has... not gone so well. Unfortunately, the architecture I was pursuing for WASM just didn't work out. I was trying to write *everything* in Rust and compile to WASM, which means even the JS/Typescript method calls would access WASM/Rust. This meant bending JS ideas into Rust itself, and that got... gross. Those of you that follow the twitter account got to see some of that. Over the weekend, I decided to finally just restart using the same Rust FFI code that C# currently uses, except now compiled to WASM, with my own Typescript to create the Client API. This is working out far better, and I hope it should be done in a week or so, which will both put me back on track to finish the Dev Guide soon, and also means that updating the WASM code in the future will suck less. # Syncydink Welp, lots of people unhappy with me about dropping Syncydink. I've lost about 5 patrons so far, which is honestly less than I thought I would, so thanks to those who've stuck around. The reason I cut development when I did is because someone else needs to take over the project. There was lots of low hanging fruit to fix and even some new pull requests to bring in, but if I started updating again, it'd raise expectations of even more updates after that, and honestly, I just do not fucking care about video sync.  Video sync has a huge community, and one of the tenants of working on the core Buttplug library is "never get involved in a community you do not have direct interest in". Due to sex software being about, well, sex, you either need to be directly interested in the subject matter of the software, or monetarily interested in producing it, or ideally, both (looking at your, furry porn game producers on patreon). Without those, you're going to have a Bad Time. With video sync, I'm not in either category, so I'm hoping someone else will pick up the idea of a web based hardware synced movie player and go make themselves so big patreon/subscribestar/whatever dollars. # Everything Else The amount of new hardware I have in for testing and videos is just fucking ridiculous. I've got an Edge-O-Matic ([https://maustec.io/pages/nogasm),](https://maustec.io/pages/nogasm),) a few WeVibe toys, a Hismith on the way, etc. I am very much looking at getting this library and documentation shit done so I can work on integrations and apps. GHR w/ Buttplug C# FFI will hopefully be out soon. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## Metafetishcom And Metafetishclub Shutting Down In my continuing goal of trying to maintain less zombie brands, I'm finally shutting down the Metafetish brand to focus on Buttplug/Intiface. For metafetish.com, this doesn't mean much. Blog hasn't been updated in years, and I'm getting a new blog for Nonpolynomial that I'll be doing long form posts too. I also just have no interest to be a general sex toy blogger anymore. I've kinda got a different perspective than when I started Slashdong/Metafetish, and my needs have changed with that. The blog itself will stay up on the domain in perpetuity (don't wanna link rot it), though with the static engine it used, it's also up and indexed on internet archive until whenever. The forums at metafetish.club will be live until Jan 1 2021, at which point I'll set them read-only. The info on them is either really old stuff about Buttplug, or MK312 tech stuff that needs to move elsewhere (somewhere managed by someone actively involved in the scene, because I'm also extremely done with that project), so it's not a huge loss. Anyways, not much change here. Buttplug/Intiface are still things, the youtube channel will continue, and I'll announce the new blog in the next week or so, which will have a heavier tech focus (i.e. incredibly dense programming posts because if I'm gonna level up in the Rust community that's how you grind). --- ## What's qDot Up To This Week? (2020-12-21 Edition) DAMNIT V1 WILL HAPPEN. SOON. # Buttplug So close. So damn close. The WASM layer has been reworked and is now far more sane. C# has a few testers, all of whom seem relatively happy with the functionality. Dev Guide examples are up and working for Rust, C#, and JS Outside of fixing massive memory leaks during certain unique types of usage ([https://github.com/intiface/intiface-cli-rs/issues/9,](https://github.com/intiface/intiface-cli-rs/issues/9,) just fixed and released new libraries/binaries) and getting READMEs updated, Buttplug v1 is ready to go. Next few days will be me nailing down that last documentation, then writing a blog post and calling this done. We'll see how long it takes, but I'm not really set on any specific date for this release because it's really a beginning, not an ending. There's going to be tons of bugs to fix and new features to add once v1 is done, but at least I can start rev'ing real versions at that point versus just promising new functionality. I'm off from my dayjob from Christmas thru NYE, so I'll have a week to figure out what's next. # Everything Else Soon after v1 drops, outside of figuring out what's next, I'd like to: - Updating the website for the first time in many many months. - Bring GHR up to v1 and add Intiface Desktop connectivity so people don't have to wait on me for updates - Bring VAMLaunch up to v1, same deal with Intiface Desktop. - Get Buttplug Playground onto WASM, mostly done, just need to release it. - Fix the fucking tutorial. - Update Intiface Desktop to remove the C# option that hasn't worked anyways, and get us down to just using the Rust engine. And maybe adding Sentry logging for the constant crashes I'm expecting from that. - Continue writing the "advanced" part of the dev guide, which will cover some of the deeper parts of the library. I also would like to do some blog posts about v1 development, and maybe some youtube videos? We'll see how much energy I have. Hope everyone is having some sort of decent holiday or something. Until next week, which will hopefully be post-v1 release, Keep Buttpluggin'! - qDot --- ## Whats Qdot Up To This Week 2020 12 28 V1 Launch Edition LAUNCHING V1. WOOOOOOOOOOOOO. # Buttplug I LAUNCHED V1. WOOOOOOOOOOO. Yeah that's pretty much it. Rust/C#/JS V1 are out, announced on the Nonpolynomial blog here: [https://nonpolynomial.com/2020/12/28/buttplug-hits-v1-milestone/](https://nonpolynomial.com/2020/12/28/buttplug-hits-v1-milestone/) Made reddit and HN (Ok I posted both of these but they trended well enough!): [https://news.ycombinator.com/item?id=25561392](https://news.ycombinator.com/item?id=25561392) [https://www.reddit.com/r/rust/comments/klvd4o/buttplugrs_hits_v1_milestone/](https://www.reddit.com/r/rust/comments/klvd4o/buttplugrs_hits_v1_milestone/) It's been a good day! Mostly been fielding questions and replying to comments, but as usual, everything was pretty positive. The rest of the week is going to be continued cleanup, as well as starting work on updating: - Intiface Desktop: yanking out the C# stuff, adding in downloading of the new device config file. - Intiface Game Haptics Router: Updating to use C# v1, connect to Intiface Desktop, maybe finally fix process detaching. - VAMLaunch: Updating to use C# v1, connect to Intiface Desktop - Playground: Updating to v1 - Buttplug Unity: Possibly updating to v1 but may run into architecture issues here. - Buttplug Twine: Updating to v1 - Buttplug.io website: Finally update front page, move apps/dev links to pointing at awesome-buttplug repo - awesome-buttplug repo: Actually fill this in with projects. Was gonna do this before v1 but just wanted to get v1 done. - Documentation: Continue filling out the Developer Guide, tighten up language API docs Ideally I could finish all of this (minus documentation) in the next couple of days, but that's a pretty long list now that I've typed it out, so, uh, we'll see. # What's Next That's Not Maintenance Here's some possible upcoming projects: - OSR2 Support, finally. - Handy Support, once FW3 drops. - Python Language support - C/C++ Language support (god I hope I'm not the one that has to write this :c ) - Poking at that whole teledildonics/device forwarder idea in Rust And who knows, maybe something actually fun, too. :| But, for now, I'm just relieved I got v1 out. Until next week, Keep Buttpluggin'! - qDot --- ## Software Update Blog Post Now that Buttplug is post v1, I'm trying to be a little more public in the "what I did" stuff, so the Monday newsletter here can hopefully focus more on "here's what I plan to do" with the ability for you to give me feedback. This is the first blog post I've made with updates from the past 2 weeks, including a lots of library updates and a new GHR version. --- ## What's qDot Up To This Week? (2021-01-11 Edition) Fuuuuuuuuuuck. # Buttplug Well, it took me 3.5 years to get to v1, and now ~3 weeks to get to Buttplug v2. \>.\< Since (and slightly before) the release of Buttplug-rs v1, I've been working with developers to find issues with the library. This has led to quite a few bugs being squashed, but I found a lot of them were coming from the same part of the system that has to do with how we handle distributing information between different components. Taking a deeper look at this, I realized the library is basically doing it completely wrong. It's not super surprising, since this is part of the system I wrote well over a year ago when just starting the buttplug-rs project, and I was still very new to async Rust. However, it'll mean major changes in the surface API of buttplug-rs, so that requires a major version roll. My hope is that fixing this will make things far more reliable though, and it should hopefully be done this week. The FFI layer shouldn't really change much, so this is really only of concern to anyone using Rust directly, and I'm not sure anyone other than me is doing that. >.> # Intiface Game Haptics Router The GHR v10 is out! You can sorta detach now! You can hook it up to Intiface Desktop! It runs on buttplug-rs! Really happy to get back to work on this and make it better. It still needs a ton of UX work, and I'm now starting to scope out handling stroking toys like the Keon/Launch/OSR2 with it, though that's gonna be... weird. # Intiface Desktop With the first major GHR update done, I'm going to be working on Desktop next. I'm really not happy with where Desktop is at the moment, as it just... doesn't make sense for what it is. I'd like to simplify what's there currently, and add some utilities like device checks, configuration, etc... to actually make it useful. The first release will probably be mostly under the hood changes to remove the C# engine, get device config updates working again, etc, but after that, expect more drastic feature work. # VAMLaunch With GHR v10 done, I'm hoping I can port that code over to update VAMLaunch. I'll be reaching out to the VAM community to see what other things might be needed too (like maybe renaming it something other than VAMLaunch since the launch is no longer a thing? :3 ). # New 3rd Party Projects A couple of new 3rd party projects to announce! - Aethersense - [https://github.com/Ms-Tress/AetherSense](https://github.com/Ms-Tress/AetherSense) - New FFXIV project that seems to be picking up steam. I've been working with the dev to diagnose buttplug issues, so it's getting lots of support from my end too (even though I still don't play FFXIV yet heh). - Osu!Toy - [https://github.com/hornyyy/Osu-Toy](https://github.com/hornyyy/Osu-Toy) - Fork of the Osu! rhythm game that has Buttplug support. Ok, back to bug squashing. Until next week, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-01-18 Edition) Buttplug v2! # Buttplug After discovering some nice structures in tokio v1 that would allow me to massively clean up some of the nastier parts of Buttplug, I spent the last week doing just that. tl;dr Using the library in rust sucks way less now, using any other language on top of the FFI looks in no way different. >.> This ended up being a ton of work that I'll hopefully now be writing some blog posts about, but everything from btleplug up through the FFI libraries and the CLIs got a upgrade. Also, for anyone using Intiface Desktop, Lovense dongle support got quite a few bug fixes. Also also, there's now support for the Lovense Ferri, and the Lovense Edge 2 works with all versions of Buttplug old and new. Also also also, gonna try to start work on Satisfyer devices, which are *weirdly* cheap. [https://us.satisfyer.com/us/](https://us.satisfyer.com/us/) # Intiface Desktop I really, really, *really* need to get back to updating Intiface Desktop. I'm hoping buttplug is at a spot where it can stay in a holding pattern for the next month or so, outside of updates for the Handy and maybe the OSR 2. I have some simplification of Intiface Desktop started, and I'll do an intermediate release once that work is finished so we can have nice things like crash reports and less people trying to use the old C# engine. After that, I'm hoping to start adding new features like a device configuration tab, and maybe, just maybe, starting on remote features (aka teledildonics) over WebRTC. # Intiface GHR Haven't heard much from anyone after the GHR update last week, but I'm assuming it at least works. Still would like to get stroking devices in there soon too. That's it for now. Not much of an update because I've been so heads down on v2, but hopefully I'll bounce back quick. Until next week, Keep Buttpluggin'! - qDot --- ## New Buttpluggin With Qdot Video Lovense Edge 2 Unboxing Threw together a quick video to compare the Lovense Edge 1/2, talking about the differences in the new product. All in all, it's a pretty decent upgrade! (Weekly update tomorrow) --- ## Periodic Checkin What Do Yall Want More Of Ok, I haven't run one of these in a while, and I'm quietly hemorrhaging patrons lately (while still getting some new ones, so hi new ones!), so: Is there something y'all want more of? Check all that apply in the poll below! Or if you've got other things you'd like to see, leave them in the comments or feel free to message me privately. --- ## What's qDot Up To This Week? (2021-01-27 Edition) Tests! # Buttplug This has been another week of finding out exactly how broken Buttplug is. Lots of firefighting as bugs show up in different parts of the system, though most are in the core buttplug-rs library. The good news is that a lot of these bugs are being found by new devs, who are pretty good about reporting them and helping to test after patches, so the project is still seeing growth. The bad news is that a lot of these would've been avoided if the system had better tests. With that in mind, I'm now trying to fill out more base test bases for the system, and working on getting tests in for the FFI layers also. It's going to take a while to get things back to where they were with C#/JS (both of which had multiple years of work behind them before they were retired), but anything more than we've got right now will be nice to catch things up front.  # Websites I spent the weekend updating project websites! [https://buttplug.io](https://buttplug.io) is now up to date with the new logo, and updated app lists via... Our new awesome list, [https://awesome.buttplug.io!](https://awesome.buttplug.io!)  For those not familiar, "awesome lists" are basically a "curated" list of applications in a certain topic/library/etc area. Popularized by the web dev community, I'm trying to keep one for Buttplug apps. If there's anything I missed in the list so far, please file an issue on github or just comment here and let me know! # Intiface Desktop Alongside adding more tests to Buttplug, I'm working on Intiface Desktop v20. While this is mostly cleanup to remove the older engine support, I'm also starting on the Device Panel, which will allow users to check their devices in Intiface Desktop before connecting to applications. The fact this wasn't in from day 1 is horrible, but once again, now is better than never, heh. That's it for now, back to writing tests. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-02-01 Edition) Staring at polls. # The Patreon Poll Results So last week I decided to try one of my "is there anything else y'all" want polls. The results: - No one wants more updates (fair) - 1 patron each would like more youtube or merch - 3 patrons would like more application work - 17 patrons are like "keepin' on truckin', my guy" Keep on truckin' I will. I lost ~10% of my patrons over January, but I'm approaching year 4 of Patreon now. I've realized that there are people that are gonna stick with you, then there are people who are gonna check things for a month or two and then peace out, but I haven't quite come to terms with that yet and I need to. It's a little challenging, being surrounded by content creators pulling huge patron/intake numbers, while I kinda do my own code thing that is not exactly as instantly gratifying as making audio/visual content, but it's the nature of the beast. The good news is, I'm not really lacking for motivation or anything, so that's nothing to worry about, I'm more just reevaluating if I'm making a go of this in the right way. I'm actually pretty happy with my output at the moment, and that's what really matters. With that in mind, on to... # Buttplug I'm trudging along on buttplug-rs v2.1 now, which is shaping up pretty nicely. There's more tests in the system (kinda shocking how many things didn't throw errors at ALL), as well as more capabilities to test different parts of the system. I'm really hoping this shores up stability some, because I'm still getting a worrying amount of crash reports. I also went ahead and added a tiny bit of new device support, in the form of the Nobra's Silicone Dreams Twincharger. Made some video/tweets about that here: [https://twitter.com/buttplugio/status/1356102567692931073](https://twitter.com/buttplugio/status/1356102567692931073) This is exciting because not only has Nobra been around for longer than I have in sex tech, it's also a serial port toy, which means this is going to be the first public test of the user device config system (as people have to identify which serial port the toy is on). This is a system I built in C# 2 years ago but it never got the UI in front of it for people to use, so I ended up porting it blind into Rust. It'll be usable in buttplug-rs v2.1 via CLI (WASM serial/HID is coming, but that's like, months away), but it'll need UI updates to Intiface Desktop to make it truly useful, so that'll take a bit more. # Intiface Desktop After buttplug-rs v2.1 ships later this week, I am really hoping to have time to concentrate on ID v21/v22 finally. v21 will be a fairly small update for stripping out all of the old code and just making sure the rust engine works with external device configs (so if, say, lovense releases a new device, I don't have to recompile and update the whole engine). v22 will have the new Device Panel, which will allow for device testing and setup. That's where things get exciting. # Youtube and Other Stuff I have so many toys sitting on my desk right now it's fucking ridiculous. There's new Lovense toys dropping tomorrow (Diamo cock ring and Lush 3), I've got Satisfyer toys in to add to the library (will take some extra bluetooth work), and I'm still trying to figure out what I want to do about this Hismith fucking machine I just got and all. I also just received a decibel meter, which I'll be using in a new series of loudness testing videos for youtube. A lot of places I hang out have people that just absolutely freak about the idea of their toy being heard, so I figure having some tests up that people can reference should help. It's a bit of a stretch outside of the pure technical stuff I've been aiming toward, but it seems useful. Speaking of, I have been spending the past month kinda figuring out where I want to go with Buttplug and it's various communities, as well as what stuff I'd just like to have someone to point to and say "check out their stuff". I'm starting to get a good direction on that now, so I'll be talking about that more next week. Ok, enough introspection for now. Until next week, Keep Buttpluggin'! - qDot --- ## Blooper Reel Qdot Tries Vrchat Teledildonics Well I promised bloopers in the tiers at one point, but the past couple of years are mostly me yelling at code so not many interesting ones have happened. I've been trying VRChat + VibeGoesBrrr this weekend, which has taken some learning to try and get the avatar workflow correct. Above is a video of me trying to intersect a grabbable object in VRC with a collider area to try and trigger a toy and it's... not working well. --- ## What's qDot Up To This Week? (2021-02-08 Edition) Figuring out what it is I do other than library work... # Buttplug Got buttplug-rs v2.1 out the door over the weekend. After a few hiccups due to still not having *quite* enough test coverage, I think we're good. I'm hoping I can keep the library in a holding pattern for a bit now while I work on other things. Also, for anyone that wanted Nobra's support, it's there but somewhat difficult to get to at the moment. If you're interested in it, message me and I can help out. # VAMLaunch Getting more questions about VAMLaunch lately, so gonna fork that and try to maintain it on my own, while having to also admit that I have *zero* clue what I'm doing with VAM. But I can at least get the toy support updated and hope someone will take care of the VAM side, or that what's there from 18 months ago still works. # Intiface Desktop Intiface Desktop v20 is in progress now, mostly cleaning up stuff that's no longer valid since I dropped the other engines and updating dependencies, as well as finally bringing in device config file updates for the Rust engine (so adding new devices to protocols we already have won't require a recompile of the engine). Gonna try to get that out soon to make sure those base changes work, then get back to work on new Intiface Desktop features. I admittedly have no idea what I want Intiface Desktop to be at this point. I'd definitely like to get more device management and simulation utilities in, but right now Buttplug/Intiface as a whole are stuck in this weird situation where they are accessible in SO many ways that no one is quite sure how to do anything, and it's really confusing to pretty much everyone involved. So should Intiface Desktop host applications (like Steam/Epic/Itch/etc), or should it just stand alone and support outside connections, or what? Gotta figure that out. # Web Apps and Support Libraries Playground and the tutorial are still running on buttplug-js, and Buttplug Unity/Twine are on v0.x stuff too, so I need to drag those into the new world. This will be happening between all of the aforementioned work. Luckily I've got people using both Unity and Twine currently, so I have help on testing and advice. That's it for now. Looking forward to bringing everything up to date and creating new stuff! Until next week, keep buttpluggin'! - qDot --- ## The Handy Support Update Yaaay, finally get to give patrons some early news before everyone else gets it! :) Just talked to the engineers at SweetTech (the company that makes the Handy). New firmware *should* be out today, which will support BTLE, and therefore should mean Buttplug support is possible. There's proof-of-concept code already available. I'm going to try to work on support this weekend, and will update when that's available. --- ## Handy Support Now In Buttplug Intiface Desktop As of about an hour ago, support for The Handy stroker ([https://thehandy.buttplug.io)](https://thehandy.buttplug.io)) is now available in Buttplug. It basically acts similar to the Launch or Keon, allowing setting of goal position and movement time. Seems to work pretty reliably. Gonna try to get a new version of VAMLaunch out, though I currently have no way to test that so I'm gonna have to figure that out. Note that you'll need to be on Handy Firmware v3 Beta 2. More info on how to get that on the Handy subreddit: [https://www.reddit.com/r/theHandy/comments/li89ou/handy_end_of_january_update/](https://www.reddit.com/r/theHandy/comments/li89ou/handy_end_of_january_update/) --- ## Vamsync Formerly Vamlaunch V2 Hot of the build server, VaMSync (I renamed it because the Launch isn't a thing anymore) v2 is out. Looks exactly like the newest GHR because I ripped all of my UX code from that. Works exactly the same as VAMLaunch, but now supports newer hardware. --- ## What's qDot Up To This Week? (2021-02-15 Edition) Being mad at The Handy? # Buttplug Been a week of bug fixes and hardware updates in Buttplug. The biggest thing, which I've already announced here, is support for The Handy ([https://thehandy.buttplug.io](https://thehandy.buttplug.io)). This took more work than it really should've because they did weird shit with their protocol (trying to mimic mine) without asking me for advice, but I've yelled at them about it and hopefully it's the last time. Hardware seems happy now. Also fixed some MAJOR bugs (buttplug would ignore StopAllDevices commands, as well as crashing if you tried to set a toy to full vibration speed!). More firefighting than I'd like, but tests are going in with every fix, so hopefully we'll move toward better coverage and less dumb breakage. # Btleplug This is really a bit orthogonal to what I cover on this discord, but as a quick update, the bluetooth library that I maintain is now seeing a ton of work from the Rust community! This should hopefully mean more stable bluetooth support in Buttplug in the next few weeks. Really excited about this. # VAMLaunch I'm running builds to update VAMLaunch in the background while writing this post, so I'm hoping v2 will be out tonight or tomorrow. Keon support seems fine, and it should have Handy support too. # Intiface Game Haptics Router If you use the Intiface GHR, and are on v11-13,** YOU WILL NEED TO MANUALLY UPDATE.** I broke the updater in v11 and it stayed that way more a bit. Download v14 from [https://intiface.com/ghr](https://intiface.com/ghr) # Other Stuff Since buttplug-rs/c#/js are now stable, most of my time not spent firefighting is spent upgrading older software. Needs to happen but good lord there's a bunch of it. Buttplug Playground has been updated to buttplug-js v1.x. It basically works but def has bugs still. Work continues slowly on Intiface Desktop v20. I think it's mostly ready to go, just trying to make sure I don't flub yet another release, as has been the case with pretty much everything lately. I started porting Buttplug Unity to buttplug-C# v1.x, but I have completely forgotten how Unity works so this is slow going. Once Unity and Intiface Desktop are done, it's on to Buttplug Twine and the Intiface Tutorial. After that, I *think* I'll have dragged everything I've developed and am still maintaining up to the current library version. Hoping to crank out some new Youtube Videos soon, finally got my desks cleaned up enough to set up my filming equipment again, and I have tons of toys to look at. Also hoping to start a new series where I go over how different programs that use Buttplug work (like the GHR, ViRo Club/Buttplug Unity, etc). I'm going to be adding Youtube Video Credits as a tier reward again, will be sending out updates for that in the next day or two. Ok gonna cut things off here for now. Until next week, Keep Buttpluggin'! - qDot --- ## Want Your Name In The Credits In My Next Youtube Video Hello, special people in my >= $10 tiers! I'm going to be adding a new perk to all of these tiers, the ability to get your name at the end of my youtube videos for as long as you're a patron at these levels! However, due to the nature of my videos and some people possibly wanting to stay anonymous or just not be included, this perk is **OPT-IN.** If you'd like your name (doesn't have to be you real name, or even your donor name, just not a URL or something), **please send me a message either here on Patreon, or on discord or twitter if you're in touch with me there, and let me know what you'd like it to be.** My next video will probably be out in the next few days, so get back to me **soon **if you'd like to be included! --- ## New Tier Reward Youtube Credits At The 10 Month Level Interested in having your name posted in my youtube videos? Then sign up or bump up to the $10/month or higher level! For anyone at that level or higher, I'll be offering **OPT-IN **credits on my patreon video! There will be credits screens at the end of videos I make (which there will hopefully be more of soon), and you can have your name (either patreon name or other name that you specify) there for as long as the video is on youtube! This is opt-in because I realize the nature of my videos may not be something that everyone wants to attach their names to in public, so it's something that I want to make sure people consent to before I throw their name on there. :) Also note, changing tiers in Patreon is... weird, so if you're already subscribed at a lower level and want to bump up, please poke me when you do as I'm not sure exactly how Patreon handles that in terms of notifying me. --- ## New Video Buttpluggin With Qdot Lovense Diamo Overview Everything you ever wanted to know about Lovense's new bluetooth controllable cockring. Including silly sound tests. --- ## What's qDot Up To This Week? (2021-03-01 Edition) Not much, honestly. It's been a Extremely Fucking Bad couple of weeks out in reality, so things are going very slowly right now. # VR But at least it was a rough couple of weeks with new toys? Got a Valve Index + Full Body Tracking setup, in order to both get more testing in with the GHR (where I've had people yelling at me about Vive issues for years now), as well as just having an overall better experience with Neos and VRChat. I am now mildly obsessive about VR Worlds, so expect more content in that direction soon. # Buttplug Only real Buttplug development that's happened has been bugfixes. There's a TON of work happening on the btleplug library (which handles bluetooth for Buttplug) thanks to some contributors, so I've updated that, as well as fixing some log messages that were possibly causing crashes in Intiface Desktop. A new Intiface Engine was released yesterday that I'm hoping will make life way better for those afflicted (which now, thanks to the aforementioned VR worlds obsession, includes me :| ). # **Intiface Tutorial, VaMSync** After being broken for at *least* 18 months, I've now ported the Intiface Tutorial to buttplug-js v1.x. I still wouldn't exactly call it helpful, but it's something. I also updated VAMLaunch to become VaMSync, but given that I don't really use or even know how to use VaM, I'm not sure how successful that's been.  # Everything Else Here's what's on my TODO list right now: - **Intiface Desktop updates:** ID 19 is 6 months old now. This needs to happen so badly. Mostly quality of life updates to start but then moving onto larger additions like device management and configuration, simulation, etc. - **Device additions:** Switch Joycon, which shouldn't be too hard. OSR-2 still coming, but needs the Intiface Desktop updates for port setup. - **Documentation:** I need to finish the developer guide, update STPIHKAL for the first time in like 2.5 years, and rework the tutorial to start from the point of "So you've decided to buy a computer controlled sex toy" - **WebRTC:**Last but probably most important to the platform, adding WebRTC as a connector. This will (hopefully) easily allow people to use their phone as a Buttplug hardware server while using their desktop as a client (i.e. VR/movies on desktop, with toy controlled via phone, since desktop bluetooth isn't reliable for everyone). It also really opens up a lot of remote control situations, as [https://xtoys.app](https://xtoys.app) has shown. - **Python Library: **I was really hoping someone else would do this but given that I've had people show up then give up on Java, Kotlin, and C, I think the FFI extensions are gonna be all me. As always, if you have things you'd like to see implemented, comment or poke me! That's it for now. Here's hoping things start sucking less. Until next week, keep buttpluggin'! - qDot --- ## Whats Qdot Up To This Week 2021 03 08 Update VRChat, mostly. I wasn't kidding about the virtual world obsession thing. # Buttplug But I also fixed some Buttplug stuff! v2.1.7 just went out the door before I wrote this, fixing some issues with Vorze devices and the Handy for software using older buttplug versions like ScriptPlayer and Syncydink. Also fixed some issues with Kiiroo vibrators. Intiface CLI (aka Intiface Engine) v33 is in CLI now, should release in the next 10 minutes or so. And... that's kinda it for this week, really. I'm still dealing with a pretty massive amount of burnout so getting code work in has been *extremely* difficult. Fucking around in VRChat has been great though, doing a lot of thinking about future projects, interactive systems, etc. I'll hopefully have more to post on this soon. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-03-15 Edition) Weird week. Weird fuckin' week. # Ear Haptics Yeah ok so that whole VRChat thing? It's been givin' me *ideas*. We've already conquered vibrating toys in VRChat fairly thoroughly via plugins like XXXHaptics and VibeGoesBrrr. There's a lot to be done on interfacing, but that's truckin' along just fine. But what about the rest of the body? For vests/hands/feet, there's companies like bHaptics and oWo (yes there's a haptic company named oWo and I think they have zero furries on staff). bHaptics also makes a vibrating face mask for VR headsets for some reason. But what about ear pets and headpats? Well, we ain't got shit. Or didn't until last weekend. Here's a picture of me in a rig I built in about 4 hours on Saturday: [https://twitter.com/buttplugio/status/1370940208523350021](https://twitter.com/buttplugio/status/1370940208523350021) This project was twofold: - I wanted to be able to feel ear pets on my av in VR without needing visual confirmation, like standing in front of a mirror. - I wanted to exactly how hard it is to stand up DIY hardware on buttplug. I now have a better idea of both of these. The rig itself consists of: - A RPi 0W running a simple python script that's a http-to-i2c bridge (didn't want to fuck with rust compile times here and it's not doing much) - 2 haptics motor drivers - 2 ERM coin motors For the ear pets, things... work, but it's VERY experimental right now. I was taping the motors to my ears/head, they're ERMs instead of LRAs (LRAs are still in shipping. For those not familiar: ERMs are the big spinny motors like they used to have in gamepads. LRAs are smaller, faster, more controllable systems, like the motors in the switch joycons or that simulate taps/clicks on your phone), etc... I need better mounting mechanisms, more tuning, etc... For Buttplug, well... It took me the better part of 2.5 hours to integrate this. This required adding network communication managers, wiring the protocol up to control the motors, getting the device configs running, as well as modding my VRChat avatar and making sure VibeGoesBrrr would talk to the motors. With all that done, I now have per-ear haptics. And have also found out that my ears go numb pretty quick. I've got 100 controller chips on the way in order to expand this project, as these nodes are made to be modular so we can cover basically wherever we want on the body. I'm not really sure if this project is going to end up as a product, but it's been a great way to get a better idea of what approaching buttplug as a DIY builder is like. (it sucks and needs fixing) # Everything Else - [https://xtoys.app](https://xtoys.app) is now using Buttplug for some of its protocols! :D - I've found out that a lot of people in the audio erotica scene are using syncydink for funscripts + audio. If you're one of them and you have opinions, please comment or get in touch. I'd like to at least think about making life better for y'all. - Trying to knock out some bugs in Buttplug, but VR (and life in general) keeps getting in the way. I expect there will be a bit of a library development lull for at least a couple more weeks, but actually getting in world and seeing how the library is used has been massively helpful. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-03-22 Edition) I can apparently code again! # Intiface Desktop And that means Intiface Desktop updates! I was already working on cleaning up ID back in January, then got sidetracked onto... something or other. Anyways, with the new release of VibeGoesBrrr (a VRChat plugin for Buttplug) on Friday, it managed to trigger a bug that would cause Intiface Desktop to stop server processes after ~15-20 minutes. This had been a problem for months, though usually it took 4-6 hours to crop up. Turns out, the server process buffer wasn't flushing and would overflow at 1MB of log messages, and the new VGB caused us to spew TONS of log messages, hence the ~15-20 minute time to server stoppage. I changed the process input to streaming (so now there's no limit, I racked up a 20mb log file testing that heh), so that should no longer be a problem. Everything else there has been quality of life stuff, just bug fixes, removing the C# engine choice, etc. The next big thing for Intiface Desktop is... figuring out what Intiface Desktop is supposed to be. The application was never really defined as a product, I just chucked it together so people didn't have to run a command line. That's not really working anymore, so I'm going to take a bit of time and figure out exactly what it *should* be. # Buttplug Updated Buttplug C# and JS yesterday. Mostly bug fixes, but should make life nicer for devs using either of those. # Other Projects - Syncydink continues to be wildly popular now that I said I'd no longer work on it. Am now weighing my options here. - I've gotten a bunch of people asking about Phasmophobia Buttplug mods. May look at that, as it uses the same system as the VRChat mods. - VRChat work continues apace. The new VibeGoesBrrr release is super neat. Highly recommended. Really hoping to get back to Neos work here soon too. That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## Buttplug Rs V3 Released What I thought was going to be a simple update for Unity turned into another major version release! So I wrote a blog post. More updates in the weekly update tomorrow. --- ## Buttplug Rust v3.0 Released - Less is Less When I released [Buttplug Rust v1](https://buttplug.io/), I figured I’d be rolling major versions whenever we updated the [Buttplug Protocol](http://buttplug-spec.docs.buttplug.io/). Here we are, at major version 3.0, still running the same protocol, but with more surface API changes. So much for those plans. ## Why v3.0? Since the release of Buttplug Rust v1, I’ve been getting steady pings from game developers asking when the [Buttplug Unity](https://github.com/buttplugio/buttplug-unity) plugin would be updated, in order to support new hardware as well as IL2CPP compilation. I finally got time to start work on this project a couple of weeks ago. Unfortunately it didn’t get off to a great start. Using the [C# FFI to Buttplug Rust](https://github.com/buttplugio/buttplug-rs-ffi) worked fine, everything basically compiled with no real changes outside of some module paths, which was great. However, the development cycle after that basically became unusable. We found we could run Unity in Play Mode once, but any subsequent run would stall. [There’s more info in the related bug](https://github.com/buttplugio/buttplug-unity/issues/9), but long story short, Unity’s Mono implementation wasn’t able to properly shut down Buttplug Rust’s async handling runtime. This meant threads got left open, and when Mono tries to reset itself (as is common, to save Unity game developers from having to manage their own state resets), it’d just stall forever. The fix to this was moving from our current runtime ([async-std](https://async.rs/) on top of [smol](https://github.com/smol-rs/smol)) to [Tokio](http://tokio.rs/). [Tokio](http://tokio.rs/) provided far more granular runtime lifetime handling and passing, meaning we can easily manage when we bring up and take down the system. We now don’t spin up any runtimes (which brings up a number of threads) until we need to, and we can tear it down once all of our devices and clients disappear. With that work done, Unity seems to be pretty happy. It compiles Buttplug support to either Mono or IL2CPP, and the development loop seems stable. I also took some time to work more with the fantastic [tracing](https://github.com/tokio-rs/tracing) crate to improve logging in the library, making it easier to follow device connection lifetimes. This work also made me realize that my “batteries included” philosophy for Buttplug Rust maybe included a few too many batteries. ## What Got Removed One of the original tenets of Buttplug followed my philosophy about sex toy design: that it should be as quick as possible to start using, and able to run basically standalone while also having the ability to extend where needed. Developers can just get the library and integrate it with their program, not having to worry about how devices connect, how IPC mechanisms works, or other boring details. This hopefully allows for developers to concentrate on implementing interesting things with sex toys. Sometimes though, this gets overrun by me learning things while implementing the library, so we end up with more features than might really be needed, or that I can support. Optimizing the library for Unity brought up a few things that could be removed. # Removing async-std and ThreadPool Runtimes Unlike many languages with async capabilities (C#, JS, etc…), Rust’s async execution system is designed in such a way that the language comes without a way to execute tasks. Rather, it depends on outside implementations that can tune to the specific requirements of an application. While this is overall a win for the ecosystem, it can sometimes cause [frustration](https://kevinhoffman.medium.com/rust-async-and-the-terrible-horrible-no-good-very-bad-day-348ebc836274). Supporting multiple runtimes in Rust is common, but usually for libraries that will have widespread use: network services, database connectors, etc… While there are certainly developers using Rust to develop Buttplug applications, they are a minority compared to developers using FFI libraries, where this runtime selection will be hidden. Buttplug Rust as it exists now was started in September 2019, slightly before the release of async features in Rust 1.36. At the time, async-std was developing alongside the nightly branch of rust, and looked more like what the async ecosystem does now. Thanks to that, I ended up going with that for our initial execution system, and it has worked great up until our current issues with Unity. This also functioned as a way for me to learn how to live as a library developer in the new Rust async ecosystem. This was a combination of interesting and frustrating, especially as requirements sometimes differed greatly between libraries. With subsequent releases of Tokio over the past 18 months, it has grown to integrate with the async facilities of Rust in a more ergonomic way, while still providing more granular control (and the cost of some added complexity sometimes, i.e. runtime handle management). Thanks to this, it now fits Buttplug’s needs better, and comes stocked with some very useful sync primitives and channels, including [Broadcast](https://tokio-rs.github.io/tokio/doc/tokio/sync/broadcast/index.html) (which I use heavily to simulate the event systems we had in C#/Javascript). On top of this, most of the async work we still need to happen ([Windows Named Pipes, serial ports](https://github.com/tokio-rs/tokio/pull/3388)) is farther along in tokio/mio (as far as I’m aware, and it’s currently stalled), meaning we can just integrate with that when it comes along by using tokio as our main implementation. After switching Buttplug to Tokio, it became apparent that maintaining 4 runtimes (tokio, async-std, futures crate ThreadPool, and wasm-bindgen) was silly, since I don’t really have users split across those (and many users may not even know why the runtimes are there). Some of our other dependencies like [async-tungstenite](https://github.com/sdroege/async-tungstenite) could handle the differences, but the complexity of the feature system for Buttplug was getting out of hand, as was remembering where to put all of the relevant `#[cfg()]` calls. I’ve now removed async-std and ThreadPool implementations, leaving us with just Tokio and wasm-bindgen (required for WASM). Ideally it’d be great if we could use Tokio’s executor for everything, but that’s not quite possible as of yet. The current system is managed using an internal system similar to the [async\_executors](https://github.com/najamelan/async_executors) crate, which works well enough for abstracting task systems. This does not mean that Buttplug isn’t usable with other runtimes now. Outside of the Device Communication Managers (which, granted, are possibly the most important part of the library), most of the library is runtime agnostic, and async-std contains tokio compatibility systems that will allow the library to run using its runtime also. This change mostly reduces the amount of thinking I have to do when updating the library and its direct dependencies. This is open source self care more than anything. # Removing Secure Sockets for Buttplug Servers When Buttplug C# first started in 2017, Chrome allowed for localhost websocket connections via mixed contexts (i.e. https:// website calling through ws:// for localhost websockets). Firefox did not have a feature like this, so we implemented the ability to create self signed certs and load them into the server to run a self signed websocket server for Buttplug. This allowed us to get applications working in Firefox. Firefox changed this in 2020, now also allowing mixed context localhost connections. With this addition meaning that Chrome, Firefox, and Edge all supported mixed context connections, the need for including the batteries of a secure socket connection went away. Any users that require this feature can still set up a reverse proxy in front the server port, but managing the certificate generation and loading system is well out of scope of Buttplug’s core goals. Removing this will hopefully simplify changes to our connector system in the future, and also removes the burden of keeping cert libraries in lockstep. For most of the talk of async in this post, the secure socket change is actually what drove the major version update. Removing secure sockets changes our Websocket connection API, which is exposed to developers, and therefore is a breaking change in the general public API. This change only happens in the Rust library, as the server is not exposed in the FFI, so while Rust moves to v3, the FFI APIs will continue on the v1 track. ## What’s Next Now that Buttplug v3 is done, there are quite a few releases to make on top of it: * Updating the C# and WASM FFIs, though only C# will see much of a change. * Finishing the Buttplug Unity update and releasing v1 of that package * Updating Intiface to remove the Secure Socket options These updates will be happening throughout the next week. After that, the main focus is going to be more documentation and the implementation of a WebRTC based proxy system. This stems from the [rather startling discovery that Buttplug (the library) doesn’t work very well with buttplugs (the sex toy)](https://twitter.com/buttplugio/status/1381007465056100352), which I’ll be making another post about soon. With this proxy system (inspired by the work of [xtoys.app](https://xtoys.app/)), we can start using mobile hardware (phones, linux SoCs like RPis, etc) as connection points, giving users more freedom in where and how they use toys. Alongside this will be more hardware and QoL updates, but the goal for now is making our system usable to the wave of social VR users we’ve seen over the past few months. Onto v4! But hopefully via many v3 point releases first. --- ## What's qDot Up To This Week? (2021-04-19 Edition) Ok maybe if I write these in the morning I'll actually remember to send them out... # Buttplug Unity Most of the last two weeks have been spent trying to wedge Buttplug into Unity in a way that will work with IL2CPP. For those not familiar, IL2CPP is a way for Unity to compile games to make them run faster, but it takes a lot of consideration when building libraries to work with it. So much consideration that I had to rearchitect a non-trivial portion of Buttplug. :| That ended up being Buttplug v3 (which came out last week), then most of this past week has been trying to get the FFI layer updated so the C# stuff will work with Unity. As of yesterday I finally have a solution that I *think* works everywhere. I managed to get toys vibrating in IL2CPP production builds as far back as Unity 2018, so that's a good sign. Cleanup is happening now, hoping to have this out later this week. The big outcomes of this will be updates to the FarmD ([https://patreon.com/softscale)](https://patreon.com/softscale)) and ViRoPlayspace ([https://viro.club)](https://viro.club)) games, as well as hopefully being able to discuss starting toy control work with Dominatrix Simulator. The work on the FFI will also hopefully put us in a somewhat better position to look at C/C++ integrations, which gets us moving toward Unreal Engine integrations. Maybe Java bindings too? # Everything Else The workload mentioned above has eaten my life, so there's not a ton to say otherwise. Plans for the near future include: - Hopefully making a youtube video on the OhMiBod Lumen, now the smallest Bluetooth buttplug (the toy type) usable with Buttplug (the library). tl;dr: It's pretty good, but has the same connection issues as all other butt toys currently - Writing up a blog post on our issues with butt toys and how I plan to fix them (i.e. finally getting some sort of mobile interface working, so you can use your phone as the hardware controller and connect that to desktop apps) - More FFI expansion - More hardware support That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-05-03 Edition) Just rethinking large portions of the project. Again. :| # Buttplug and Lovense Connect So it turns out I was not aware of exactly how "Lovense Connect" works. Lovense has 2 mobile apps: - Remote, which is their teledildonics system - Connect, which is for cam models and 3rd party devs Turns out, Connect just opens up a webserver on your phone, and allows access via HTTP or websockets. You have to contact lovense's servers to ask for IPs, but after that, its all local. I spent the weekend implementing this in Buttplug, and it works pretty well. This is now basically our proof of concept for the WebRTC based system I've been planning that will look like this. The problem now is that this splits Buttplug into being both local control and possibly talking to the network, which makes privacy *very weird. *Before this, we didn't really have to consider that someone using a serial port toy might be mad about us look at bluetooth too, as they're all attached to the same computer. With Lovense Connect, we certainly don't want people just using Kiiroo toys to have to ping Lovense's servers to ask for connections that will never be there. So while the technical implementation of this was pretty smooth, figuring out how we're going to message this to users and developers is going to be new, and a shift in how we've worked before. I'm going to be writing up a series of blog posts on this, as well as the future of Buttplug, over on the Nonpolynomial Blog ([https://nonpolynomial.com/blog).](https://nonpolynomial.com/blog).) I'll post here when those are up. # Other Buttplug News I've also been doing a lot of work to make Buttplug more extensible. We've been getting more and more DIY builders in our Discord, but I hadn't added a way to add protocols to Buttplug without having to modify and recompile the whole library yet. I've simplified that and made adding both protocols and device communication managers easier, so the system is fairly flexible now. This means that people can either build code for their own hardware, or else add hardware support I've been avoiding. Of course, it could use some documentation... # Everything Else - So documentation is going to be my goal for this month, alongside the aforementioned design work around figuring out online services, and... - Updating Intiface Desktop! Intiface Desktop needs documentation VERY badly, as well as UI updates to deal with selecting comm managers (so you can turn off the Lovense Connect stuff if you won't use it). Hoping I can line all of this work up. - And in news of removing work... Due to getting way too many support questions, I took down Syncydink from the buttplug.world domain. It's still available on the internet archive, because it's a static, client side program that doesn't need any databases or network services, so it should work as long as browsers do. If you're a patron and need help with it, contact me directly and we'll talk. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## When Buttplug Wont Buttplug Part 1 Oh No New blog post! In which I explain why VR users are the worst, even though I'm racking up VRChat hours like no one's business lately. --- ## Still Alive, Hoping to Resume Updates Next Week Just realized I've missed Monday updates for a couple of weeks. I'm currently in some crunch time on a couple of projects, meaning the rest of my schedule has either shifted or just stopped being a thing. Hoping that'll be over this week and I can get back to regular updates next week. There's some movement on Buttplug and related projects happening, so lots to talk about next Monday! - qDot --- ## What's qDot Up To This Week? (2021-05-31 Edition) Welp, at least I managed another May update before the month was over... # Intiface Desktop After getting the Lovense Connect code into Buttplug and releasing v4 of the library in the first couple of days of May, a whole bunch of fuck all has happened since. I got absolutely crushed with some non-Buttplug work that meant I had no energy to work on things for most of the month. Luckily, due to the long weekend in the US, I've gotten a tiny bit of time to recover. First order of business right now is updating Intiface Desktop to work with Buttplug-rs v4. This means: - Adding the ability to select Device Communication Managers, which really just means "You can say whether or not you want to connect to bluetooth devices or HID devices or gamepads or whatever". This will at some point become "say whether you want to only connect to/completely ignore certain devices", but that's still a little ways in the future. This was in service of... - Adding support for the Lovense Connect Service, which is now going to be the first opt-in feature of Buttplug. Since this requires calling out over the network to Lovense's services, it's up to users to turn this on for themselves, the library does not do it by default. This UI is part of the first feature. - Adding a device panel! You can now run what is basically a newer, slimmer, more useful version of Buttplug Playground, right in Intiface Desktop! This is just the first feature of the Device Panel, which will also includes the aforementioned allow/deny lists, as well as simulated devices in the hopefully near future. - Removing support for SSL connections, since those were removed from the core library. We'll let users handle proxying if they need that now. Most of this work was finished today, all I need to do now is make a tutorial video of all the new features, then v21 will be out sometime this week. # Buttplug After that, I've got a ton of cleanup and merge work to do around Buttplug. This includes: - Consolidating repos, yet again. I'm going to collapse the buttplug-rs repo to just be buttplug, with the device config, spec, etc all in a single monorepo. - Buttplug-rs-ffi will just turn into buttplug-ffi too, making Rust our core implementation. - We have both Java (full FFI) and native Node (client only for the moment) FFIs sitting in PRs waiting for me to review, planning to get to those in the next week or so. - I need to start merging the new async version of btleplug, as that merge is holding up the actual release of v1 of that library. - Trying to get async HID support in, in order to bring back RealTouch support as well as bring in things like the Nintendo Joycon. - And after all that, hoping to finally consider WebRTC work for mobile/remote connections. # Other Stuff Lots of work happening with 3rd parties now! - FarmD ([https://patreon.com/softscale)](https://patreon.com/softscale)) have released a new public version of their VR dragon fucking game, with Buttplug support - Dominatrix Simulator ([https://www.patreon.com/deviantdev)](https://www.patreon.com/deviantdev)) are working on integration now, and should have a new beta out soon with Buttplug support - In Heat ([https://github.com/Furimanejo/In-Heat),](https://github.com/Furimanejo/In-Heat),) a new Overwatch energy bar tracker with Buttplug integration, was released So things are definitely staying busy! That's it for now. Hopefully back to weekly updates. Until next week, Keep Buttpluggin'! - qDot --- ## Video Pre Release Intiface Desktop V21 Tutorial Well Intiface Desktop v21 isn't out yet (hoping for this evening), but if you're curious what it's going to look like or the new features that will be available, here's 20 minutes of me presenting it. And as patrons you get it before everyone else! (For whatever that's worth >.>) --- ## Intiface Desktop V21 Released Intiface Desktop v21 is out! Now with Lovense Connect support, In-App device testing, and more! All of the new features were covered in the tutorial video I posted a couple of days ago. --- ## Intiface Desktop V22 Released Intiface Desktop v22 is live! Unfortunately the autoupdater broke in v21 and I didn't notice, so if you're getting stuck on the "Updating Application" dialog, just download the installer from the site. This is a bugfix release, mostly issues in the Devices panel. --- ## What's qDot Up To This Week? (2021-06-14 Edition) Other than completely losing track of what day it is... # Buttplug & Intiface Desktop Intiface Desktop v21 is out, and with it, the first publicly usable release of Buttplug v4! This means that you can now use the Lovense Connect app with Buttplug, though I'm already finding out how many people have their desktops and WiFi on different, inaccessible subnets. \>.\< Intiface Desktop v22 will be out as soon as this evening, fixing a few major bugs in the Devices panel. Otherwise things seem pretty quiet so far. # Project Consolidation Boring project management news time! I've also taken some steps to reduce the amount of repos the project is using, mostly because it's just not worth it to have everything so split up. I just moved the spec repo (which used to be buttplugio/buttplug) into the rust repo, and have now renamed the rust repo to be buttplugio/buttplug. The main buttplug repo now has: - The Spec - The Spec Schema - The Device Config - The Rust Implementation So what was 4 repos (3 of which were rarely updated) is now one! Way less work for me. Yay. # What's Next I'm now back to having a bunch of different directions to work in, all of mostly equal importance. This includes: - Starting on Intiface Mobile (think Lovense Connect but for Buttplug in general), which includes making an FFI for the device comm managers as well as getting WebRTC connectors going. - More Intiface Desktop updates, like filling out the Device Panel with configuration (so you can set up serial ports for devices, allow/deny device lists, set device parameters like min/max speeds), etc... - Starting to consider new Buttplug Messages. This includes finally getting something done for the Lovense Max Air Bladder, plus some extremely generic messages so we can easily support all toys without requiring Raw commands - So much documentation. So much. - So much youtube video filming. So much. - Lots of other stuff. I'm gonna be spending a bit of time trying to plan, with the hopes that I'll have some better direction (and updates on that direction) in the next week or two. That's it for now. Until next week (or possibly later this evening if I get the new Intiface Desktop build out), Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-06-28 Edition) A boring but somewhat productive week in the Buttplug world... # Buttplug Right now most of the work in Buttplug is actually slightly lower than Buttplug itself. I'm working with some other developers to get the new Bluetooth LE library in, which allows me to cut about 50% of the bluetooth code out of the server, as well as making things work far better on macOS. It'll also possibly open the way for iOS/Android usage. Unfortunately things are stuck on Linux right now, where everything breaks horribly. Hoping to have that shored up in the next week or two so we can get this out. # Applications Intiface Desktop 23 was released a little over a week ago, after a major bug in v21 caused updates to break. I am *hoping* most people are finding ways to update to it, but due to the lack of tracking and metrics, it's a bit hard to tell. As I've probably said a million times before, I really need to figure out better support and logging on Intiface Desktop. We're getting enough users now that problems are starting to repeat often, but getting to the bottom of those issues requires a ton of discussion on discord, when really it should just be "user hits button, developers get system layout and relevant logs". I'm also working on taking the device panel UI and turning that into a new version of Buttplug Playground, as playground itself has been horribly broken for months and just needs an overhaul anyways. # SFW Content - New Channels/Patreon There's a bit of a change coming to how I handle my patreons and content. For the past 4 years, I've only had one patreon, youtube channel, etc, all focused on Buttplug. However, a lot of the subject matter around that isn't specifically NSFW, it just ends up being so when I add sex toys. In order to grow my audience and not cordon off content that's not explicitly sexual, I've now created a new Youtube Channel and related Patreon, known as the Poor Life Choices Network. [https://youtube.com/c/poorlifechoices](https://youtube.com/c/poorlifechoices) [https://patreon.com/poor_life_choices](https://patreon.com/poor_life_choices) Right now this will mostly be for explaining some of the VR work I've been doing in SFW contexts, even though most of it still ends in Buttplug at one point or another, heh. I'll also be using this to talk about things like the internals of the Game Haptics Router, which I'm currently forking for non-adult haptics hardware like the bHaptics and OWO vests. Once again, an originally Buttplug focused technology, but talking about the methods used in it doesn't really require that context. All that said, this doesn't mean I'm stopping work on Buttplug or adult content. It just gives me a way to take some of the technology created for the project and show it off to a larger audience without having to worry about getting removed from searches, banned from services, etc. I'll still be working as hard as ever here, and as a member of this patreon you'll still get most of the perks of the PLC patreon, since a lot of the work overlaps. I just won't be mentioning the buttplugs part of it on PLC. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-07-05 Edition) And suddenly, productivity. # Buttplug/Intiface Desktop (Now with OSR-2 Support) YES IT IS FINALLY HERE. BUTTPLUG HAS EXTREMELY BASIC OSR-2/SR-6 SUPPORT. AND IT ONLY TOOK ME 2 YEARS jfc this is ridiculous. So, yeah, as of Intiface Desktop v24 and Engine v39 (both released yesterday), Buttplug now supports a single linear stroking axis for TCode devices. We'll support arbitrary axes, rotators, and vibrators soon, but this was the first step in getting there. Intiface Desktop also got: - A way to add Nobra's Silicone Dreams devices. - A warning whenever you try to connect multiple clients. The best part about this is that we're now using the User Device Config system, a feature that's been in the library since early 2019 but never got UI to support it until now. This will eventually allow things like: - Adding your own devices (protocols will still need to be in Buttplug tho) - Renaming devices - Allow/Deny device lists - Setting min/max movement/speed limits on devices It's super exciting to get this kicked off, and I'm looking forward to getting more things implemented for it. # VibeGoesBrrr Stroker Support A lot of this happened because of the VibeGoesBrrr VRChat plugin, which is my current platform obsession if that wasn't obvious. VGB recently implemented stroker support in a beta branch, and it's working REALLY well for real time VR control! I'll have some demo videos up as soon as I figure out whether I can post them without getting banned from multiple platforms for doing so. # What's Next I'm hoping to continue with the Intiface Desktop User Config updates, as well as bringing back Device Simulators so devs are no longer required to have actual hardware (though it will certainly help if they do). We've also got someone looking at Android support now, so there may be a native Android Buttplug library soon! We *may* already work on iOS too, but we need a Swift FFI layer to get that tested. Lots of interesting developments ahead, can't wait to show them to you! Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-07-26 Edition) Too god damn much bluetooth. # BTLEPlug This is going to be one of those updates that is more about meta-buttplugs than buttplugs. About 6 months ago, a ton of code was overhauled in btleplug, the Bluetooth LE library I maintain and that powers all bluetooth in Buttplug on Windows/macOS/Linux. Unfortunately testing to this code has gone slowly, and there were a couple of stalls due to weirdness on Linux. Luckily this past weekend I finally figured out the Linux issues enough to write a workaround, so we'll hopefully have the new btleplug v0.8 released this week. The nice part about the new version is that it cuts the amount of bluetooth handling code in buttplug in **half. **The new async code is far smaller and cleaner, and it also is part of our path to getting Android support working. # **Buttplug Android** Alongside the btleplug work, Buttplug Android is continuing development. If anyone is interested in how Buttplug and Android apps will talk to each other, check out this thread (having an understanding of how Android's internally messaging system works is helpful): [https://github.com/buttplugio/buttplug/discussions/368](https://github.com/buttplugio/buttplug/discussions/368) # Everything Else - I'm continuing to expand our support for tcode, which I'm basically going to call the firmware protocol of choice for DIY buttplug projects at this point. Expect to see multiple linear axis as well as vibration support soon. - I'll also be added the ability to connect to Buttplug as a *device* via Websockets. This will allow us to rebuild the simulation system (which people have been asking for since I blew it up 2.5 years ago >.>), as well as making handling connections from things like ESP32s basically turnkey. - I'm trying to plan out the new documentation portions of Intiface, which will allow people to get help and troubleshoot within the app. This is gonna take a while, but hopefully should drastically reduce our support load and our user's confusion levels. That's it for right now. Lots of hard work ahead, but it's nice to continue growing the platform! Until next week, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-08-09 Edition) A line of yaks stretching as far as the eye can see... # Buttplug The slow march toward what is now Buttplug v5.0 continues. btleplug v0.8 has now been integrated into Buttplug, which has reduced bluetooth code size by 50% and made macOS work, like, at all. Thanks to trying to build my own DIY hardware (my head haptics for VR), I've now actually started listening to the requests/complaints of other DIY builders, and it turns out a lot of them were pretty valid. With that in mind, there are now 2 other new features coming in with with the btleplug update: - Websocket Server Device Communication Manager, which is basically a very long-winded way of saying "connect to and control devices over websockets". The big win for this will be the restoration of Device Simulators. We'll be able to build web apps that can connect as devices instead of Buttplug clients, so that you can test your apps with pictures of shaky buttplugs or stroking toys instead of... actual shaky buttplugs or stroking toys. Note that only the capability will be landing in Buttplug v5, actually building out the simulator GUI is going to take a bit afterward, but it's one of my top priorities after this release is done. - Overhauling the Device Configuraiton system to allow more user customization of device capabilities, as well as adding new devices locally. In Buttplug up until now, anyone that's wanted a device supported has had to put in code to the main library. With the expansion of the device configuration system, it'll now be easier to add your own DIY devices that other people may not have, and use them locally. - Oh and a third actually: tcode now support multiple vibrators as well as multiple linear axes, meaning you can define your OSR-2/SR-6 setup in the new device configuration system based on whatever you've built! This also will allow people to implement TCode as a firmware protocol and add it to Buttplug easily. These two features, once released and more importantly, properly documented, should make life far easier for people wanting to hook DIY toys into Buttplug. Of course, configuring it all is going to be quite the challenge, which means it's time for more updates to... # Intiface Desktop Once Buttplug v5 is landed, I'll be shifting over to more frontend work to expose all of this via Intiface Desktop, as well as starting to build in a documentation system, as the functionality of the program is growing quickly and will be getting quite complex soon. I'm hoping I can keep the program usable for those that just want to quickly hook up their lovense toy while extensible enough for those of us that are building our own thing. That may end up meaning I hire someone for UX soon, because wow I'm bad at this. :) # Youtube While working on the library I've had my 3D Printer going constantly in the background, in the hopes of kicking off some new youtube videos on the OSR-2, Handy mounting systems, etc soon. So keep an eye out for those! Anyways, that's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-08-16 Edition) The pre-release slog continues... # Buttplug There's nothing worse than changing a surface API, because that means a major version revision, which means then you just start piling in ALL of the changes that might hit surface APIs, and sudden you've got a katamari release on your hands. So that's where things are right now. The good news is that, as of v5, I think Buttplug will be *completely* modular outside of the message system, which is kind of the last big hurdle until this is just a pure hardware abstraction and message passing library that just happens to talk to sex toys. But it will be very easy for users to add/customize the library to their liking, assuming anyone understands it enough to do that. Which is why the next goal after this is documentation and better UI. And then more Buttplug protocol messages because apparently everyone is getting fucking machines now and it's becoming A Problem. Anyways, that's literally it for this week. I've just been doing lots of refactoring and replanning and am now into writing tests to make sure things basically continue working. Hoping again for v5 release this week, but we'll see if that actually pans out. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-08-30 Edition) Releases! # Buttplug With Buttplug v5 released last week, I've now moved to getting all of the dependencies updated. This means the FFI libraries (new C# and JS out yesterday), and Intiface CLI/Engine will be happening in the next day or two. For the FFIs, right now it's just a library update, without adding any new surface API for the new features of the library. I expect I'll be getting to that soon, but would like the new features (websocket devices, etc...) to get tested more in Rust before I connect them to the rest of the world. For the engine, I'm expecting bugs, since this update will be a huge overhaul of our bluetooth handler (good news macOS users, Buttplug should be useful there again!) but hoping for the best. I'm hoping the next major revision to Buttplug will be the addition of new messages, the first time this will have happened in almost 3 years. I'm still working on figuring out exactly what those messages will be, if you're interested in being involved in that discussion, check out our Github Discussions area. ([https://github.com/buttplugio/buttplug/discussions)](https://github.com/buttplugio/buttplug/discussions)) # Intiface Desktop Of course, all of the new features in Buttplug v5 *do* need to make their way into Intiface Desktop, so I'm looking to climb that hill next. While also considering rewriting Desktop in Rust using egui. :| Intiface Desktop is the largest node/typescript/electron application I've written, but it's now also the *only* one I maintain, and keeping up that maintenance when not working in those technologies is a nightmare. There's going to be some tradeoffs with egui (not gonna be quite as flexible on the GUI side, font rendering isn't great, etc), but honestly Desktop doesn't do much, so I'm hoping at least keeping it in technologies I know will help. I'm doing some research and demo implementations on this now, might actually post some alphas here if people are interested. This also may be leading to a larger integration project for easily building media/game/etc integrations with Buttplug and other libraries, but more on that as I actually come up with better descriptions for it. # New Projects using Buttplug Here's some new things people have built using Buttplug lately! - Godot.Buttplug ([https://github.com/nhydock/Godot.Buttplug)](https://github.com/nhydock/Godot.Buttplug)) - Native interface for Buttplug in the Godot game engine! - ButtplugMc (Minecraft) ([https://github.com/psiloclast/ButtplugMc)](https://github.com/psiloclast/ButtplugMc)) - A new Buttplug command system for Minecraft integration, using our new Java FFI! - Buttplug Morse - [https://github.com/kaylynn234/buttplug-morse](https://github.com/kaylynn234/buttplug-morse) - Morse Code your Buttplug! - Healsluts (Overwatch) - [https://github.com/Sir-Prise/healsluts](https://github.com/Sir-Prise/healsluts) - In-browser Hardware based Healslutting for overwatch using the display capture API! That's it for now, until next week, Keep Buttpluggin'! - qDot --- ## New Youtube Video Ask A Teledildonticist After threatening for the better part of 2 years, I've finally kicked off the Ask A Teledildonticist video series! Feel free to message me your questions if you have something you'd like answered in the series! --- ## What's qDot Up To This Week? (2021-09-13 Edition) Watching the bugs roll in... # Buttplug/Intiface First off, some pretty big news: **WeVibe Vector and other toys that have been flaky for years now work with Buttplug!** Thanks to a contribution from one of our community members, there are now fixes in for WeVibe toys that make previous unreliable hardware work with our library! This is a huge step for hardware support. We also updated our toy support for Lovense Quest, so that's working now too. Last night, I released Intiface Desktop v26 and Intiface CLI v40, which integrates the new Buttplug v5 library. This adds a bunch of new features that it's going to take me a while to expose, but we're on track to having Device Simulation and easier new device additions for DIY/makers. More info on this as I get things documented and UI built out! # Upcoming UI Overhauls One of the next big projects is going to be the next move of Intiface Desktop to another UI basis. We started out with C#, which was windows only (and yes I realize MAUI is on the way and no I don't think it'll be a great solution for us quite yet), then moved to Electron, which is cross platform but extremely difficult to maintain, especially since I'm writing less and less Typescript these days. I'm now looking at porting some of our GUIs to Rust, in a way that will work on both desktop and the web. We'll see how this ends up going, but expect more updates on this soon. As a patron, you'll also be first in line to try betas of these new releases! # Youtube I'm also trying to start cranking out more youtube videos, as I'm averaging about 5-6 per year on the Buttpluggin' with qDot channel right now, mostly because they're incredibly time consuming to make. To fix this, I'm now trying to make shorter videos as part of the Ask A Teledildonticist series, the intro to which I posted earlier today. If you've got questions you'd like answered, please message them to me! That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## Sneak Peak Ask A Teledildonticist Why Do You Use The Term Buttplug So Ofte Hey look, a patron perk! Here's the new Ask A Teledildonticist video, a few days before the rest of the world will get to see it! --- ## What's qDot Up To This Week? (2021-09-27 Edition) Rewrites! # Intiface Desktop After a couple of weeks of having problems with coding blocks (writers block except for programming), I seem to be back to vague levels of productivity. This mostly means re-implementing Intiface Desktop in Rust and egui. So far, everything is going quite well. The resulting binary will be < 10MB (instead of 190),  and it should take < 20MB of RAM while running. It's *really* streamlined, and much easier to work with. I have config file saving/loading, as well as most of the UI outside of the devices tab done (there's really not much to Desktop at the moment). The next major portion will be tying the engine and GUI together so it shows the client name/device connected updates again, then I'll probably call it good enough for alpha while I work on adding back the devices tab. Once things are to that point, I'll be posting installers here for everyone to check out. # Youtube Took a bit of a break from trying to do weekly Youtube this week since I've been busy on code, but expect more videos soon. That's it for now. Pretty singularly focused on making Desktop something I don't hate working on, so not much otherwise to talk about. My Valve Index is going in for RMA this week, which will probably multiply my productivity since I won't be able to get in VRChat. :) Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-10-04 Edition) Intiface Desktop! # Intiface Desktop Intiface Desktop work continues apace. It's looking pretty good now! Which is to say, it looks pretty much exactly like it did in Electron, but now it takes up 1/80th the disk space, and 1/10th the RAM. Not really much in the way of new features happening at the moment, as most of my time has been spent just getting us back to parity. Lots of working getting autoupdating for the device file/engine working again, rebuilding the communication between the GUI and intiface process, etc. The goal for v41 is to just get everyone on the new platform ASAP, but I've still got some plans for it: - Sentry crash logging (so you aren't stuck messaging me logs on discord) - Errors come up as system notifications (toggleable) - Rolling logs (so you'll save the last 10 logs to disk, instead of just the last session) - Batteries Included at Install (so it'll just work out of the box!) This are mostly nice to haves, that mostly didn't happen because the Electron/Web version of Intiface Desktop was such a godawful nightmare to work on. That said, I feel like any quality of life change here will be pretty massive for most users. # Buttplug, Buttplug Unity, Youtube, etc... Most of my time has been spent on Intiface, but there's been some reports of Buttplug bugs that I'm keeping an eye on. Buttplug v5.0.2 will probably be out soon, mostly with btleplug fixes for Linux. I need to get a new Buttplug Unity build out soon too, it's been a few months and a few things have been fixed by the community, so hopefully we can get a more stable build out. Youtube video schedule has already fallen behind because I have a really difficult time balancing working on code and videos. Still trying to figure out how to balance that out. My VR headset is now in for RMA, which is going to give me a lot more time to work on... not being in VRChat, so maybe that'll help. Or maybe I'll just completely lose my shit. We'll see! Anyways, that's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-10-11 Edition) New features! Finally! # Buttplug Thanks to getting bored with bringing the new Rust Intiface Desktop to parity with the JS Desktop app, I decided to play around with building some small new features that required changes all the way back to Buttplug. - User configurable names for devices! You'll be able to set the display names of devices. I eagerly await seeing how absolutely fucking off the rails this goes ([https://twitter.com/buttplugio/status/1447374441139212290](https://twitter.com/buttplugio/status/1447374441139212290) for a vague idea).  - Persistent device indexes! This means if you connect a device, it will continue to connect at the same index (which is how developers access the devices) until you delete your config files. - Device Allow/Deny! You can tell Intiface/Buttplug to never connect to certain devices, or *only* connect to certain devices! I'm also starting work on trying to design some better messages for Buttplug, as we're starting to run into more and more devices that we can't easily support with our current message set. If you're interested in some of this design discussion, check out some of these threads: - [https://github.com/buttplugio/buttplug/discussions/359](https://github.com/buttplugio/buttplug/discussions/359) - [https://github.com/buttplugio/buttplug/discussions/371](https://github.com/buttplugio/buttplug/discussions/371) # Intiface Desktop All I can say on the new ID at the moment is that work is continuing. I'm now working on bringing device configuration and testing in, which will get us back to parity with the old system, and make the new version ready for Beta. The aforementioned naming/allow/deny UI will hopefully be folded into this. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## Coming Soon Diamo Modding Video Oh yeah, forgot to put this in the weekly update: I bought a second Lovense Diamo. Plan is to see if there's a way to cut the upper loop and use heatshrink to make the device more usable for those that find it too small, or that may want to use it with a chastity cage or something. The WeVibe Bond is a bluetooth cock ring that comes with a way to adjust the loop built in, but I'm still waiting for someone on the Buttplug dev team to receive one of those so I'm not sure how well it'll work with our software yet. I'm hearing that lots of people already have diamos that they can't use for one reason or another, so this'll be handy in that case. Hoping to have that done in the next week or two, and you'll hear about it here first! --- ## What's qDot Up To This Week? (2021-10-25 Edition) It's ADHD time, apparently... # Buttplug Having learned a couple of new tricks in developing the new Intiface Desktop, I've taken a bit of a break from it to use that knowledge on Buttplug. I've now added a new IPC connector using Named Pipes/Unix Domain Sockets that should be way nicer for devs that don't care about remote connectivity to the Buttplug Server. I'm also currently sweeping through the library and doing a bunch of error handling cleanup to try and avoid future issues with crashes, as we've been getting a lot of reports lately. Finally, I'll be updating the library to btleplug v0.9, which should fix some issues on Linux. With most of that out of the way, I'm hopefully going to release Buttplug v5.1. After that, I'm planning to work on the next version of the message spec and adding in LevelCmd, which will make it much easier to start adding new devices or filling in functionality we've been missing (like the Max air bladder). # Intiface Desktop Things have slowed down a bit here, mostly because I've been busy otherwise and it's easier to pick up the non-GUI stuff in the places where I have time. That said, I'm still hoping to get a demo out to patrons soon! # New Hardware (Either Just Released or Coming Soon) - Lovense ([https://lovense.buttplug.io)](https://lovense.buttplug.io)) released the Hyphy, which is an electric toothbrush lookin' thing. - Lovense will be releasing the Gush, which is their penis wrap similar to the Hot Octopuss Pulse, as well as a fucking machine I can't remember the name of, before the end of the year, so keep an eye out for those. - Kiiroo ([https://kiiroo.buttplug.io)](https://kiiroo.buttplug.io)) released the Hot Octopuss Pulse Solo Interactive (almost like Lovense knew they were gonna do this...). It's a $179 version of a toy I wasn't super into when it was $99 and not connected. But, if you like the Pulse, lemme know! I'd be curious to hear positive comments on it. - Kgoal (formerly Minna) will be releasing a "kegelcizer for men" next month. Basically it's a button you sit on. [https://www.kgoal.com/products/kgoal-boost-kegel-trainer-for-men](https://www.kgoal.com/products/kgoal-boost-kegel-trainer-for-men) As always, we'll be trying to get support for all of this hardware into the library as soon as we can after release. Anyways, that's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-11-15 Edition) Uh.... # Burnout Yup, I smacked into a burnout wall a few weeks ago (mostly life/day job related) so it's been real slow going here for the past month. I should stress that this isn't necessarily a bad thing, I tend to work in cycles and this time of year (especially around the time change) usually ends up running a little slower for me. I'm slowly recovering out of it, but I expect things may stay a bit quiet for the next couple of weeks still. # Buttplug That said, I did manage to get some work done on Buttplug last weekend. I extended the new Pipe Manager to use Unix Domain Sockets on Mac/Linux, so now we're cross platform compatible there. That should be it for Buttplug v5.1, so I'm hoping to release that this week. # Other Stuff - I finished filming the "Cut the Diamo open to see if we can make the loop bigger" video, it just needs editing then it'll be up on youtube. - Just because I'm moving slowly doesn't mean other developers are too! We just got a new addition to the Awesome Buttplug list, a Minecraft mod using Buttplug Java FFI! [https://github.com/Cyloci/ButtplugMc](https://github.com/Cyloci/ButtplugMc/blob/main/src/main/java/com/psiloclast/buttplugmc/commands/AddToyCommand.java) Thanks for sticking with me through the quieter times, looking forward to my brain letting me get back to Buttplug Related Productivity. :3 - qDot --- ## What's qDot Up To This Week? (2021-11-21 Edition) More than last week! (An admittedly low bar.) # Buttplug / Intiface Desktop After finally wearing myself out on Forza Horizon 5, last weekend I got back to work on Buttplug and Intiface Desktop, and made quite a bit of progress! Enough that there should be an alpha version of the new Intiface Desktop available to patrons this week! It's pretty much ready to go, just want to poke a few more things in it first. Right now, the system is... pretty much where the Intiface Desktop is. The only extra feature is the ability to set device allow/deny lists, meaning you'll ONLY connect to certain devices (allow) or will NEVER connect to certain devices (deny). This will be handy for the reports I'm getting of multiple people using devices in the same vicinity. It's missing extra device configuration (for the OSR-2/Nobra/etc) but that'll be coming back in shortly, and may be back in before the alpha ships this week depending on my schedule. These updates have required changes to both Intiface CLI (aka the "Intiface engine") and Buttplug, so there will be releases of those coming too (those can ship before the new desktop ships). In Buttplug, the big update is that we now handle with Lovense Gush, with Lovense Hyphy support coming later this week. # Other Stuff - I still have youtube videos to finish editing, we'll see if I get that done this week. - The [KGoal Boost](https://www.kgoal.com/?rfsn=6183821.98f400&utm_source=refersion&utm_medium=affiliate&utm_campaign=6183821.98f400) ships next week. Assuming it's as shitpost-worthy as it looks, I'm expecting this'll be a lot of fun. That's it for now. Hoping the productivity keeps up this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2021-12-13 Edition) AND WE'RE BACK. I seem to have recovered from my coding burnout, while simultaneously getting VR burnout. So now I'm writing a bunch of code but barely using VR. # Buttplug Finally released Buttplug v5.1! This has important features like: - Lovense Gush/Hyphy, Satisfyer support built in, along with extended support for Svakom, ManNuo, LoveDistance and Kiiroo toys - Updated to the latest version of the Bluetooth LE library we use, should fix quite a few bugs, especially on Linux - Named Pipes (no more websocket port collision issues! At least once programs start using Named Pipes, which they probably won't for a while.) - Some fixes to try and make Lovense Connect more stable to use - Lots of library stability fixes - Started working on making it easier for users to add their own devices to the library I've also finally updated the C# and Javascript/WASM libraries to work with the latest version of Buttplug, and made some small fixes on the Python library. I'd like to also update Twine, but that's going to take some serious work. This was a pretty big release, and I'm hoping it's the last one before v6.0, which will have new messages in it, allowing us to support things like some fucking machines and the Lovense Max Air Bladder (finally). Expect work on that to begin after I finish up the alpha for the new Intiface Desktop. # Intiface Desktop Work on the new Intiface Desktop (written in Rust instead of Electron) continues, and is mostly ready to ship as an alpha version to patrons! It'll be extremely rough around the edges to start, and I'll be making a lot of UI changes before it gets to public beta, but I'm definitely excited to get it out to people to start playing with! There won't be a lot of new functionality up from that will be interesting for users, but the system itself should be far more stable, and will allow users to report crashes and other errors far more easily than me trying to ask questions over discord. # Other Stuff - I still have 3 videos waiting to finish editing >.> Coding has been top priority for now, but hoping to get to video content soon. - I'm now working with devs from [Nudica](https://nudi.ca/blog/) and [Heat](http://patreon.com/heatgame) for Buttplug integration into their games! That's it for now. Been a busy few weeks, but looking forward to having new software out for people to check out soon! Until next week, Keep Buttpluggin'! - qDot --- ## New Youtube Video Bluetooth Buttplug Blowout Watch me talk about bluetooth buttplugs for 20 whole ass minutes! Includes overviews of the new Lovense Hush 2 series! The 2.25" is really big! --- ## What's qDot Up To This Week? (2021-12-20 Edition) So damn close... # Buttplug Was planning on getting Intiface Desktop Alpha out over the weekend, but unfortunately bugs in Buttplug took precedent. I fixed some issues with Satisfyer toys, as well as trying to fix some problems with the ScanningFinished message that... didn't really fix anything so I may be removing that, though it's going to make WebBluetooth weird, so we'll see what happens. Otherwise, I'm really hoping we're getting close to me being able to work on Buttplug v6, which will allow for control of things like the Lovense Max Air Bladder, Hismith Fucking Machines, etc... It's not a huge change to the code, but it'll be the first update to our message spec in 3 years, so it's gonna take some planning. # Intiface Desktop Rust We're now down to the implementation of the First Run Experience in the new version of Intiface Desktop, then it should be ready to go. I'd like to say this'll happen this week, but we'll see. # **Youtube** Finally getting more youtube videos out! Did a very quick Bluetooth Buttplug comparison video last week, and this week I'm hoping to finish up editing the diamo modification video and will get that posted. # Everything Else - There's now a mod for Our Apartment ([https://momoirosoft.itch.io/our-apartment)](https://momoirosoft.itch.io/our-apartment)) via the Love Machine BepInEx mod ([https://github.com/Sauceke/BepInEx.LoveMachine)!](https://github.com/Sauceke/BepInEx.LoveMachine)!) - Buttplug is apparently also being used in VRHot now! I hadn't even heard of this game before they announced buttplug support. Always interesting when that happens. [https://www.vr-hot.com/](https://www.vr-hot.com/) Anyways, that's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## New Youtube Video Modifying The Lovense Diamo For Size And Comfort Ever wonder what your patreon dollars go toward? Watch me cut apart a $100 sex toy and find out! Seriously though, I tried a very hacky solution to resizing the diamo, with some vague success. This video documents the process. --- ## Intiface Desktop Rust Egui Alpha 1 In lieu of a weekly update, here's what y'all actually pay me for: A chance to be the first to test my extremely alpha software! Isn't paying to be my QA fun? :3 # What To Expect If you're going to try this out, know that my main goal here is "stay out of the way". The old intiface was HORRIBLE at that, now I'm trying to minimize what users have to do normally so they can just boot up and go. Also, expect a lot of things to be missing, because I'm still working on a good bit of this, but want to make sure I'm at least headed in the right direction. # Currently Windows >= 10 Only Should work on other platforms, I just haven't had time to test on mac/linux yet. Maybe later this week. # No Application Update Notifications Currently For now, if I put out a new version, I'll post it here. I've still gotta build out the infrastructure for app updates but wanted to get this out sooner rather than later and it's already been a month of "one more thing". # Installation I actually built an installer for this, and all file will be separate from Electron Intiface Desktop. These can run side-by-side but I really don't recommend running them at the same time. Having both installed won't hurt anything though. If you need to uninstall this new one, it'll be listed at "Intiface Desktop x.x.x.x" in your apps and programs. # How To Use This is pretty much exactly like the old electron Intiface Desktop. Only difference is that the server status is now always visible. It's kinda like a music player interface now. - Hit play button to start server - Hit stop button to stop server - Icons on right will show status (Hear No Monkey = server off, Ear = Server listening, phone = server connected. I just like my weird iconography ok?) - There's also text in the middle If you hit the down button, that'll open up the rest of the UI, and looks pretty similar to the older Intiface Desktop builds. # Crash Reporting Default To On This will be part of first run setup once I get the UI together for it, but right now crash reporting defaults to on, so if anything falls over, I'll get a notification on Sentry. If you absolutely hate this, you can turn it off in App Settings > General. # If Something Goes Wrong Or Weird Hit the **"Send Logs To Sentry"** button on the log panel and send me a message on here or discord/telegram/twitter. # I Need Opinions! Is this better than the Electron one? Worse? Are the color sets for the UI ok? If you have absolutely ANY opinions, please let me know them! You can reply here, send me a message on patreon/telegram/discord/twitter, whatever, I just want as much feedback as possible. # Where We Go From Here This test will be patreon-only until I finish out the update systems and the first run experience, which might happen later this week if motivation holds out. Right now I just need a break from GUI programming though because I am starting to approach burnout again. Once I've made sure that the application can at least notify about updates and possibly even update itself, I'll move to a larger beta period that will probably get a channel on the discord server where I can interact with more people. After enough people have tested this and we're feature complete with some documentation available, this will replace the electron Intiface Desktop. What that process is going to look like is an interesting question since the Electron system updates itself using some odd methods, but we'll see what happens. I don't expect this to happen before Feb 2022 though. # Why Is This Important? So, outside of the obvious (Intiface is how most people actually use Buttplug, and I've really neglected it)... This is also me doing a test run of distributing apps through Patreon. I'd like to maybe do some fun small projects using Buttplug next year, because I've really lost touch with how developers interact with the library. I figure I'll make these part of the $5 tier or something, as they probably won't be fully formed ideas or anything I want to keep up, but rather just some fun experiments. # Other News That Would Normally Be In the Weekly Update This thing has kinda been my week so I don't have much to say otherwise, other than I got the youtube videos for the buttplug reviews and diamo mod up finally. That's really been about it.  Expect a refresh of the Awesome Buttplug Apps/Games List ([https://awesome.buttplug.io)](https://awesome.buttplug.io)) sometime this week because I'm way behind and have devs prodding me about updating it. # Conclusion Ok I think that's it for now. If you have any questions, please reply to this, message me, or hit me up via: - Twitter: [https://twitter.com/buttplugio](https://twitter.com/buttplugio) - Telegram: qdot76367 - Discord: qdot#0001 or [https://discord.buttplug.io](https://discord.buttplug.io) Until next week, Keep Buttpluggin'! --- ## Intiface Desktop Rust Egui Alpha 2 That was quick. New version attached to this message. A patron already found a bug where the new Intiface Desktop icon would overwrite the old one on the start menu. I just updated to 0.0.2 which now calls the application "Intiface Desktop Rust" to counteract this. Also hearing reports that the packed engine may not execute correctly, looking into that now. Windows is such a fragile thing. :| --- ## Intiface Desktop Rust Egui Alpha 3 No alpha survives first contact with users. New version is attached. So it turns out the engine update system was downloading an older engine that doesn't work with this build of desktop (but I wasn't seeing it because I set different engine repos for debug/release. Oops.).  For now, I've just removed the ability to get any updates, which isn't really needed at this point anyways because we're in Alpha 3. Apologies for the multiple emails, hopefully this is it for at least the night. --- ## What's qDot Up To This Week? (2022-01-03 Edition) Back to the dayjob... # Buttplug The Intiface Desktop Alpha last week surfaced some bugs! Mostly that if someone has a Lovense dongle and a Bluetooth dongle connected at the same time, they'd fight each other. Also found out that there's been a blocking issue in the serial port implementation that's made OSR-2/SR-6 performance suck with Buttplug. Fixed that too. Released Buttplug v5.1.6/Intiface Engine v46 this weekend, fixing the above issues as well as backing off the version checking problem that was crashing people with custom devices. I've started planning for Buttplug v6, which will finally include new messages (meaning support for the Lovense Max Air Bladder, fucking machines like the HiSmith, possibly kegelcizers and other input devices, triggering on-device patterns, etc), as well as a bunch of quality of life fixes. If you're curious what that release might look like, the relevant kanban board is here: [https://github.com/buttplugio/buttplug/projects/1](https://github.com/buttplugio/buttplug/projects/1) # Intiface Desktop Lots of work happening on the new Intiface Desktop, thanks to input from everyone here that tried the first few betas! I can't stress enough how much help its been to get feedback early and often. :D I should have another release out this week, which will most likely be the last closed alpha before I go to public beta. There will be some small changes to UI, but mostly concentrating on filling things in and fixing bugs for the time being. # Other Stuff - I've updated the Awesome List: [https://awesome.buttplug.io.](https://awesome.buttplug.io.) This includes adding some FFXIV stuff, as well as moving things with multiple apps/plugins (vrchat, ffxiv, minecraft, etc) into their own sections. That's... actually it for right now. Mostly concentrating on trying to get the new Intiface Desktop to beta, then it's on to documentation, Buttplug v6, and hopefully something new! Until next week, Keep Buttpluggin'! - qDot --- ## Intiface Desktop Egui Beta 1 V10999 Next version is ready to go! Tons of updates and bugfixes since the alphas last week. Still needs basic documentation and all that, but the repo is now public, and updates should work too! (You'll have to manually update the application on new versions but it'll prompt you to do so) As always, if you decide to check this out, please let me know any feedback you have! --- ## What's qDot Up To This Week? (2021-01-17 Edition) One more featuring myself to death... # Intiface Desktop Intiface Desktop Beta 2 is pretty close to done! Lots of bugfixes, polishing and layout tweaks, but the big addition this time is going to be... **THE RETURN OF THE DEVICE SIMULATOR** Yes! After 3 years of saying "yeah I'll get around to it", there's now a device simulator in Intiface Desktop Rust Beta! No longer do you have to use hardware to test the library!  It allows you to create devices with vibrators, rotators, and stroking elements, and connect/disconnect them as you please! I honestly can't believe I waited this long to put this together, as it makes testing things MUCH easier. The other major addition is going to be the News panel. This will just be a panel that will pull news from a site so I can update people about new hardware support and apps within Intiface, instead of depending on them to watch the buttplug twitter account. # Buttplug Getting the device simulator going has actually required a surprising amount of updates to Buttplug, most of which are way under the hood, but I'll be releasing a new version of the library this week because they're important changes. This includes finally removing all *unsafe* blocks from the code, as they didn't need to be there in the first place and were vestiges of me not knowing what I was doing 2.5 years ago. # Everything Else - There's a new audio-to-vibration app that uses Rust and egui! It's currently Windows only and very alpha, but definitely something to watch! [https://github.com/Shadlock0133/music-vibes](https://github.com/Shadlock0133/music-vibes) That's pretty much it for right now. Expect Intiface Desktop Beta 2 out this week! Until next week, Keep Buttpluggin'!  - qDot --- ## Intiface Desktop Beta 2 Intiface Desktop Rust/egui Beta 2 is out! Now with: - A news panel that I can update without making new versions of the app! - A device simulator! - Better server status panel layout (but still kinda jank)! - Lots of internal cleanup! [https://github.com/qdot/intiface-desktop-egui/releases/tag/2.0.999](https://github.com/qdot/intiface-desktop-egui/releases/tag/2.0.999) (This is why there was no weekly update this week, was busy trying to get this release together and it took longer than planned) --- ## Intiface Desktop Beta 2 First Run Experience Broken Welp so much for that. If you're updating from Beta 1 to Beta 2 of the new Intiface Desktop, you're fine. If you've never run Intiface Desktop Beta before, wait until tomorrow. I broke the first run experience on it so you'll be stuck on the first screen. :( --- ## Intiface Desktop Beta 2 Fixed Fixed the first run experience, so now you can give the new application a shot! [https://github.com/qdot/intiface-desktop-egui/releases/tag/2.0.999](https://github.com/qdot/intiface-desktop-egui/releases/tag/2.0.999) --- ## What's qDot Up To This Week? (2022-01-31 Edition) v6 begins. # Buttplug Finally started Buttplug v6. First off: Step Ranges. This is a fancy term for saying "limit how fast/far your toy can go". As we're looking at implementing things like fucking machines in this version of the library, we'll need limiters. However, this will also be handy for things like strokers, if you don't want them to go past a certain point. I've also started work on the new LevelCmd, which is what will allow us to easily extend to oscillation, inflation, etc without having to do massive revisions of the library every time. It's won't be a panacea, but it'll definitely be better than our current situation. # Intiface Desktop Intiface Desktop Beta 2 is out! Seems to be pretty solid so far, for all... 12 people who've downloaded it. I'm burnt as hell on GUI programming, so I'm taking some time to work on Buttplug while I see how this beta goes. The next version of Desktop will probably be both boring and important, as it'll mostly be cleaning up places where things could crash on error, and providing better ways for users to receive errors and get help (possibly automated help!). After that's done, we'll probably be ready for release. Oh and for Mac/Linux users, getting the rest of the platform compat up is the next step. There should be Beta 2 Mac/Linux versions soon. # Everything Else - I've got some new Hismith hardware coming in to test, as they also make a stroker. Who knew! (IOSTIndex knew :| ) Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-02-07 Edition) A short one because... # Buttplug ... Things got difficult. Right now I'm trying to implement one of the most important features of Buttplug v6: User device settings. This will allow you to set cosmetic things like device display names, which is pretty easy. However, it's also required for far more important features, like minimum device communication gaps (to stop programs that send too many commands and jam up BLE queues) and step ranges. Step Ranges are a way to say "A device has a minimum speed of x, and a maximum speed of y". This is a nice to have for things like vibrators (so you can just tune out speeds that are too low), but is the only way to make things like fucking machines safe to use with the library. Implementing this has turned out to be quite challenging, due to the way we structure the library and store configurations. I've gotten the basic system working and some tests implemented, but I've already had to redo things multiple times to make it work, and it's not quite as future-proofed as I'd like. Working on this design and implementation took up pretty much all of the time I had to work on anything last week. I'm pretty confident I'll have a full solution ready this week and can hopefully get on to other things. # In Other News - It's similarly boring to the previous news, but there's a new version of the windows API library we depend on for Bluetooth that should fix a bunch of issues like device disconnect (WE'LL BE ABLE TO DROP DEVICES IN-PROCESS ON WINDOWS FOR THE FIRST TIME EVER) and OS compat. Will probably end up in a new Buttplug v5 this week. So, yeah, not every week can be exciting I guess, but getting this feature done should really improve quality of life for developers and users. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-02-21 Edition) Same as it ever was... # Buttplug This will probably be the shortest weekly newsletter ever because, well, I'm still working on the same damn thing. Redesigning how we deal with device configurations so that users can build their own settings is now in Week 4 of development. The slow pace is mostly due to me having 1, maybe 2 days a week to work on things, mostly due to Life Getting In The Way. Though also because designing this has been difficult and required multiple iterations. I *think* I'm seeing the light at the end of the tunnel now, and will have things done soon. # Other Stuff - Part of Life Getting In The Way was VRChat releasing the beta of OSC on Av, which is something I've been waiting for since last April. As always,[ I did some dumb shit with it](https://twitter.com/qDot/status/1494724108830994436/). Anyways, that's it for now. Back to the slog. Until next week, Keep Buttpluggin'! - qDot --- ## Elden Ring And Haptics Rerouting The weekly update would consist of one project this week, so I'll just post the project itself.  I managed to reroute Elden Ring rumble to sex toys. This involved using USBPcap, which is a pretty wildly unsafe way to do things, but it did the job. There's video of the project at [https://www.youtube.com/watch?v=KyMZBOQtmic](https://www.youtube.com/watch?v=KyMZBOQtmic) I've written a post on how *all* of my rerouting projects worked, from the original SeXBox all the way through to Elden Ring, which is the post above. It has all of the relevant links at videos. Was nice to do a shitpost project again. Anyways, back to the buttplug mines. Hopefully more library updates next week. --- ## What's qDot Up To This Week? (2022-03-14 Edition) Our long national nightmare is... well, not exactly *over*, but... **Buttplug** Ok apparently Patreon removed the header font choice for posts so things are gonna look a little weird this week. Anyways, after 6 weeks and god only knows how many refactors, the new device configuration system for Buttplug is done! It even has a few tests! This will allow us to build more capabilities for device setup and configuration on a per-device basis. In the first version of this release, you'll be able to: - Make device allow/deny lists - Set device movement limits (This has been what is holding up fucking machine support, so we'll hopefully have hismith support now!) - Get the same device index for a device repeatably I've still got some work to do around the rest of the library to make sure this is supported properly, but the fact that it's done is cause enough for celebration, 'cause for a while there it was looking like that was never going to happen. **Intiface Desktop** With the config stuff done, I'll now need to add UI so that it can actually be accessed. I'll be doing this in the next version of the egui Intiface Desktop release, which I'm working on now. This will most likely also move that application from Alpha to Beta phases, and I'll be adding a webpage for it on the Intiface domain to start pushing it for usage more while starting to deprecate the Electron based application. That's it for this update. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-04-18 Edition) Being very tired. **Personal News** To start, news about me. Due to some family illnesses involving long hospital stays, I don't have anything close to a schedule or general understanding of time at the moment, hence not having posted updates here in the past month. I'm hoping things will return to normal soon, and with that, more update posts. That said... **Buttplug Android** Sitting around a hospital is pretty boring, so I decided to try a new project: Getting Buttplug up and running on Android. Most of the work here was already done, between our community contributed Java layer, as well as some work an anonymous developer did last year to hook Android into our Bluetooth library. I just needed to glue everything together and bring it up to date, which I've been working on for the past few days. I'm happy to say that, as of writing this, I just manage to have the library find and turn on a lovense toy using my Android Pixel 3 phone. There's still a lot of work ahead before this is distributable, but my hope is that we can have Intiface Mobile alongside Intiface Desktop, since most toys are made to talk to phones anyways. This would solve a ton of our problems with random desktop bluetooth APIs too. **Buttplug v6** I've also been working on Buttplug v6, but it continues to be slow going. Building the device configuration system has really proven to be difficult, but I think it's most of the way there now, and I'm down to figuring out what UI to access it will look like. So, yeah, that's it for now, just wanted to at least post *something* since you're sending me money and all. Thanks for your continued patronage, and until next time I have some time to post, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-05-09 Edition) Family emergency over, finally, and slowly but surely returning to life as normal... **Buttplug** Work has resumed on Buttplug v6. Right now I'm documenting the work I've done so far, as the portion of the library that deals with device configuration (how we know what devices we can connect to and what protocols to speak to them) has become ridiculously complex. So much so that if I walk away from it for more than a couple of weeks, I can possibly lose track of where I was in it. Documenting it has just made this complexity even more obvious, as it's hard to state in complete sentences how it works, but I'm doing my best to just get down what I can and come back to it to refactor later. Once that's done and working, I'll be implementing the LevelCmd command, which will give us the promised extensions to fucking machines, device sensor reading for some input devices like pressure sensors, etc... That will be another large bit of work since any messages will be translated to/deprecated around that, but in the end we should have a much cleaner system. **Intiface Desktop and Mobile** With the successful porting of Buttplug to Android, there's now a major question of how much work should be put into the new Rust-based Intiface Desktop. It's mostly feature complete next to the Electron version, but just needs a few more updates to work with v6. I'm probably going to try to keep new features as minimal as possible, then start concentrating on actually producing the Android/iOS based apps, which will possibly free us of many of the issues we have with bluetooth connections on desktops (as well as pairing across multiple machines). No ETA on when mobile apps will start happening. I have an extremely minimal Android app with one button that just scans for devices currently, but there's a ton of work to do at the FFI level to handle exposing server APIs and what not, which we'll need for mobile apps. I also still need to work up a Swift FFI layer for iOS first. Anyways, that's where things stand for now. Hoping both updates and development will speed up now that I'm not busy with Life Stuff. Until next week, Keep Buttpluggin'! - qDot --- ## Where the Fuck is qDot? (2022-06-06 Edition) Been a while since I've dropped off updates for a whole ass month. # Buttplug So it turns out if you rush the development of a thing to get it done then sit on it for 2+ years, it takes a while to clean it up. In this case, months. That said, I think the server side of Buttplug Rust is finally in better working order. When I started Buttplug Rust's server implementation in late 2019, it was because I found a mostly-already-done way of accessing Bluetooth in a cross platform way through rust. Everything that wasn't that got rushed in order for me to reduce the amount of work I'd have to do by maintaining multiple versions of the server (at the time we already had C# and JS). I... never really revisited things after that, just bolted shit on. "Technical debt" at its finest. That's what most everything this year has been so far, cleanup from that mess because it was becoming impossible to bolt anything more on. Now that's done, BACK TO BOLTING. Which will hopefully mean LevelCmd and lots more device support. There's a bunch of Quality of Life things this fixes too, like most protocol implementations being like, 30 lines of code now, but it's QoL for me and like, 1-2 other people. :) # Intiface Desktop and Mobile This is where shit gets weird. In the last update, I mentioned that I was looking at building Intiface Mobile, probably using native APIs. [Then this comment on btleplug happened](https://github.com/deviceplug/btleplug/issues/8#issuecomment-1132878595). Someone ported our Rust bluetooth library to work under Flutter, google's cross platform desktop/mobile framework. Using this as a template, I may be able to have Desktop and Mobile all run under the same codebase, getting us to all platforms WAY faster than my original egui/java|kotlin/swift idea. I'm researching this in the background while finishing up Buttplug v6, but would really like to have some sort of mobile solution for toy connections ASAP, because the discord gets more and more desktop bluetooth support requests daily, and I'm not sure how much longer we can keep up. # Not Buttplug With all of that happening, what am I currently working on? Eye tracking. >.> Turns out there's a decent DIY solution to possibly get avatar based eyetracking VR for < $50. I've been working over the past week with a few other developers (who've already been at this for 6 months) to put a solution together for this. It's looking really good so far! Check out [https://github.com/RedHawk989/EyeTrackVR](https://github.com/RedHawk989/EyeTrackVR) if you're interested. But yeah it has nothing to do with Buttplugs. Anyways, that's it for now. Hopefully back to at least every-other-week updates if not every week. :) Until next time, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-06-27 Edition) ALL HAIL SCALARCMD # Buttplug Buttplug development is back on track! After one last overhaul of part of the configuration system (for those keeping count, that's the 8th time I've had to do a major refactor on it this year. But this'll be the last one. Really. Maybe. I think), I've finally moved to adding new messages to the Buttplug protocol. First up is ScalarCmd, which is what used to be known as LevelCmd, but Scalar sounded mathy-er so I went with that. This will allow us to convey information about devices that take a single, static value. Currently the only way we can send that information is via VibrateCmd, but there are devices like fucking machines (which oscillate at a set speed), the Lovense Max Air Bladder (which constricts to a certain level), etc that don't actually vibrate, so we needed to either add new messages for those, or just make a new message that conveys this setting in general. Ended up going with the second one because it'll be easy to add on in the future. The work to integrate this throughout the library is happening now. Once that's done, I'll be moving on to Sensor messages, will which allow input of different types. We're mostly concentrating on pressure for the moment (kegelcizers, Nogasm/Edge-o-matic, etc), but could also manage information for other sensors like temperature, accelerometers, etc... Still figuring out exactly how this will work, but those two messages will be the big additions for Buttplug v6. Once I have something to Beta, I'll let everyone on patreon know. :) # Intiface Desktop/Mobile I've started working on some of the new Flutter code for Intiface Desktop/Mobile. Due to the amount of new features coming in Buttplug v6, it'll need to ship with a new version of Intiface, and while the Rust version was coming along, the Mobile part is just too good to pass up, so Flutter it is. That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-07-17 Edition) Oh so that's what Dart looks like # Intiface Central Yup, you read that right, now it's a rewrite AND a rename. As I need some space to consider sensor messages in Buttplug (I'll talk about that in a sec), I've started work on Intiface Desktop in Flutter. However, since this will hopefully be mostly a shared code base between mobile and desktop, calling it "Desktop" doesn't really work anymore.  So now it's Intiface Central, which will be completely clear and not at all confusing when the Desktop version of Intiface Central will work as a router for the mobile version of Intiface Central! HOW COULD THIS POSSIBLY GO WRONG. Anyways. Porting from Rust to Dart is going pretty quick, outside of the fact that Dart somehow doesn't have sum types in the year of our lord 2022, which is rough. But compiling to desktop and mobile and having a decent, non-immediate mode GUI means I'll put up with it. Will post alphas once they become a thing, probably a week or two out, minimum. # Buttplug Buttplug v6 is down to getting sensor messages (i.e. pressure readings from kegelcizers, accelerometers, buttons, battery, RSSI, etc) in! Ok and also probably a shitton of tests. But honestly if the features are in I can just ship v6.0.0 and then patch to my heart's content as my users QA for me, right? Only problem with sensor messages is that they're a completely new dynamic in Buttplug, so I'm having to think through the design on this pretty hard before laying down code. A lot of the Intiface work right now is manual porting, so it kinda gives the codemonkey part of my brain something to do while I mull over that architecture. Hoping at some point in the next week or so I'll finally feel like I've got something solid and can sit down and bang the sensor MVP out over a few days. # Everything Else Hopefully have some new toy stuff coming in soon! Can't talk much about it quite yet but excited. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-08-01 Edition) DONE! SORTA! # Buttplug Buttplug v6 is feature complete! I got sensor messages in over the weekend, and can now relay pressure and battery using them! This is a huge step forward for the library, as now we can provide information from toys that have capabilities for it. For v6.0.0, this will probably just end up being a few pelvic floor exercisers, and maybe some buttons on some devices, as well as the ability to get battery levels and now RSSI from bluetooth (hopefully, that's a weird one). We'll be quickly growing those capabilities in patch versions later on though. Now the work is on to get things tested, cleaned up, and released! Dev cycle ran WAY too long on this version (8 months >.>) so I'm very much looking forward to getting this out. # Intiface Central Intiface Central (what used to be known as Intiface Desktop, now written in Flutter and no longer just on desktop) is up and running on Desktop AND Android! It should also work on iOS, I just haven't had a chance to set that up yet.  Now, just because it's up and running doesn't mean it does much. It can bring up the Buttplug Server and that's about it at the moment. There's a lot of UI work left to do, but I plan on releasing betas with minimal features as soon as possible so y'all can start trying toy connections on your phones! This will be a huge deal for compatibility. # Everything Else You may have heard about the upheaval in VRChat last week. There's LOTS of churn about toy access in VR virtual worlds right now thanks to that. I'm trying to keep up to date lists of every available plugin for VRC/ChilloutVR/neos/god knows what else in [https://awesome.buttplug.io](https://awesome.buttplug.io) That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## Whats Qdot Up To This Week 2022 08 151 Edition Paying for my sins! # Buttplug Well, Buttplug v6 is (mostly) feature complete, which meant it was time to test things, and, um. Oops. So it turns out that all of my tests were ONLY for the new version of the protocol that I'd been working with since February. Trying Buttplug v6 with pretty much anything that's actually out and working with Buttplug v5 right now breaks pretty quickly because of incompatibilities in the way I wrote some message checks. It alllllllso turns out that protocol compat with versions 0 and 1 of the spec have NEVER worked with Rust. Which means either no one uses really old stuff or no one talks about it because that's been broken for 2 years now. (Or else my initial tests there were wrong and it somehow passes checks but I really don't know how). In order to alleviate this now and hopefully in the future, I've spent the past couple of weeks finally writing a nice, scripted test system that should allow us to easily test across all versions of the spec. For the first release of Buttplug v6, I'll at least be making sure everything that worked with Buttplug v5 still works, but I'd like to have a point release soon after that which will get us to the full compat I've always said we had. >.> # Everything Else Yeah that's pretty much it. All I've been doing for 2 weeks is tests. It's one of those things that simultaneously super fulfilling and extremely frustrating. But in the end I'd really like a library that I know mostly works. :| Until next week, Keep Buttpluggin'! - qDot --- ## Buttplug V6 Its Like Firefox V4 For Your Butt Ugh. Ok. v6.0.0 is as done as it's gonna get. Blog post sums up most of it, really shouldn't surprise anyone here as this is most of what I've been talking about during development. On to v6.0.1. --- ## What's qDot Up To This Week? (2022-09-12 Edition) BLoCs! # Intiface Central The past 2 weeks have been almost purely Intiface Central UX work. This has required me to learn how state management works in flutter, which is Very Much Its Own Thing And Does It In Its Own Special Way. This was a good 4-5 days of reading and trying things until it finally clicked. After that, everything came together surprisingly quick. I now have a basic version of Intiface Central running on Desktop, and I'm now trying to finish the work required to port that on to mobile. This mostly involves taking the Intiface CLI and turning it into both a CLI (for desktop) *and* a library (for mobile), which will now be known as Intiface Engine. Made good progress on this over the weekend, and I'm hoping to have everything building on Win/Mac/Linux/Android/iOS by next weekend. Soooooo, I feel like I can now say we'll see an alpha of Intiface Central in weeks instead of months! This is huge progress. :D # Everything Else - Having unblocked Buttplug with the v6 release, some of the device developers are working there again. v6.0.1 with more device updates and some bug fixes should be out soon. That's it for now. Once information for joining the mobile alpha is available, I'll let everyone here know, as anyone that's a patron should be able to try it out! Until next week, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2022-09-19 Edition) APPS # Intiface Central Well, I am as shocked as anyone else, but Android and iOS apps are up, running, and seem fairly stable?! I spent the weekend hammering out platform specific issues mostly having to do with dumb buildchain mistakes, but I've got the app running on both platforms, with the ability to start/stop the server, connect/disconnect toys, change settings, and basically be functional as a minimal version of desktop! I'm now just down finishing out a couple of the panels so the first version doesn't ship with anyone blank, then I'll be ready to start accepting testers. I figure for android I'll probably just distribute an APK, and iOS it'll require people use testflight and be on my dev account team so I'll send instructions for those interested once it's time to do that. Can't wait to start getting this into people's hands! (And that was everything that happened this week, but I mean, come *on*) Until next week, Keep Buttpluggin'! - qDot --- ## Cbat By Hudson Mohawke Trombone Champ Interactive Fleshlight The things I do when taking a break from working on Intiface Central. :| --- ## Intiface Central Desktop V001 [https://github.com/intiface/intiface-central/releases/tag/v0.0.1](https://github.com/intiface/intiface-central/releases/tag/v0.0.1) Here we go. The first version of Intiface Central Desktop is live. Expect very basic functionality mirroring Intiface Desktop, but now using Buttplug v6, and running under flutter. Note that the devices panel is barely existent at the moment, so you won't be able to set up serial devices, test device control, etc... That's coming once I get the basics nailed down. Builds for Windows 10+ x64 and macOS ARM are up. macOS x64 should be up later today. Linux will hopefully follow later this week. I'll also be getting everything building on CI so this'll be updated at some point. In a departure from my normal modus operandi, right now the application is not open source. This is really fucking annoying, but as the codebase is shared between desktop and mobile, I have to wait until mobile ships on a store before I can open source things. Otherwise I'll have the system released to stores out from under me (this has happened to me in the past). So for alpha/beta phases, we're closed source. Plan is definitely to open source everything though. For Android/iOS, I'm still figuring out how to distribute things. If you *really* want to be in on Android/iOS betas, please send me a private message and we'll figure something out. For Android, I'll try to make sideloadable APKs available. For iOS, this will require developer team setup so I'll need your Apple Account info, so be aware of that. Will actually make an update post this week. Maybe. --- ## Whats Qdot Up To This Week 2022 10 24 Edition And Also Intiface Central Oof. # Intiface Central For those that just want the software (that this time should actually work) before reading all of the fun surrounding the software, Intiface Central v0.0.2 is available for Windows/Mac at [https://github.com/intiface/intiface-central/releases](https://github.com/intiface/intiface-central/releases) Linux on the way this week hopefully, followed by new mobile releases which are happening on discord but I may upload here. So, yeah, Intiface Central v0.0.1 was a mess. I found out that my strategy of downloading the Engine (i.e. the part that actually has the buttplug server in it) as a separate executable and having Intiface Central run that is... not really viable given the security models of most modern OSes. Windows and macOS both hate this and won't let it happen easily. The good news is that I already had a plan for this. Our new mobile apps never even had the chance of running this way, so I had to embed the engine in them, so I spent the past week porting that functionality to desktop. It seems to work fine now, and also makes life much easier in terms of application development. We should no longer have issues of people not being able to download/update the engine, or having the file go corrupt or whatever. It does mean that any time I update Buttplug I'll also have to release a new version of Central, but at this point I really don't care. I just want this done and easier for users. I also got Android release builds working finally, so that app will be ready to ship to Google Play once it's a little more tested. We're still looking quite good for releasing Central as a usable replacement for Intiface Desktop within the next month or so, and mobile is just going to be a matter of seeing how difficult it is to get into app stores. # Everything Else That is actually pretty much it right now. I'm singularly focused on getting this done, at which point hopefully this newsletter will actually turn more varied and interesting again. Until next week, keep Buttpluggin'! - qDot --- ## Intiface Central V003 For Win Macos Android Intiface Central v0.0.3 is out, with tons of bugfixes/updates over the past couple of weeks. I'll go into the specifics in the Weekly Update tomorrow but wanted to get release info out now: Windows/macOS: [https://github.com/intiface/intiface-central/releases/tag/v0.0.3](https://github.com/intiface/intiface-central/releases/tag/v0.0.3) Android APK (Requires sideloading): [https://cdn.discordapp.com/attachments/1019675660563787776/1039087591611453490/intiface-central-v0.0.3-android12-aarch64.apk](https://cdn.discordapp.com/attachments/1019675660563787776/1039087591611453490/intiface-central-v0.0.3-android12-aarch64.apk) --- ## What's qDot Up To This Week? (2022-11-14 Edition) SO CLOSE TO DONE # Intiface Central Things are moving right along with Central. At this point, outside of custom devices (which is a tiny niche of our users), Central is either on par or exceeding the features of Intiface Desktop. I'll be releasing v0.0.4 after this email, which I'm probably going to call the last version before v1, unless some sort of massive bug pops up that requires me to release another intermediate version. Biggest new feature in v0.0.4 is the new devices panel. It's basically the same as the Desktop devices panel, except that **you can use it while clients are connected!** No more having to keep track of if the tab is connected locally and having to turn it off for clients! This may be messy, and I'll probably turn off controls while a client is connected, but I'm hoping it'll make life easier overall. The goal for v1 is to just get SOME replacement for Desktop out that has newer features. The mobile apps are going to take a little more work, but I'd still like them out before years end, assuming the app store submission process doesn't suck. And that is it for the moment! I'm only getting 1-2 days a week to work on things right now due to life in general being really stressful, but I'm really looking forward to getting this done and out to the world. Until next week, Keep Buttpluggin'! - qdot --- ## Intiface Central Desktop V004 Released Ok took me an extra night but [https://github.com/intiface/intiface-central/releases](https://github.com/intiface/intiface-central/releases) v0.0.4 is live, with the new revamped Devices panel! This will most likely be the Feature Complete point before v1 (at which point I'll be switching back to major only versioning), so if you find any bugs, please let me know! --- ## New Buttplugio And Intiface Support Forum I decided to set up a Discourse forum for support questions about Buttplug and Intiface. While I'll be keeping the discord, we tend to repeat information a lot there, so I'm hoping we can centralize info on this forum instead of making users try to dig through chat search logs. We'll see if it works out. It's been a rather rough month due to personal events, hence the lack of updates, but I'm hoping to get back on schedule this coming monday. --- ## Where the Hell is qDot? (2022-12-19 Edition) Oops. # Life So yeah, it's been a real slow month on Intiface/Buttplug updates. A combination of crunch time at the day job and a family emergency that had me back in the US Midwest for a week completely blew my development time post-Thanksgiving. Luckily that all mostly seems to be over now, and I've got 2 weeks off around the holidays, so I've got lots of plans! We'll see how many of those actually get done. # Buttplug and Intiface Central I've spent today catching up on PRs and bugs from the past few weeks, and just released Buttplug v6.3.0 and Intiface Central v2.1.0. These have support for a bunch of new Lovense toys, a few new brands (metaXsire, TryFun, etc...), and a bunch of bugfixes for major brands like Lovense, WeVibe, Satisfyer, etc... Not the most feature packed of releases, but important nonetheless. I'm hoping to start making headway on device configuration UX in Intiface Central next. This is the biggest new capability of Buttplug v6 and Central and I can't wait to show it off! Also very much hoping to get documentation and client libraries updated so our developers can start using the newest features in the system. # Mobile Intiface Central Intiface Central is now up on the Android Play Store. Just search "Intiface Central". That said, it's... not working real great at the moment. This is my first mobile app release and I'm learning a lot. Issues include: - Bluetooth doesn't work on Android < 12 - App Backgrounding doesn't work - Connections to the device itself need to be direct for the moment, which screws trying to connect to mobile intiface central from a desktop web browser, so instance. This will be fixed with a new Intiface Central Desktop feature I'm working on. The iOS app store review went well but got stuck with me needing to update my bluetooth permissions string, and due to the aforementioned life issues I haven't had time yet. Hoping to get that back on track this week but we'll see what review turnaround is like with the holidays. # Everything Else It has been EXTREMELY FUCKING BUSY despite not having much time to develop - The [UKButt Ultrakill](https://github.com/PITR-DEV/ukbutt-mod) mod blew up so much stuff omfg. Our website got more traffic than when it was trending HN. Affiliate sales went through the roof. I'm still recovering - Someone wrote a [Guilty Gear Mod](https://github.com/super-continent/acpr-buttplug)  - Someone wrote a [Hollow Knight Mod](https://github.com/danatron1/ButtplugKnight)  - [We have a forum now!](https://discuss.buttplug.io)  So yeah, just because I haven't been coding, it doesn't mean everyone else stopped too. :) That's it for now. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2023-01-30 Edition) First newsletter of the year! At the end of the first month of the year. >.> # Buttplug Having released v7 of Buttplug over the holidays, I've now shifted over to documenting things as best as possible. At the moment, this is a combination of updating the [Buttplug Developer Guide](https://docs.buttplug.io/docs/dev-guide), and trying to get our API docs for Rust/C#/Typescript etc in some sort of working order. This work is going well, if slowly. There's just a lot of information to fill in since the library is rolling up on 6 years of existing, and it turns out that writing understandable words about technology is hard, exhausting work. I also finally overhauled the Unity plugin to basically be a repackage of the C# Client DLLs. This is sitting in a branch in the Unity repo currently, but will become the main distribution of Buttplug Unity very soon. I'm hoping this, alongside better documentation, will make life easier on game devs. # Intiface Central Most of my concentration in Central right now is Mobile App Foregrounding. This is the fancy way of saying "toys will stay connected and you can still control them when the app is in the background or the phone is off". I have this working pretty well in Android as of this past weekend. iOS works-ish, but is going to take some extra considerations due to Apple's strict rules on foregrounded services. It *is* possible to support this (Lovense Connect/Remote work fine on iOS devices when backgrounded/off, for instance), it's just not something I'd originally planned for in Buttplug, so changes need to be made. # Everything Else - Been getting some new additions to the [Buttplug Awesome List](https://awesome.buttplug.io)  - I'm apparently a big enough deal to get my own Lovense Sale now, so if you want like 10% off on a toy thru this upcoming Friday: https://[lovense.com/p/buttplugio](https://www.lovense.com/p/buttplugio) That's it for now. Until next time I remember to actually send one of these things to the people who pay me to send them these things, Keep Buttpluggin'! - qdot --- ## What's qDot Up To This Week? (2023-02-20 Edition) All the things, slowly... # Buttplug Buttplug v7 continues to be fairly stable, but there's still one sticking point: The device control API sucks. The device control API is something I threw together years ago without thinking much about developer ergonomics, and due to the recent upswing in developer interest in the library, I'm now getting a lot of complaints. The good news this, I think there's some fairly easy ergonomics fixes for this. The plan is to get these fixes into Rust/C#/Typescript soon, then continue to iterate as I get feedback. Luckily the dev community seems much more engaged lately, so I've been getting really helpful comments and PRs. # Intiface Central Intiface Central v2.3.0 was released last night. For Desktop, this doesn't mean much, it's just an update of flutter and some of the dependencies. Apparently is now compatible out of the box with the steam deck though, so that's something. For mobile, specifically Android, this will be the first version with opt-in App Foregrounding. This means Intiface should be usable when the phone is off or the app is in the background, making it the reliable, carry-with-you system I'd hoped it'd be. Unfortunately the new app permissions for this require me to upload videos of proof of usage to Google, so it may be a few more days before I can get this into the Play Store. iOS is coming soon after, just requires some updates to the bluetooth code first. # Intiface Game Haptics Router The GHR is finally getting an update! Not only am I yanking out the embedded server so that it will now only connect to Intiface Central (reducing my support load), I'm adding the ability to take haptics from *all* connected controllers. This will allow games like Rez Infinite to control vibrators using both the main controller as well as the extras. An update to the GHR after this will also allow routing, so you can say things like "only vibrate when controller 2 vibrates". # Everything Else That's... actually pretty much it for now. There's been some things added to the Awesome list, so check that out: [https://awesome.buttplug.io](https://awesome.buttplug.io) Until next time, Keep Buttpluggin'! - qDot --- ## Does qDot Even Exist Anymore? (2023-04-10 Edition) Oof. Not particularly the past while. Life is getting in the way of Buttplug work. That said... # Buttplug I started working on getting user configurations into Intiface Central, and thanks to our convoluted configuration files, it got very difficult very quick. So it's time to move to a convoluted relational DB! I'm moving device configs and user configs to a SQLite setup. This will massively reduce the amount of bookkeeping I'm required to do when loading device and user configurations (meaning less code in the library, and removing many of the most complicated code paths), and should in general keep everything cleaner going forward. Unfortunately it's also a big architecture change, so I'm guessing it'll be a few weeks of work, especially since I'm maybe getting 2-3 hours a week to work on the project right now. I think it'll end up being much better in the long run though. # Everything Else - I went to GDC. It was ok I guess. That is pretty much it for right now. Until next time, keep buttpluggin'. - qDot --- ## What's qDot Up To This Week? (2023-04-17 Edition) Oops more platform support? # Intiface Central Having dragged my feet on it for a whole 2 months, I finally removed background device scanning (it'll be coming back in the future, but requesting the permission requires jumping through a ton of hoops on the play store) from the Android build of Intiface Central and released it to the Play Store this weekend. However, I'd forgotten that I'd put in untested fixed for Android versions < 12 and 32-bit processors. Luckily, both work now! AFAICT IC now works on Android 9+ (I haven't gotten any reports about Android 8 yet), and on 32-bit systems (tested on my own Nexus 7 tablet now running Android 11 thanks to LineageOS). Then I was like "Wait doesn't the Quest 2 run Android?" And sure enough, Intiface Central works on the Quest 2! Sideloading the APK via Sidequest works fine, bluetooth devices come up quickly, and can be controlled from our internal devices panel! So that's fun. I'm still figuring out how we're gonna handle distributing this, but if anyone wants the APK, just let me know here or ping me on discord. # Buttplug Not a ton to say on Buttplug otherwise. I got the SQLite project a decent bit of the ways along just to realize that it was solving a different problem than the one I was having. I've put that project on the back burner for a bit while I return to concentrating on user device configuration in Intiface Central, which I can hopefully mostly do with our current setup for now. # Everything Else Not a lot to say otherwise right now. Got a lot of interesting development happening around the discord, so hopefully more to announce soon! Until next week, Keep Buttpluggin'! - qDot --- ## Wheres Qdot 2023 06 05 Edition Ok, short one for this week because it's been ~7 weeks since the last update, but there's good reason for that. My partner was in the hospital for an extended amount of time and had major surgery, meaning I haven't really had a ton of time to write much here or elsewhere. Luckily we're back home now, but I'm still spinning back up on having a life that does not revolve around the hospital again. I managed to get a bunch of the work I did on Intiface Central in March/April out as v2.4 a couple of weeks ago (though iOS just went out today). I'm now working on some new APIs for client device access that will hopefully make life easier on developers using the Buttplug library. Really looking forward to getting the first version of this out, though it'll need to be quickly followed up by documentation updates. After that, the plan is to continue on Intiface Central UX improvements, starting with bugfixes from v2.4 updates as well as being able to add Websocket Devices through the UI (which are about to become *very* important for some fun reasons I'll talk about soon), and starting work on figuring out desktop/mobile linkage and discovery. Hopefully will be getting back nearer weekly updates over the next couple of months, but there may be gaps for a while. - qDot --- ## What's qDot Up To This Week? (2023-06-26 Edition) Still bein' a nurse... # Buttplug Looks like Buttplug Protocol v4 gonna be happening a lot sooner than I expected! I've been working on trying to make life easier on developers, and one of the big goals there is "you should be able to control every device using a single number that represents some sort of vague intensity value". Will this be a *good* experience? Probably not. But since Buttplug gets used a lot for shitposts, and also people get confused by the current granularity of device control, I'm trying to hit a happy medium that allows ease of use with advanced controls for those who need them, and I think I've found a good way to do that. Except that Buttplug v3's messages don't support the ability for a single actuator (output) on a device to be driven by multiple types of messages. So I gotta fix that. It's not a huge deal, but fixing that plus some issues with sensors will make life *so* much easier on other people writing clients. I've had the authors of the python and an alternative C# client asking about this for months and I was trying to make the current system work, but it's just not worth it. Not sure how long the new v4 design will take, hopefully weeks rather than months. Once that's done, I've got a lot of documentation updates to do, then hopefully buttplug as a library will be stable and quiet for a while and I can work on other things around it. # Everything Else - Life is still busy with the medical stuff I outlined in the last update, so in general things are very, very slow right now. But the community is doing things like... - [BUTTPLUG VALLEY, A STARDEW VALLEY BUTTPLUG MOD](https://github.com/DryIcedTea/Buttplug-Valley). Yes there is now a stardew valley mod for vibrators!  That's it for now. Until next time, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2023-08-07 Edition) Life can really just stop it at any point now. # Intiface Central But the good news is, at least progress is happening sometimes! I've managed to get Intiface Central v2.4.3 out to all platforms, which has a lot of quality of life work, as well as some pretty important bugfixes (especially for Android Bluetooth). Also, I'm now working on Intiface Central and GHR Documentation! It's available at [https://docs.intiface.com](https://docs.intiface.com) Right now, I'm mostly porting over the Buttplug FAQ, but at some point there will also be actual documentation on how to use Intiface # Buttplug Every time I try to work on Buttplug at the moment, I keep running into issues with the current message spec, so I've given up trying to work around those spec problems and am just working on fixing the spec itself now (which means we're on to Buttplug v4, a year after v3 landed). This gets back into boring, in-the-weeds developer stuff, but as always, in the end hopefully it'll be easier for everyone. # Everything Else - As mentioned at the start, due to family medical events, day job events, etc I have had pretty much no time or energy to do much of anything since May, so things are going *very* slowly right now. Thanks to everyone who's still signed up here, I'm not dead, it's just... not been a great year so far. - I'm hoping to maybe start getting to either more writing or videos here soon, as code has been a bit difficult to get around to lately. We'll see how that pans out, will post updates here if/when that happens. - For those looking for me on social media, I'm mostly over on bluesky at this point, at [https://bsky.app/profile/buttplug.engineer](https://bsky.app/profile/buttplug.engineer) or [https://bsky.app/profile/buttplug.io.](https://bsky.app/profile/buttplug.io.) If you're looking for an invite, let me know. Until next time, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2023-08-28 Edition) ## Intiface Central I finally got fed up with the logging panel and have now rebuilt it. It's now much more compact, easier to see more messages (especially on mobile), and we should have log/crash reporting in again too! This will be massively helpful for support in the future. Annnnnnnnd that's it. Life continues to be rough due to personal/medical issues, but managing to get stuff done here and there. Until next time, keep buttpluggin'! - qDot --- ## Whats Qdot Up To This Week A Lot 2023 09 11 Edition Ok well I guess I'm back on the development wagon. # Buttplug Teledildonics I've been feeling like developing again lately (and not only because I finished Baldur's Gate 3), so I decided to try to make headway on some fun projects instead of just diving back into the library specifics. First and foremost: I have a proof of concept of Buttplug Teledildonics working. This is a subject that will probably need a whole blog post, but tl;dr: I have a very easy way to do peer-to-peer and server-client style remote connections for Buttplug using WebRTC. I ran my first test on saturday, streaming a GHR session to someone on the other side of the US while doing screenshare through Discord, and it worked wonderfully. I'm planning on doing another stream with multiple viewers at some point soon to see how that works out, will post here when I've got that scheduled. There is a LOT to do before this is usable in the wild, but it will most likely power our upcoming desktop/mobile interconnect system first (to make it easy to forward to control to a phone when using desktop apps/games that don't have an easy way to set server addresses). Feel free to poke me on here or Discord if you have any questions about this. # Buttplug WASM Due to several requests, I'm working on getting the Buttplug Server component (the part that actually talks to hardware) compiling for the web again. This will allow people to run Buttplug completely within Chromium/Blink based browsers (though I still recommend connecting out to Intiface Central if at all possible), a feature several apps depend on now. The code is done, I've just got to figure out packaging, which I am... not looking forward to (this involves webpack :c ).  # Intiface Game Haptics Router I also updated the GHR finally! The way the GHR was working was to watch a system called XInput for Gamepad commands. XInput has now been EOL'd in favor of another system, known as UWP Gaming Input. Unity now compiles to this API instead of XInput, meaning some games were simply not even showing up on the GHR anymore, or were showing up as XInput but not working. With this addition, the GHR *should* work with many new games. I've only tested it with one so far (Pawperty Damage), but I suspect we'll be hearing about more games after I get this released. I just have some cleanup to do, should be ready to go later this week. In addition, I'm looking at adding some very simple "cheat" style routing to the GHR. This would allow people to use programs like Cheat Engine to find health/damage/etc values in games, and we could pick those up and route them to toys via hooking. I'm still working out the design and feasibility on this, but it could make the GHR much more useful in the future. More info on this soon. # Everything Else Life is starting to become *slightly *less hectic but still isn't great. Really hoping to keep up on this new momentum though, I'm actually excited about working on stuff again for the first time since I got the mobile apps shipped. This has been the biggest week for Buttplug development since January. Excited for what's to come! Until next time, keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2023-10-09 Edition) Playing Cyberpunk 2077 so much that I forget it's Monday and therefore write my update on Tuesday. :| ## Intiface Central and Buttplug Anyways, Intiface Central v2.4.5 is now out! There was a v2.4.4 but we don't talk about that because I completely hosed Lovense Dongle support in it. This release took *way* too long to get out, mostly because of scope creep and my still unpredictable schedule. I ended up just making a hard cut after I finished mDNS and calling what we have at the moment done. The big new features: - Joycon support on Desktop - mDNS Advertising on all platforms - Experimental, I didn't have a lot of time to test it. This will allow Intiface clients/servers to find each other on the local network instead of users having to type in IPs. - Crash Reporting on all platforms - Experimental (until I feel like I have the privacy where I want it) and opt-in  We're already getting a ton of crash reports, so thanks to anyone who has turned those on! The next 4 things ahead: - iOS Backgrounding - So people can run the app on iOS and still control their toys when its not on focus and not have the whole thing disconnect. This is *surprisingly* difficult to pull off. - Intiface Central Phone/Desktop Interop - This will allow users to use their phone to control hardware, with apps interacting with intiface central on the desktop. There's two reasons we need this: older apps that don't give a way to select intiface central addresses, and websites that can't connect offsite to insecure endpoints (i.e. https site on desktop trying to talk to non-secure websockets on a phone, which all browsers will block). There's also the chance we could just run a self signed certificate in front of the mobile app too, but teaching users how to debug and bypass that is a nightmare which is why I took that feature out in the first place years ago. - News/Log panel updates in IC - Just needs some UI work. - Buttplug Spec v4 - Mostly for developers, but this will fix some issues in Buttplug v3 as well as hopefully futureproof us for more complex devices that will have sensor/actuator interactions (i.e. motors with encoders, etc...) Ideally all of this will be done before the end of 2023, but we'll see what my schedule ends up permitting. Assuming we do get it all done though, we'll be in very good shape to start looking at actual implementation of the Remote Control project that I did a proof of concept for last month. ## Everything Else I don't actually have a ton to write here myself, I've been so busy on the above content that I've not really been able to pay attention to much otherwise. Things have been pretty busy in community contributions though, so keep an eye on the Awesome list ([https://awesome.buttplug.io)!](https://awesome.buttplug.io)!) We have a C++ and Kotlin client, an Unreal plugin, and other things happening! Anyways, that's it for this week. Until next time, Keep Buttpluggin'! - qDot --- ## Intiface Central Coming To Steam Finally got through the store page part of the process, now just gotta get a build up and a trailer made. Aiming for Steam release early November. This is mostly in the service of making Steam Deck installs easier. Otherwise it'll just be a shitpost, mostly because I've always wanted to add Achievements to my software. There may be paid DLC in the future, which will mostly be for incredibly, useless dumb features that will not affect core usability, as a funding strategy for the project. All core features will remain free. --- ## What's qDot Up To This Week? (2023-11-06 Edition) So much for that Quiet End Of The Year wish. # Life A couple of weeks ago, my workspace in my house flooded due to some broken plumbing. The good news is, no hardware was damaged. Almost no material losses really. The bad news is that we're still dealing with insurance and water remediation, and that's gonna take a while, so I'm having to work from another space, and all my hardware and stuff is packed up for the moment. This has caused what few schedules I did have to no longer really exist. # Patreon Rewards Due to the aforementioned events, making videos isn't really happening like I thought it was going to, which means my addition of video credits to rewards isn't really working out. I'm going to add Patreon Rewards for $5/month and up that include getting credits in Intiface Central (with people in higher tiers getting... a bigger font or something). This is OPT-IN, so you'll need to let me know you want in and what you want your name to be there. I'll be messaging everyone at or above this level soon to confirm. # Intiface Central and Buttplug Despite having to move my workspace and all, I'm still getting releases of Intiface Central done. I released 2.5.1/2 this past weekend, which should fix some small bugs. I'm now starting on some slightly larger feature work to get features like desktop/mobile repeaters, better error communication, and more extensibility in on the UI side, while continuing to refine the requirements for the next protocol version of Buttplug on the internals side. # Everything Else - We now have not 1 but 2 options for Unreal Engine support! [https://github.com/DeviantdVeloper/ButtplugUE](https://github.com/DeviantdVeloper/ButtplugUE) and [https://github.com/epsypolym/Buttplugin](https://github.com/epsypolym/Buttplugin) - There's work happening on a Slay The Spire buttplug mod! Realizing I don't have the github for that yet but hopefully it'll be up soon That's it for now. Until next time, Keep Buttpluggin'! qDot --- ## What's qDot Up To This Week? (2023-11-27 Edition) Scrubbing away technical debt # Buttplug and Intiface Engine Back when I built Intiface Central, I didn't really do much work on adapting the layers below it. I just kinda made Buttplug and Intiface Engine (the first user layer on top of Buttplug, which handles things like setting up the engine, running our command line interface, etc... Central sits on top of Engine and provides the GUI) work with the new Central setup. This is now officially *getting in the way*. Back when we had Intiface Desktop, Engine used to run as a separate program, so it could upgrade outside of Desktop (like whenever I wanted to add new hardware without changing the GUI). Unfortunately, that model doesn't work with Central, where we also have to run on phones, and phones don't let you start new processes. So I spent my holiday break starting to clean up Engine to work with the new world where it compiles directly into Intiface Central. This work is ongoing, but it should mean hopefully fewer crashes and better reporting of errors in the future. Unfortunately it's really boring to talk about though. # Intiface Central Because I also needed to implement new features to keep myself sane, *modes* have started development in Central. In the next release, there will be two *modes* the app can run in: - Engine, which is what it does now - Repeater, which allows Intiface to work as a proxy to... another version of Intiface somewhere else. So like, if you're on desktop but you want to use your phone as your hardware controller, but you also want to play a movie through a webpage that will control the toy, you need an proxy to hop through so the webpage on your desktop can talk to intiface on your phone. Now Intiface on the desktop can be that proxy. This is handy for situations like the web (already mentioned) as well as older Buttplug programs that expect everything to be running on the same machine. The repeater feature is nice, but even better is that this will allow me to add even more modes, with the next hopefully being a teledildonics service layer. When that'll get done, I have no idea, but it's nice to finally be in striking distance of it! # Everything Else - Next version of Intiface Central will hopefully also have crowdfunding credits, so everyone at the $5 or above level, be watching for messages soon, as this is an opt-in deal. - Someone built a [Lethal Company Buttplug Mod](https://thunderstore.io/c/lethal-company/p/LethalPlugging/LethalVibrations/) if you're one of those cool kids playing the current cool kid game. - Construction starts on my flooded work area tomorrow, hoping to be back in soon! That's it for now. Until next time, keep Buttpluggin'! - qdot --- ## Does qDot Even Exist Anymore? (2024-02-12 Edition) Sorta? # Buttplug Things have been pretty quiet on the Buttplug/Intiface front lately. The good news is, reconstruction of my workspace is done! The not so good news is, moving back in is taking forever and life in general has gotten in the way of me having development time, so everything is a bit stalled right now. Next big goal remains getting the new configuration system in then building on top of that for things like device simulators, user specified devices, etc, just need to get time to get the last bit of it over the line. # Everything Else - [Intiface works on the Apple Vision Pro](https://www.youtube.com/watch?v=tLc3d2MD_0g&feature=youtu.be)! But please do not take this as a recommendation to actually buy the thing, no one has any clue what to do with it yet, me included. Yup, that's pretty much it for now, but I figured I'd at least show some signs of life. Until next time, Keep Buttpluggin'! - qdot --- ## What's qDot Up To This Week? (2024-03-11 Edition) Simplifying! ## Buttplug There's been one major holdup on Buttplug that's been stalling everything for months. The system we use to store info about all of the devices we support is... getting a bit unwieldy. I think we're creeping up on support for over 500 different devices now, and most of that info is all in one gigantic JSON file. On top of that, we now have "user device" configurations, which are specific to devices that users connect, so they can do things like change device names shown in UI, persist information between connections, etc... This is just another JSON file, but it's even more of a mess because, unlike the first file I mentioned, this one is edited by users and intiface central, but needs to map back to the big JSON file. This gets extra complicated. A solution I came up with mid last year was extremely stereotypical for being a developer: Let's shove it all in a DB! sqlite to be specific. I've been poking at that project on and off since April 2023. As of January 2024, it was looking pretty good in terms of access, but there's a ton of unanswered questions like - How do we update user DBs when we add new devices? - How do we handle easy debugging when a user has to ship us their DB? - Will this break WASM? None of these were problems when we were just using JSON files. Earlier this week I was discussing this issue with[ someone doing some really neat work on using buttplug + mods as a vtube avatar event system](https://twitter.com/renpona/status/1762685027064664108), and I went back to re-evaluate the work. Turns out, we can probably keep the JSON, we just need to change now we manipulate it. That'll also save us from the problems listed above. For those nerdy and curious, here's the issue with my design notes: [https://github.com/buttplugio/buttplug/issues/616](https://github.com/buttplugio/buttplug/issues/616)  So, that's a year of work out the window. Which is fine. That's not really the first time that's happened with Buttplug, and I use this project as a way to learn things, so it's been a nice way to experiment with sqlite. Really, I just want this done. ## Intiface Central For Intiface Central, I'm mainly try to get the new version with the Repeater Feature and possibly auto-updating capabilities out. Repeater is done, auto-updater should be done this week, the last thing to do after that is updating documentation as the program is already complex and the introduction of *modes* (which can change what Central does when you hit the big play button) will make it *complex*. I'm also hoping to finally get patreon/github contributors into the About dialog! As with youtube, this is **OPT-IN**, so you will need to respond to the message I send about this! After this, it looks like the WebRTC library I've had my eye on has finally implemented the features I was waiting for, so we might start looking at remote interconnect for Central! Not quite sure how this is going to look yet but it'll make for some fun experiments. ## Everything Else - I was on a podcast/vtubercast thing![ You can watch it on youtube.](https://www.youtube.com/watch?v=HZoad7S55tU)  That's it for now. Until next time, Keep Buttpluggin'! - qdot --- ## What's qDot Up To This Week? (2024-03-25 Edition) I think I'm gonna be recovering from GDC for at least twice as long as I was there... # Intiface Central Intiface Central v2.5.6 is out as of about 20 minutes ago! This has mostly been blocked on me trying to get documentation done for the new "Repeater" mode, which is really just a simple websocket proxy for doing things like using websites on desktop while controlling toys via Intiface Central on a phone. Usually this would be shot down by mixed content issues (most websites are https but can access http locally, but phone aren't local), and we're starting to see more users trying Central on phones, so this seemed like a good stop gap while we work toward WebRTC for direct P2P. There's also a bunch of device integration and fixes in Buttplug, including for Svakom, Satisfyer, and Motorbunny products that we've been getting a lot of complaints about. Finally: everyone who got back to me that donates at the $5 or higher level, your names are now in the about/help screen! :D Next up in Intiface Central: - Possibly a roadmap on github? I'm trying to get things more organized - Fixing issues with adding/removing user devices, as this is becoming very popular very quickly, even while being undocumented. - Simulated devices needs to happen ASAP. - More documentation! And possibly a website overhaul! # Buttplug and Btleplug Buttplug will require some changes to accommodate the new IC features mentioned above, but more important will be possibly patching a *huge* problem in the Android implementation of our bluetooth support. I've finally managed to get a crash log from someone with a phone that's having problems with Android IC, so I'm hoping to make progress on fixing that soon (we see this crash 100s of times a month and it is actively blocking android users). Otherwise, I would very much like to get back to the next version of the message spec in Buttplug. This is holding up a lot of fun features in relation to sensors (i.e. being able to play games with your bluetooth kegel hardware, or possibly even [erection sensing hardware](https://github.com/buttplugio/buttplug/pull/617). # Everything Else - GDC was great! Met lots of cool people, may have some collaborations coming out of it! We'll see! - There's some really exciting work happening with buttplugio being used as a vtube avatar event engine! [Check out this social media post for more info.](https://twitter.com/renpona/status/1771621312823255500) - I think I still owe a ton of people stickers. I will be messaging about that soon. That's it for this week. Until next week, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2024-04-22 Edition) Starting to think I've built a complicated platform... # Buttplug Over the past 6 weeks I've been reworking the system we use to store device information in Buttplug. The first major phase of that project is mostly done in Buttplug itself. We have a new format for our base device configurations, and the way we load/store specific user device information has been overhauled. All of this work will make things like "setting speed/movement limits on devices" and "adding DIY devices" and "adding simulated devices" far easier that it would've been with the old system. In fact, config was most of what was blocking all of these from happening, because the original system was designed just to bring in base device info, not actually be customized. Anyways, I'm now getting all of this wired up through Engine and Central, which I suspect will still take a while longer. I may also start releasing beta versions for people to test, which I'll post about here if/when they happen. # Intiface Central New version of Intiface Central is out! This should fix the issues that've plagued the Lovense Solace since January, as well as adds support for a ton of JoyHub devices (as well as Kiiroo and Lioness). That's about it for the IC update, really. I've been so busy on the lower levels that I didn't have much time to change anything in the UI. # Everything Else - I'm currently working on updates to our Apps/Games list, worth checking it out if you haven't in a while! [https://awesome.buttplug.io](https://awesome.buttplug.io) That's it for this week. Until next time, Keep Buttpluggin'! - qdot --- ## What's qDot Up To This Week? (2024-05-06 Edition) Short weekly update 'cause I'm working on stuff, but: DEVICE SPEED LIMITING IS A THING NOW! Finally got the config system into a place where device speed and movement range can be set! It works! I'm hoping to release Intiface Central v2.7 this weekend, just got some cleanup and testing left to do. The UI is... not great and getting WAY too cluttered, but we'll live for now. --- ## Weird Dicked Bear Unboxing Vod After a *very* rough couple of weeks I've finally managed to get time to edit and post the Lurevibe Weird Dicked Bear unboxing stream I did a couple of weeks ago! It's available for free (no subscription and hopefully not even an account needed) on fansly. I'm currently putting together a youtube friendly version too, will announce seperately when that's live. --- ## What's qDot Up To This Week? (2024-06-24 Edition) Mostly trying to figure out what I should be up to. :| # Roadmap That's right, right now the only thing I'm trying to work on is some sort of fucking roadmap. I've got too many projects in various forms of flight right now: - btleplug (needs some android fixes) - buttplug (needs to move to spec v4) - intiface engine/central (needs TONS of UI updates) - media event router (i.e. the new GHR except way more abstract) - Misc: Half done AHK bindings, half done Nightmare Kart mod, mostly done Gwent mod, etc... - Trying to reboot my video properties 'cause I kinda miss it? Things have now gotten to the point where I'm gonna have to sit down and plan out what order to do things in, possibly start looking at what I can maybe farm out, and what I can kick way down the road. Due to a combination of Furality then other tempestuousness over the past month, very little has gotten done, so instead of just trying to embark on whatever I figure I'll try to plan. We'll see if that gets anywhere. That said, if you've read this far along and have anything you'd specifically like to see, let me know! You do give me money, after all, so I'm inclined to listen. But, yeah, that's pretty much it for right now. Until next time, keep buttpluggin'! - qDot --- ## Qdot On Projekt Melody Lewdcast At 6pm Ct 4pm Pt Today I'm doing Projekt Melody's Lewdcast today at 4pm! [https://twitch.tv/projektmelody](https://twitch.tv/projektmelody) --- ## What's qDot Up To Lately? (2024-08-12 Edition) Dropping the idea that I'm gonna be doing this weekly again any time soon... # Buttplug/Intiface Central Things have been fairly quiet lately, mostly because the rest of life has been keeping me really busy (will get to that in the Everything Else section). I'm still managing to get some work done though! The work in question is pretty low level. I'm setting up our internal system for the move to our new message spec. Buttplug Message Spec v4 fixes a bug in how we define and communicate the features of devices, which should make it easier to expand functionality in the future, as well as letting us start implementing devices with sensors (kegel, depth, etc). The goal right now is to ship a version of Intiface Central in the next couple of weeks that will have this work embedded in it but not really visible to the outside world. This will allow us to exercise the new code while we work on the actual message spec changes. I'm also hoping to wrap a few bug fixes for IC into that, as we've had days where our Sentry (crash logging service) event count goes into the 30-40k range (usually a single fairly innocuous error message firing very quickly in a loop. Thank fuck I get 5 million sentry events per month :| ). # Everything Else - I did a podcast thing with Projekt Melody last week and it was awesome! There's a VOD here: [https://www.twitch.tv/videos/2216819840](https://www.twitch.tv/videos/2216819840) - For some reason a couple of my articles have made it on HackerNews again, and are getting lots of positive responses. I'm hoping to start writing more soon. - Also getting a LOT of requests for updates to the Cult of the Lamb buttplug mod I made late last year, looking into the work that'll require now - I'm considering streaming! Maybe doing some architectural overviews of buttplug, showing the process I use while modding games, etc. Please let me know if you're interested in that kind of content! - I'm also thinking about doing a VRChat meetup! I have a [buttplug.io](https://buttplug.io) group in VRC now, will try to plan a couple of meetup times across timezones. Will post an event notification when I finally figure out when I want to do that. That's it for now. Until next time, keep Buttpluggin'! - qDot --- ## Buttplugio Is Now On Twitch In an effort to get over my procrastination about making more videos, I'm going to see if I can go the route of "streaming then cutting it down for video content for youtube then also clipping that into tiny bits for tiktok" because that is just how the game is apparently played these days. Not to mention, people seem to have all these "questions" about "how anything works" in Buttplug so this'll provide a forum for questions to happen in real time while I'm showing stuff off. Plan for the first few streams: - First stream will probably just be me testing things out and showing off how I'm going to work with Buttplug without actually showing sex toys on stream. This will be a demo of our websocket device manager system which a lot of people have asked about anyways. - After that, I plan on doing a stream where I add some functionality to the new Peglin mod ([https://thunderstore.io/c/peglin/p/nonpolynomial/Pegginglin/](https://thunderstore.io/c/peglin/p/nonpolynomial/Pegginglin/) ), as well as go over the basics of BepinEx - After that, probably just more streams about modding, maybe some library explanations, etc. For showing off anything actually involving toys, that'll still be over on Fansly, as the twitch rules for showing sex toys are VERY weird and abstract. You can only show toys in an "educational manner", meaning if I make any sort of joke that's not considered educational while showing a toy, I could be banned. However, getting viewers over on Twitch is far easier than getting people to sign up on Fansly, so I figure this is worth a shot. I'm still getting things set up right now but I'll try to give at least 24 hours notice here before streams are announced! --- ## New Youtube Video Testing Rump With My New Vtuber Av Ok well as usual I'm horrible about remembering to announce streams here, but I did an impromptu stream last night showing off Renpona's new RUMP tool! It uses [Buttplug.io](https://Buttplug.io) game mods for manipulating and triggering VTuber animations alongside or instead of toys! It's super neat. This video is a condensed version of the content, going over how the software works, showing installation and setup, and a quick test using my Peglin mod! --- ## What's qDot Up To This Week? (2024-09-09 Edition) Too much stuff! # Buttplug/Intiface Central Finally got a new version of buttplug-rs and Intiface Central released! This implements the beginnings of our new v4 message spec, though it's only visible internally in the library right now. I've shipped it as part of the current Intiface Central so we can get people testing it though. Which is why I had to quickly release an Intiface Central v2.6.2, because we found a huge bug in some of the new message translation code right after release. Oops. Anyways, now that Central/Buttplug are basically stable, work now turns to adding new messages to v4 and trying to get those stabilized via testing with some of our trusted developers. More on that as it happens! # Twitch In the mean time, I've also started a twitch channel! [https://twitch.tv/buttplugio](https://twitch.tv/buttplugio) I've been wanting to make more video content for a while, but just doing videos without feedback is kinda boring, so I'm seeing how well streaming then editing for youtube works. So far... well, I've got a lot to learn, heh. As mentioned, I will be trying to post when I stream, I just gotta come up with a schedule first, and that may take a bit. Please let me know if you've got topics you'd like to see on stream! I'll probably let people here vote on topics once I get a few streams under my belt. Current plans include: - Building OSR-2/SR-6 on stream - Tutorial on building basic mods for Unity games - GHR overview and explanation - Tutorial on the websocket device system - Building out device visualizers on stream since I can't really show real hardware # Everything Else - I built a Peglin mod! You can check it out here: [https://thunderstore.io/c/peglin/p/nonpolynomial/Pegginglin/](https://thunderstore.io/c/peglin/p/nonpolynomial/Pegginglin/) - Renpona made RUMP! It's a super neat vtuber av event system based on buttplugio! [https://renpona.itch.io/rumbling-universal-mayhem-plugin](https://renpona.itch.io/rumbling-universal-mayhem-plugin) That's it for now. Until next time, Keep Buttpluggin'! - qDot --- ## Lets Talk Tube Movers On Twitch 8pm Pt Tonight TUNE IN TO TWITCH AT 8PM PACIFIC TIME TONIGHT TO GET THE LOW DOWN ON THE LOVENSE SOLACE PRO. See how it stacks up as a Fox Movement Device against the Keon, handy, SSR-1, etc! This’ll be the first time I’ve tried actually showing hardware on twitch so let’s see if it’s my last stream! [https://twitch.tv/buttplugio](https://twitch.tv/buttplugio) --- ## Going Live To Reverse Engineer The Solace Pros Linearcmd Support Streaming me trying to reverse engineer a device! How poorly could it possbily go?! --- ## Going Live 3 30pm Pt Today 30 Min From Now To Continue Reverse Engineer Oh god if what I figured out is true I'm gonna have to turn on profanity warnings on my stream. --- ## Streaming More Lovense Solace Pro Reverse Engineering On Twitch Please god let this stream be the end of this stupid project. --- ## Live On Twitch Probably Not Doing Much Hardware Related This Time Just need to test my audio changes and build some new streaming screens. But feel free to come say hi, happy to answer Buttplug related questions while I work! --- ## Obs Visualizer For Buttplug Stream Streaming at 2pm today (30 minutes from now) to work on OBS Browser visualizers for Buttplug devices! Join us at qdotsFoxMovers on twitch! [https://twitch.tv/qdotsfoxmovers](https://twitch.tv/qdotsfoxmovers) --- ## Installing A Buttkicker On Twitch Just got my buttkicker bass rumbler, time to attach it to my chair! --- ## What's qDot Up To This Week? (2024-10-21 Edition) Unemployment! Unless you count my own company, too bad that doesn't pay very well. # Life So yeah, the startup where I worked as a dayjob disappeared 2 weeks ago. Like, literally just poofed out of existence due to lack of money. It sucks, but such is life in the startup game. Thanks to everyone who donates to the project, as, well, now it *really* matters since it's my only income. Good news is, there seems to be a lot of opportunities out there for engineers at my level right now. Bad news is, finding them is gonna take a while and some work, so I have no clue what my schedule look like for the foreseeable future. I'm going to hopefully spend more time work on Buttplug, Intiface, the twitch streams, etc while I can, because honestly I like having the time to do so. Just wish it wasn't quite so abrupt. # Buttplug and Intiface The newest release of Intiface Central has been out for a little over a week now, and seems to be working pretty well. I got the Solace Pro linear movement code in, which has made many people happy (or at least, I'm guessing they're happy, they're at least not yelling at me anymore). I'm honestly not sure what's up next for Buttplug and Intiface. This isn't to say that there isn't a ton to do, as I very badly need to get the v4 spec scoped and done (the work is a good bit done as is, a lot of it shipped in the past couple of Intiface versions), Intiface UI is a mess that could use cleanup, etc. I just need to sit down and roadmap a few things to figure out what comes next. Outside of that, I also very much need to work on documentation for buttplug. I'm getting more and more interest from developers, who are then running headlong into a wall when they realize there isn't a lot of info about the different command messages and what you can do with them. I think a couple of days spent writing in-depth docs for ScalarCmd/LinearCmd could make a pretty big difference.  # Everything Else - Twitch Streaming was going great until that whole unemployment thing! I was getting in 2-3 streams a week, though still hadn't really been able to get a schedule going yet. Then a combo of company disappear and going to BLFC completely blew my schedule. I've just finished up a new streaming related Buttplug project that I'm pretty excited about and will be showing later this week, most likely Wednesday afternoon. Once I get that planned, I'll post an event notification here and on social media. - In addition to the aforementioned documentation, I'm gonna see about getting more blog posts done. I've got a lot of writing I'd been meaning to do about Buttplug architecture, streaming as a warmup for presenting info on the project, etc... That's it for now. Until next time, Keep Buttpluggin'! - qDot --- ## Live On Twitch Soldering Together Some Haptics Putting together tundra tracker haptics on twitch, in order to get back into the swing of streaming! --- ## Streaming More Haptics Building On Twitch Finishing out building my tracker haptics! --- ## Streaming Balatrobuzz The New Vibrator Mod For Balatro Mod is at [https://github.com/a-e-m/BalatroBuzz/](https://github.com/a-e-m/BalatroBuzz/) I'm showing setup and usage on Twitch now! (I swear I'll post a project weekly update soon) --- ## Qdot On Techovertea Podcast Youtube I'm on Brodie Robertson's TechOverTea Podcast/Youtube this week! [https://www.youtube.com/watch?v=Lq-k6abTucY](https://www.youtube.com/watch?v=Lq-k6abTucY) --- ## Does qDot Even Exist Anymore? (2025-02-17 Edition) Sorta. # Life For those not aware, I unexpectedly lost my last job in October 2024. Ok, it was actually kind of expected, we were a startup with iffy funding prospects. I just didn't expect it to collapse as fast as it did. Last time I wrote one of these updates was about 2 weeks after that happened. I was luckily able to move into a new position at an even smaller startup in December. That's been going well, but due to the hectic nature of being at a tiny, under-resourced company, I haven't had time for... much of anything other than work, really. Hence the lack of updates outside of random twitch streams and media appearances. There's not been much of anything to say on the code front. Things haven't really calmed down, but I'm now trying to regain at least some hobby time to make sure I don't burn out completely. # Patron Benefits Many of you have signed up since last time I did a patron survey, so I'll be sweeping through again to get an idea of who wants their name included in Intiface Central builds. If anyone else has extra benefits they'd like to see on this Patreon, please let me know. I'm 8 years into having this and still trying to figure out how to grow it. # Buttplug Buttplug did get a good bit of work done on it in the time between jobs. Version 4 of the spec and library continued to roll along, though it came to a screeching halt once the new job started. I've now gotta go back and figure out what was left to do, which is going to be difficult because it was mostly esoteric/challenging bugs and features. One of the things I may prioritize is getting a new website up. While the current site has... well I hate to say it's served us well, 'cause honestly it's mostly years out of date at this point. The plan now is to just have a simple front page to our docs site ([https://docs.buttplug.io](https://docs.buttplug.io)) that outlines the library, and possibly a better formatted version of our awesome list ([https://awesome.buttplug.io](https://awesome.buttplug.io)). May also add a blog. Dunno. # Intiface Central Intiface Central is basically stagnant right now. Any updates are mostly around device additions or bug fixes, but it's hard to tell when I'm going to get time to do UX work or add more features. Luckily no one is really asking for that. At some point, I'm really hoping to add some small utilities to Central, like a REST API for device control, desktop audio reactivity, maybe a very simple funscript playback system, etc. Nothing fancy, just simple utilities people keep asking for, that can be used on both desktop and mobile. These are all things that have been implemented in one way or another outside Intiface, and I really don't want to step on the community's feet, but for both the REST API and audio following, none of the utilities stay maintained for long and there's confusion about what to use. We'll see if implementing that in a central place fixes it or just makes things worse. # Everything Else Despite my lack of activity, people are still writing Buttplug mods and apps, which is great. The BalatroBuzz plugin got a decent amount of attention, and we've had other announcements happening in the discord and on social media lately. Wish I had more concrete things to announce, but right now it's pretty much returning from basic survival mode. That's it for now. Until next time, keep buttpluggin'! - qDot --- ## Streaming As Part Of The Romchip Fundraiser Today At 3pm Pt 6pm Et I'll be on the ROMChip game histories journal fundraiser stream today at 3pm PT/6pm ET showing off one of my favorite games, Cubivore! --- ## What's Up With qDot? (2025-05-05 Edition) What once was a weekly newsletter is quickly turning bi-annual heh. # Intiface Central Well the good news is, I finally got a new version of Intiface Central out! Not a ton to say about it because I've had almost no time to work on new features, but it does integrate a bunch of device updates that've happened over the past 5 months. We're also in discussions about creating a "simple" mode for Intiface. This was requested by a user who then actually provided wireframes, which is way more than we normally get! If you're interested in checking out the direction is this going, see [https://github.com/intiface/intiface-central/issues/185](https://github.com/intiface/intiface-central/issues/185) # Buttplug I've started working on the neverending project that is Buttplug v4 again. I think I've shaved the new protocol down as much as possible, which should make life much easier on both Buttplug app devs and client devs for new/different languages. At this point, the work is mostly down to fixing backward compatibility (so all of our apps on the current protocols stay work), and making sure everything still functions. It's slow going, but it's getting there. # HTTP/REST Buttplug While the above work is happening, I'm also finally looking at simplifying buttplug down to a REST API. We've had complaints for years that the current system is too complex for a lot of developers, so I'm hoping a simple web API will open things up even more. This will be integrated into Intiface Central, and I'll post OpenAPI specifications here as they become available. # Everything Else - I'm still absorbing the life changes of the past 6 months, hence the slow development and lack of news. I'm not really sure what my development schedule is going to end up looking like, but I feel like I'm slowly making progress. - I spoke at NYU last month about the experience of developing Buttplug! I'll be doing a stream of the talk soon. - We've had lots of new additions to game mods and apps, including an MCP layer, as well as mods for R.E.P.O., Garfield Kart, and others. Everything is updated on [https://awesome.buttplug.io](https://awesome.buttplug.io) - We've gotten a lot of free members following here on patreon, so I'm opening this newsletter up to them in order to say Paid Subscriptions Are Appreciated! As the project is free I don't really get much income for it outside of Patreon and Affiliates, so every dollar is appreciated! That's it for now. Until next time I decide to write one of these things, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2025-06-16 Edition) Bringing about a world where buttplug doesn't suck to use... # Buttplug Holy shit, after 8 years of writing this stupid library I think I may have finally landed on a message format and API I don't hate, and that I hope others will similarly not hate. Buttplug didn't start with plan so much as just a problem: How to control a bunch of random shitty hardware? Coming up with a solution didn't happen through planning so much as just coding until something worked, calling that done, then throwing it out and seeing what the response was. As of Buttplug Spec v3, that's mostly been "eh it mostly does what it's suppose to but it isn't easy". Part of the reason Spec v4 is nearing 2.5 years in development is that I wanted to actually plan, figure out formats, etc. Up until a couple of weeks ago I had something that was... ok and I could live with shipping but it didn't feel good, and it wasn't going to scale or extend well. Cue me driving to pick up ramen and having some sort of weird epiphany about turning data structures inside out. Thanks to this, buttplug is now much simpler. Devices are now defined in terms of features, which have groups outputs and inputs. Outputs can do things like vibrate, rotate, etc. Inputs are sensors. Features act as a container to bring context to things a device does. Of course, most devices are just like, a vibrator, so this isn't very interesting in that case. However, we are getting to the point where people are making DIY devices with motors that may have encoders and temp readings. All of those would be in the same feature since they all related to that specific motor. It also gives us a way to extend how we command outputs to do things, or new types of inputs we can take. On top of this, we now just expect one command from a client to be one command for a feature. The new Buttplug server takes care of throwing away repeated commands *as well as* *keeping timing so apps don't flood devices.* No more blaming app devs for sending too many messages, we regulate that ourselves now! This will probably all make more sense after I actually write up the new documentation for it, but I've been writing some sample programs with it and in general the library becomes so much easier to use and build clients for. Really looking forward to getting this out into the world now, mostly down to a few small tasks and changing some of the weirder protocols we support. If you're curious how work is going, the to-do list is at [https://github.com/buttplugio/buttplug/issues/565](https://github.com/buttplugio/buttplug/issues/565) . I think I probably still have a few weeks or so of work left before this is in any releasable form, and I may put out a beta of Intiface Central before doing a full release since this changes so much. # Everything Else That is actually it for this update. There's been so many huge structural overhauls to the library that getting to where I am now has taken most of the past month, but for once I actually feel like I'm putting out *useful* software, versus software people have to use because it's the only thing that does what it does. We'll just have to see if that holds up when it's out. Until next time, keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2025-06-23 Edition) Updates two weeks in a row! A christmas miracle! # Buttplug omfg I think I'm actually on the home stretch of v4. The current to-do list: [https://github.com/buttplugio/buttplug/issues/565](https://github.com/buttplugio/buttplug/issues/565) Honestly, we're mostly to updating documentation and client libraries, and a little bit of internal cleanup. I expect documentation may take a few weeks, but I'm planning to release beta version of engine/central while that's happening. Goal right now is to minimize any more major changes going into the library. This past weekend saw me rip out Raw messages altogether (a development feature that got used 2-3 times in the past 7 years but contributed almost 2k lines of code to the library due to all of the special casing it required) and continue trying to simplify things, but I think I'm mostly done now. At least I hope I am. # Intiface Not a lot has been happening on the Intiface front as I've been so busy with the base library, but plan is still to concentrate on Central once the new spec and library versions are done. I'll probably release Intiface v3 with the same UI/features at Intiface v2.x, then start slowly upgrading UI/UX and adding features through the v3 line, with v4 being a huge UI overhaul to make things simpler up front (as I keep hearing that Central provides way too many features to people who really want to do 1-2 things). # Everything Else That's pretty much it for now actually. Thanks to the surprising amount of new patrons in the past week! Until next time (maybe... next week even?!), keep buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2025-07-07 Edition) Edging ever closer to the v4 release... # Buttplug Buttplug Spec v4 and library v10 is... mostly feature complete! I think! Maybe! I keep adding stuff and I really need to stop it! For real though, great progress is being made and I think I'm now down to hammering out specific message details and starting to rework client libraries for other languages. I spent the July 4th weekend finishing up some bugs and rebuilding the message spec, which is available at [https://beta.docs.buttplug.io/docs/spec](https://beta.docs.buttplug.io/docs/spec) You will probably notice that it is much, much simpler than prior specs, which is the point. I wanted to remove a lot of complexity while giving us room to grow more easily in the future, and I think I've achieved that. If you're curious about what's left, the tracking bug is being kept up to date: [https://github.com/buttplugio/buttplug/issues/565](https://github.com/buttplugio/buttplug/issues/565) I'd like to get the Buttplug v10/Intiface Central v3 release done before the end of July, but it kind of depends on how much I continue to change things, and documentation/testing I can get done. # Intiface Central Intiface Central is now building against the new spec, and seems to be working pretty well. I'm trying to figure out what prerelease builds will look like, but I'm hoping to have a build for people to try up soon. This will be an important step in making sure the new version is ready to release, since pretty much every part of the library code got touched at some point over the past 2-3 years of development. Probably the most interesting thing here outside of all of the underlying changes (which will make things hopefully more robust for users, but probably won't be noticable) is that I'm still hoping to release an HTTP REST API built into Central, for easy access to toy control. No more being required to use websockets! (Though I will still recommend that :| ) # Everything Else - A lot of people making Keyboard/Mouse pickup software now! We've got [VibeMapper](https://github.com/LivingTh1ng/VibeMapper), [Lewd Input Viewer](https://github.com/Namaztak/lewd_input_viewer/), and at least one other in the works! That's it for this week. Thanks to all of the new patreon/github/etc subscribers this past couple of weeks, the funding means a lot, especially as my affiliates fall apart due to me being so busy with coding I forget to run ads. Until next time, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2025-07-28 Edition) Exciting new features! # Buttplug Work continues on trying to get the next version of Buttplug out to the world! Work is split between two areas of focus right now - Documentation and building things with the API to make sure it's sane - Documentation can be found at [https://beta.docs.buttplug.io](https://beta.docs.buttplug.io). Currently the new spec is redone, as is the dev guide up to the "how to use the API" portion. For anyone that wants to help with the project, letting me know if the documentation makes sense is a huge help! - For building things, I'm implementing a native HTTP/REST server! This'll ship in Intiface Engine and most likely Intiface Central, to make it easier to build Buttplug apps quickly without having to go through websockets (json parsing will be optional in some cases too). - Getting extra features due to things I find in the API builds too, as I figure out things that might be handy. For instance, we've now got the ability to reverse the min/max points of position-based stroking/thrusting devices, as well as disabling features of a toy. - [Fixing issues with devices I broke while converting protocols.](https://github.com/buttplugio/buttplug/issues/765) Both of these initiatives are going well, if a bit slowly as I have to stop to fix things, do my dayjob, etc... What was a hope in getting this shipped by the end of July is now end of August, but I'd rather not rush it. That said... # Intiface Central Just because I don't have a full release done yet doesn't mean I don't want people trying things! I'm hoping to start posting pre-release alpha builds of Intiface Central v3 in the near future. I still need to add some extra UI to work with our new features, but once that's done I'll throw a desktop (and possibly sideloadable APK?) on our github and will post here about it. Unfortunately I think we're going to limp into Intiface Central v3 with the current UI mostly intact. I'm hoping to spend the rest of the year concentrating on updating that and adding features once this project is done. # Everything Else - Someone built [quake3 buttplug](https://github.com/er2off/ioq3-buttplug) - Getting multiple projects working on the "keypress-to-buttplug" dream: [VibeMapper](https://github.com/LivingTh1ng/VibeMapper), [Buttplug_AHK](https://github.com/Cramonty/Buttplug_AHK) That's in for now. Until next update, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2025-09-01 Edition) Maybe I'll win the powerball so I can work on this fulltime... # Buttplug So much for doing a release candidate of the new version of Buttplug in August! Life got in the way and I wasn't really able to touch the project for the better part of the month. That said, got some time in this weekend to finish up the very boring but very needed Configuration Separation project. Basically, how we stored config was too intertwined with how we work with data in the system, and it ended up being a bit of a pulling apart a grilled cheese sandwich situation. Good news is that the feature is now complete, and I'm mostly working on getting bugs and tests fixed up. After this, I'm hoping to sweep through and update documentation/APIs once again for the changes that brings in, then actually get to that release candidate. There's still a chance we'll ship the new REST API as part of the RC too! # Intiface Central Alongside the Buttplug updates, we'll be doing one last release of Intiface Central v2, in order to accommodate some device updates (including the Kiiroo Keon WiFi, for those of you that've been asking about it). I'm hoping to also get a "use beta version" option in this build so we can have people auto-update to RC's of Intiface Central when those are ready. # Everything Else - We're still seeing a steady stream of new game mods in with the current hardware, check out [https://awesome.buttplug.io](https://awesome.buttplug.io) to see what's new! - Alongside all of this, a whole bunch of new VR Hardware just landed here, so I may be doing a stream or video on all of that soon. Not particularly buttplug related but there's some overlap in interests. :) Hopefully a more productive month this upcoming month. Until next time, Keep Buttpluggin'! - qDot --- ## Buttplug V10b2 And Intiface Central V3b2 Released The time has come! Or, well, I finally got sick of saying "one more thing then I'll release" and just decided to fucking release everything, lol. For the past 3 or so years, y'all have been listening to me ramble about the next version of the Buttplug Spec, how long it's been in development, etc... I honestly wasn't sure it was gonna make it out this year, but over the past couple of weeks things have come together enough that I felt ok starting beta releases, so here we are. # Buttplug The buttplug changelog is pretty massive: - v4 Spec implementation! A simplified spec, with expanded capabilities and extra future-proofing (I hope) - Rebuilt our backward compatibility for older specs - Split repo in many different crates, as we rarely touch like 80% of the code - Folded Intiface Engine into the main Buttplug repo Everything is now on the main branch at [https://github.com/buttplugio/buttplug](https://github.com/buttplugio/buttplug) # Intiface Central Intiface Central looks almost exactly the same, but has Buttplug v10 under it now! There's also been quite a few bugfixes, mostly for quality of life issues. And then there's the built-in REST API! This will *hopefully* make it easier to make quick one-off apps and test ideas without having to use a full client implementation. Pre-releases are available at [https://github.com/intiface/intiface-central/releases](https://github.com/intiface/intiface-central/releases) - v3b2 is up already, though the builds are not signed and it's just desktop for now. v3 builds also have a "Use pre-release" option so you can track beta updates. # What's Missing At this point, I'm pretty sure we're feature complete on the Buttplug side. I'll be updating and changing Intiface Central while we test both of these though. - Documentation. There is **almost no accurate documentation currently**. I'd updated the spec and some of the dev docs at some point in the past, but I need to sweep through and update everything again. Due to this, I'm not really announcing this release much yet. - Bug fixes. We're aware of quite a few devices that are broken, mostly devices that have commands that can cancel other commands (joyhub devices, lovense devices with rotation, etc)... We've done quite a lot of testing but still have a lot to go. - Client implementations. Rust has an implementation, but so far none of the other languages are implemented. This is considered part of testing. # What's Next The plans as they currently are: - Documentation, documentation, documentation - Continue bugfixing as we find things, as well as filling out holes in implementations. - Move the Buttplug and Intiface websites to be built on docusaurus - They've been static pages since 2017, the plan now is to integrate the base pages into the documentation sites so everything is in the same place. - Start work on JS and C# implementations - Maybe do some development streams? The main thing that could get in the way of this is my dayjob, the thing that's mostly been the reason for the slowdown over the past year. Not necessarily a bad thing, because I love the work and it's a great place, but it's definitely keeping me busy. There's a lot more motivation to work now that I've hit a big milestone on this though. 3 years was way too long to run this branch, but it gave me a chance to actually do things as right as possible. I hope. As always, for those with subscriptions, thank you so much for your continued support and dealing with the long quiet spells. I really appreciate it. Anyways, that's it for now. Until next time, Keep Buttpluggin'! - qDot --- ## What's qDot Up To This Week? (2025-12-01 Edition) omfg buttplug spec v4 might be out before the end of the year # Buttplug Currently working through implementing new versions of the Buttplug client! So far I've gotten Rust and Typescript done, next up is C#, then Python. After that, I'll be updating all of the examples in the documentation, at which point we'll be pretty close to done. We've still got a lot of random device bugs floating around in the latest version, but we may just release with some of those as they're on devices almost no one actually has. For those that've picked up the Lovense Spinel, we do have support for it in the library now, and I'll be doing another beta release of Central soon to pick that up. # Intiface Central Mostly doing bugfixing in Central right now. Got limit UI for linear devices working again, otherwise holding off on adding anything new because I'm mostly interested in just getting v3 out with the new spec under it, *then* I'll get to work on Central updates. # Buttplug Website I haven't updated the [buttplug.io](https://buttplug.io) website since... 2018? 2019? Somewhere around there. It's super stale now. Planning to just fold the front page into our documentation site, since that's kind of the important part anyways. You can see the beginnings of that at [https://beta.docs.buttplug.io](https://beta.docs.buttplug.io) I'll also be bringing up a blog over there to do longer form posting about the library. # Everything Else - [We got another balatro mod!](https://github.com/Fraggenard/Buttlatro) - [And a war thunder mod!](https://github.com/TheDR-lul/Tailgunner/) Anyways, that's it for now. Starting to get a bit more time to work on things so I'm pretty hopeful I can get v4 out in 2025, then spend 2026 actually creating new stuff! Until next time, keep Buttpluggin'! - qDot --- ## Merry Christmas, I got you a new Buttplug.io website! Because why spend the holiday with friends and family when you can spend it debugging docusaurus. The new [https://buttplug.io](https://buttplug.io) website is live, and for the first time in years I don't dread updating it now. There's a blog, as well as the documentation for both the current version of the spec (v3) and the upcoming versions (v4, hopefully out by... next Wednesday. :| ). Please let me know what you think! --- ## Intiface Central v3 Beta 4 Live Small update that still means a breaking change! But now there's a macOS build too! https://github.com/intiface/intiface-central/releases/tag/v3.0.0-beta4 Still planning on doing a release on 12/31! --- ## What's qDot Up To This Week? (2026-01-19 Edition) So much for that end of the year buttplug v4 release # Buttplug Missed the deadline on getting Buttplug v4 out by end of 2025 because I started working on testing Input messages annnnnd it turns out I just completely forgot to implement like half the system. Christmas break was mostly spent on that, porting the typescript and dart libraries into the v4 spec, and various refinements within the library. By the end of it things were feeling more solid but not quite there, hence more betas. Since then, I've done even more work on reducing our message footprint (now there's just one stop message instead of 2!) and cleaning up the insides of the library. I've also started a bit of fun work [trying to integrate a small scripting language into commands](https://github.com/buttplugio/buttplug/issues/810), which is something people have been asking about for just about forever. Check out the linked issue if you'd like to see where that's going or have some input. This will not be shipping in v4 (most likely v4.1, because yes we can minor version specs now), but it should be neat! # Intiface Central Not much to say on Intiface Central, outside of that it's now the first testing ground of the v4 spec! Whenever you use the device panel in the beta, you're now sending v4 messages! It probably looks about the same! Most IC updates will be coming after I get Buttplug v10 and Intiface Central v3 out, but at that point I'll have a lot of room to make smaller updates. # Everything Else Still honestly not sure when everything is going to get released as it mostly revolves around my otherwise very busy schedule now, but we're real close. Here's hoping it happens soon! Until next time, keep Buttpluggin'! - qDot --- ## Buttplug v10/Intiface Central v3 Released! It happened! It finally happened! 3.5 years of work, now released! https://github.com/intiface/intiface-central/releases/tag/v3.0.0%2B36 Intiface Central v3 and Buttplug Rust v10 are out! This also includes new versions of Buttplug C#, Python (using the old "buttplug" pypi project!), Javascript/Typescript, and Dart! There's a LOT that's come out today, which I'm going to be spending the rest of the week writing a blogpost or 3 about. I'll post about those when they're ready. Please let me know (via one of the links on the bottom of this page) if you have any issues. Looking forward to implementing new stuff soon finally! --- ## There will be no official Buttplug related memecoin Was wondering when this particular bit of stupidity would come for me, and here we are. I would just like to state that there is not, and will never be, a memecoin related to Buttplug, Intiface®, or any subsidary projects that is "official" or in any way endorsed by me or anyone involved with this project. Working in open source is so much fun. --- ## Intiface Game Haptics Router v20 Released! [Intiface Game Haptics Router v20 is live!](https://github.com/intiface/intiface-game-haptics-router/releases/tag/v20) First update in 18 months! Hopefully the first one that doesn't register as a virus/malware in... several years! I removed process finding code that opened live processes and list their library bindings. Windows hated that lol. --- ## Intiface Central v3.0.3 Released It's that time again. We're releasing Intiface Central 3.0.3. This is an exciting release with a lot of bug fixes. Not so much in the way a new features this time around, but this'll give us a good basis to build out on, or at least hopefully stop people from yelling at us so much. [You can get it via the Intiface Central front page.](https://intiface.com) ## Android Changes There’s been a lot of updates to the android system in this release, including the Bluetooth system as well as handling keepalives a little bit better. On the Bluetooth side, there were just a lot of errors we weren’t throwing, which would cause users to crash when starting and stopping Bluetooth scan. These have been by far the most common crashes we see in our crash logging system for all platforms, since the mobile app was first released. With the changes made this version, we hope these bugs have been resolved, or at least that we'll have a better chance of figuring out how to resolve them versus just falling over. This includes building a full hardware platform for testing our bluetooth library, which has already surfaced several bugs we didn't even know we had. ![Android vitals showing wakelocks at 21% when bad behavior threshhold is 5%. This is bad and we should feel bad.](./wakelocks.png) We’ve been getting a lot of complaints from both users and the Google play store that the app keeps the phone alive for too long and therefore drains power. The only time this really needs to happen is with certain devices that require updates every few seconds to stay on (brands like Satisfyer, VibCrafter, Mysteryvibe, etc). We've done some work to make sure we only stay on when needed, which should hopefully reduce power draw on phones. ## Deprecating Lovense Connect and the Lovense Dongle The next Intiface Central will have *less* features (I can hear every other software dev out there sighing happily). We are deprecating support for the Lovense USB Dongle, as well as the Lovense Connect Service. Support still exists in v3.0.3 of Intiface Central, but will be removed in v3.1.0 (the next non-bug-fix version). Both of these services were added when Buttplug and Intiface were in their early stages, and we did not have a mobile application. That’s no longer the case, so while they're still used (mostly due to habit and our lack of documentation and guidance), these services really just produced bugs more than anything. We’ve gotten in tons of reports that Lovense Connect no longer works post Intiface v3. We're not sure whether we broke it or Lovense changed it, and frankly, we don’t care. Neither Connect nor the dongle were documented by Lovense or meant for use by 3rd parties, we reverse engineered them as best we could with the time/resources we had. Maintenance is a nightmare, and we don’t want to do it anymore. We’re replacing Lovense Connect with using the Interface Central mobile app in a couple of different ways, with [starting documentation already available in the Intiface Docs](https://intiface.com/docs/intiface-central/brands/lovense). ![I really cannot emphasize how much the Lovense Dongle sucks.](./dongle.png) For the Lovense Dongle, the recommendation to is to use a regular Bluetooth dongle. Windows 10 and 11 both have decent Bluetooth capabilities at this point, and a regular bluetooth dongle is far faster and more reliable than the Lovense dongle. [Guidance on which Bluetooth Dongles we recommend are available in the Intiface Documentation](https://intiface.com/docs/intiface-central/hardware/bluetooth). We're happy to help users through this transition where we can through our [various support channels](https://buttplug.io/docs/dev-guide/intro/getting-help). ## TCode Fixes and Device Additions We're aware that users of TCode devices have had issues with the device not registering with video sync services lately. This was due to a device misconfiguration in a prior version of Intiface Central, which has been fixed in this version of Intiface. **IMPORTANT NOTE**: To fix this properly, you may need to hit "forget device" in the Intiface Central devices tab and readd the device using the serial port dialog. For anyone using TCode devices in real time situations (VRChat + OSCGB, etc), please get in touch with us [via our support channels](https://buttplug.io/docs/dev-guide/intro/getting-help), as we're looking at how to support those users better. Finally, we’ve got some device additions. We’ve added support for [HoneyPlayBox devices](https://honeyplaybox.buttplug.io) as well as more Joyhub devices. WeVibe devices now have battery reading support. ## What's Next With what is hopefully a more stable base to work on top of, what's next? _**JFC. THE DEVICE PANEL. IT'S SO BAD.**_ The Device Panel of Intiface Central is possibly the most important part of the UI, but also the least worked on because it's a complicated mess. We're looking forward to scrubbing and rebuilding it, with some new features: - Support for device property changes while clients are connected or the server is on, so you can tune limits while using things instead of having to constantly stop and restart - Ability to see the current state of a device, such as how fast it's vibrating or where in a stroking event it is (I cannot believe we don't have this yet) - Simulated devices so poor devs don't have to put a toy on their desk every time they want to do something. No ETA on when this will be out, but it’s our hope that this is going to be in the next minor version update. As always if you have any issues with the software, please do not hesitate to reach out via our [support channels](https://buttplug.io/docs/dev-guide/intro/getting-help). Until next time, keep buttpluggin'!