Skip to main content

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), 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. 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), 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 created an async android runtime and JNI bindings to the bluetooth portions of the android API. This allowed 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. This binding was originally built for the mobile apps using buttplug, but came in handy for desktop too.