buttplug 3.2.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/.eslintrc.js +25 -25
  2. package/.jscsrc +2 -2
  3. package/.jshintrc +5 -5
  4. package/.prettierrc.json +3 -3
  5. package/.yarnrc.yml +5 -1
  6. package/CHANGELOG.md +577 -571
  7. package/LICENSE +27 -27
  8. package/README.md +97 -97
  9. package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js +6 -9
  10. package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js.map +1 -1
  11. package/dist/main/src/client/{Client.d.ts → ButtplugClient.d.ts} +3 -4
  12. package/dist/main/src/client/ButtplugClient.js +227 -0
  13. package/dist/main/src/client/ButtplugClient.js.map +1 -0
  14. package/dist/main/src/client/ButtplugClientConnectorException.js +17 -7
  15. package/dist/main/src/client/ButtplugClientConnectorException.js.map +1 -1
  16. package/dist/main/src/client/ButtplugClientDevice.d.ts +13 -28
  17. package/dist/main/src/client/ButtplugClientDevice.js +105 -247
  18. package/dist/main/src/client/ButtplugClientDevice.js.map +1 -1
  19. package/dist/main/src/client/ButtplugClientDeviceCommand.d.ts +42 -0
  20. package/dist/main/src/client/ButtplugClientDeviceCommand.js +105 -0
  21. package/dist/main/src/client/ButtplugClientDeviceCommand.js.map +1 -0
  22. package/dist/main/src/client/ButtplugClientDeviceFeature.d.ts +18 -0
  23. package/dist/main/src/client/ButtplugClientDeviceFeature.js +166 -0
  24. package/dist/main/src/client/ButtplugClientDeviceFeature.js.map +1 -0
  25. package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -8
  26. package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js +1 -4
  27. package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js.map +1 -1
  28. package/dist/main/src/core/Exceptions.js +27 -9
  29. package/dist/main/src/core/Exceptions.js.map +1 -1
  30. package/dist/main/src/core/Logging.js +12 -6
  31. package/dist/main/src/core/Logging.js.map +1 -1
  32. package/dist/main/src/core/Messages.d.ts +118 -228
  33. package/dist/main/src/core/Messages.js +51 -404
  34. package/dist/main/src/core/Messages.js.map +1 -1
  35. package/dist/main/src/index.d.ts +2 -2
  36. package/dist/main/src/index.js +4 -2
  37. package/dist/main/src/index.js.map +1 -1
  38. package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js +40 -52
  39. package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js.map +1 -1
  40. package/dist/main/src/utils/ButtplugMessageSorter.js +27 -15
  41. package/dist/main/src/utils/ButtplugMessageSorter.js.map +1 -1
  42. package/dist/main/src/utils/Utils.js +1 -2
  43. package/dist/main/src/utils/Utils.js.map +1 -1
  44. package/dist/web/buttplug.js +1 -38
  45. package/dist/web/buttplug.mjs +595 -1984
  46. package/dist/web/client/ButtplugBrowserWebsocketClientConnector.d.ts +0 -7
  47. package/dist/web/client/{Client.d.ts → ButtplugClient.d.ts} +3 -11
  48. package/dist/web/client/ButtplugClientConnectorException.d.ts +0 -7
  49. package/dist/web/client/ButtplugClientDevice.d.ts +14 -29
  50. package/dist/web/client/ButtplugClientDeviceCommand.d.ts +42 -0
  51. package/dist/web/client/ButtplugClientDeviceFeature.d.ts +18 -0
  52. package/dist/web/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -15
  53. package/dist/web/client/IButtplugClientConnector.d.ts +0 -7
  54. package/dist/web/core/Exceptions.d.ts +1 -1
  55. package/dist/web/core/Logging.d.ts +0 -7
  56. package/dist/web/core/Messages.d.ts +118 -227
  57. package/dist/web/index.d.ts +2 -2
  58. package/dist/web/utils/ButtplugBrowserWebsocketConnector.d.ts +0 -7
  59. package/examples/node/SYNC_MANIFEST.md +105 -0
  60. package/examples/node/application-example.ts +213 -0
  61. package/examples/node/async-example.ts +124 -0
  62. package/examples/node/connection-example.ts +76 -0
  63. package/examples/node/device-control-example.ts +131 -0
  64. package/examples/node/device-enumeration-example.ts +86 -0
  65. package/examples/node/device-info-example.ts +131 -0
  66. package/examples/node/errors-example.ts +166 -0
  67. package/examples/node/package-lock.json +281 -0
  68. package/examples/node/package.json +25 -0
  69. package/examples/node/remote-connector-example.ts +84 -0
  70. package/examples/node/tsconfig.json +14 -0
  71. package/examples/web/application-example.js +197 -0
  72. package/examples/web/async-example.js +90 -0
  73. package/examples/web/device-control-example.js +87 -0
  74. package/examples/web/device-enumeration-example.js +49 -0
  75. package/examples/web/device-info-example.js +100 -0
  76. package/examples/web/errors-example.js +110 -0
  77. package/examples/web/index.html +55 -0
  78. package/examples/web/logging.js +42 -0
  79. package/examples/web/ping-timeout-example.js +59 -0
  80. package/examples/web/remote-connector-example.js +68 -0
  81. package/node-test.js +24 -0
  82. package/node-test.ts +23 -5
  83. package/package.json +85 -87
  84. package/src/client/ButtplugBrowserWebsocketClientConnector.ts +25 -25
  85. package/src/client/ButtplugClient.ts +242 -0
  86. package/src/client/ButtplugClientConnectorException.ts +16 -16
  87. package/src/client/ButtplugClientDevice.ts +178 -401
  88. package/src/client/ButtplugClientDeviceCommand.ts +112 -0
  89. package/src/client/ButtplugClientDeviceFeature.ts +138 -0
  90. package/src/client/ButtplugNodeWebsocketClientConnector.ts +17 -17
  91. package/src/client/IButtplugClientConnector.ts +18 -18
  92. package/src/core/Exceptions.ts +107 -101
  93. package/src/core/Logging.ts +197 -197
  94. package/src/core/Messages.ts +209 -480
  95. package/src/core/index.d.ts +4 -4
  96. package/src/index.ts +21 -19
  97. package/src/utils/ButtplugBrowserWebsocketConnector.ts +89 -92
  98. package/src/utils/ButtplugMessageSorter.ts +66 -65
  99. package/src/utils/Utils.ts +3 -3
  100. package/tsconfig.json +22 -22
  101. package/tsfmt.json +14 -14
  102. package/tslint.json +27 -27
  103. package/typedocconfig.js +6 -6
  104. package/vite.config.ts +26 -26
  105. package/dist/main/src/client/Client.js +0 -242
  106. package/dist/main/src/client/Client.js.map +0 -1
  107. package/dist/main/src/core/MessageUtils.d.ts +0 -10
  108. package/dist/main/src/core/MessageUtils.js +0 -65
  109. package/dist/main/src/core/MessageUtils.js.map +0 -1
  110. package/dist/web/core/MessageUtils.d.ts +0 -10
  111. package/doc/.nojekyll +0 -1
  112. package/doc/assets/highlight.css +0 -22
  113. package/doc/assets/main.js +0 -58
  114. package/doc/assets/search.js +0 -1
  115. package/doc/assets/style.css +0 -1280
  116. package/doc/classes/ButtplugBrowserWebsocketClientConnector.html +0 -234
  117. package/doc/classes/ButtplugClient.html +0 -331
  118. package/doc/classes/ButtplugClientConnectorException.html +0 -216
  119. package/doc/classes/ButtplugClientDevice.html +0 -489
  120. package/doc/classes/ButtplugDeviceError.html +0 -218
  121. package/doc/classes/ButtplugDeviceMessage.html +0 -165
  122. package/doc/classes/ButtplugError.html +0 -220
  123. package/doc/classes/ButtplugInitError.html +0 -218
  124. package/doc/classes/ButtplugLogger.html +0 -288
  125. package/doc/classes/ButtplugMessage.html +0 -147
  126. package/doc/classes/ButtplugMessageError.html +0 -218
  127. package/doc/classes/ButtplugMessageSorter.html +0 -128
  128. package/doc/classes/ButtplugNodeWebsocketClientConnector.html +0 -239
  129. package/doc/classes/ButtplugPingError.html +0 -218
  130. package/doc/classes/ButtplugSystemMessage.html +0 -150
  131. package/doc/classes/ButtplugUnknownError.html +0 -218
  132. package/doc/classes/DeviceAdded.html +0 -186
  133. package/doc/classes/DeviceInfo.html +0 -114
  134. package/doc/classes/DeviceList.html +0 -160
  135. package/doc/classes/DeviceRemoved.html +0 -158
  136. package/doc/classes/Error.html +0 -179
  137. package/doc/classes/GenericDeviceMessageAttributes.html +0 -107
  138. package/doc/classes/GenericMessageSubcommand.html +0 -90
  139. package/doc/classes/LinearCmd.html +0 -187
  140. package/doc/classes/LogMessage.html +0 -134
  141. package/doc/classes/MessageAttributes.html +0 -160
  142. package/doc/classes/Ok.html +0 -151
  143. package/doc/classes/Ping.html +0 -151
  144. package/doc/classes/RawDeviceMessageAttributes.html +0 -86
  145. package/doc/classes/RawReadCmd.html +0 -188
  146. package/doc/classes/RawReading.html +0 -179
  147. package/doc/classes/RawSubscribeCmd.html +0 -170
  148. package/doc/classes/RawUnsubscribeCmd.html +0 -170
  149. package/doc/classes/RawWriteCmd.html +0 -188
  150. package/doc/classes/RequestDeviceList.html +0 -151
  151. package/doc/classes/RequestServerInfo.html +0 -169
  152. package/doc/classes/RotateCmd.html +0 -187
  153. package/doc/classes/RotateSubcommand.html +0 -108
  154. package/doc/classes/ScalarCmd.html +0 -170
  155. package/doc/classes/ScalarSubcommand.html +0 -108
  156. package/doc/classes/ScanningFinished.html +0 -146
  157. package/doc/classes/SensorDeviceMessageAttributes.html +0 -107
  158. package/doc/classes/SensorReadCmd.html +0 -179
  159. package/doc/classes/SensorReading.html +0 -188
  160. package/doc/classes/ServerInfo.html +0 -178
  161. package/doc/classes/StartScanning.html +0 -151
  162. package/doc/classes/StopAllDevices.html +0 -151
  163. package/doc/classes/StopDeviceCmd.html +0 -161
  164. package/doc/classes/StopScanning.html +0 -151
  165. package/doc/classes/VectorSubcommand.html +0 -108
  166. package/doc/enums/ActuatorType.html +0 -104
  167. package/doc/enums/ButtplugLogLevel.html +0 -97
  168. package/doc/enums/ErrorClass.html +0 -90
  169. package/doc/enums/SensorType.html +0 -90
  170. package/doc/functions/FromJSON.html +0 -113
  171. package/doc/index.html +0 -184
  172. package/doc/interfaces/IButtplugClientConnector.html +0 -137
  173. package/doc/modules.html +0 -176
  174. package/doc/variables/DEFAULT_MESSAGE_ID.html +0 -104
  175. package/doc/variables/MAX_ID.html +0 -104
  176. package/doc/variables/MESSAGE_SPEC_VERSION.html +0 -104
  177. package/doc/variables/SYSTEM_MESSAGE_ID.html +0 -104
  178. package/src/client/Client.ts +0 -276
  179. package/src/core/MessageUtils.ts +0 -48
@@ -0,0 +1,84 @@
1
+ // Buttplug TypeScript - Remote Connector Example
2
+ //
3
+ // This example demonstrates the explicit WebSocket connector setup.
4
+ // While you can create a connector inline, creating it explicitly
5
+ // gives you more control over the connection parameters.
6
+ //
7
+ // Prerequisites:
8
+ // 1. Install Intiface Central: https://intiface.com/central
9
+ // 2. Start the server in Intiface Central
10
+ // 3. Run: npx ts-node --esm remote-connector-example.ts
11
+
12
+ import {
13
+ ButtplugClient,
14
+ ButtplugNodeWebsocketClientConnector,
15
+ ButtplugBrowserWebsocketClientConnector,
16
+ } from 'buttplug';
17
+ import * as readline from 'readline';
18
+
19
+ async function waitForEnter(prompt: string): Promise<void> {
20
+ const rl = readline.createInterface({
21
+ input: process.stdin,
22
+ output: process.stdout,
23
+ });
24
+ return new Promise((resolve) => {
25
+ rl.question(prompt, () => {
26
+ rl.close();
27
+ resolve();
28
+ });
29
+ });
30
+ }
31
+
32
+ async function main(): Promise<void> {
33
+ // Method 1: Inline connector creation (most common)
34
+ // This is the simplest approach for most applications.
35
+ console.log('Method 1: Inline connector creation');
36
+ console.log(' const connector = new ButtplugNodeWebsocketClientConnector(url);');
37
+ console.log(' await client.connect(connector);');
38
+ console.log(' (Simple and direct)\n');
39
+
40
+ // Method 2: Explicit connector creation
41
+ // Use this when you need to reuse the connector or
42
+ // configure it before connecting.
43
+ console.log('Method 2: Explicit connector creation');
44
+ console.log(' const connector = new ButtplugNodeWebsocketClientConnector(url);');
45
+ console.log(' // ... configure connector if needed ...');
46
+ console.log(' await client.connect(connector);');
47
+ console.log(' (More control over connector lifecycle)\n');
48
+
49
+ // Note about environments:
50
+ // - Node.js: Use ButtplugNodeWebsocketClientConnector (uses 'ws' package)
51
+ // - Browser: Use ButtplugBrowserWebsocketClientConnector (uses native WebSocket)
52
+ console.log('Environment-specific connectors:');
53
+ console.log(' - Node.js: ButtplugNodeWebsocketClientConnector');
54
+ console.log(' - Browser: ButtplugBrowserWebsocketClientConnector\n');
55
+
56
+ // Let's actually connect using the explicit connector method
57
+ const client = new ButtplugClient('Remote Connector Example');
58
+ const connector = new ButtplugNodeWebsocketClientConnector(
59
+ 'ws://127.0.0.1:12345'
60
+ );
61
+
62
+ console.log('Connecting using explicit connector...');
63
+ try {
64
+ await client.connect(connector);
65
+ console.log('Connected successfully!');
66
+ console.log(` Connected: ${client.connected}`);
67
+
68
+ await waitForEnter('\nPress Enter to disconnect...');
69
+
70
+ await client.disconnect();
71
+ console.log('Disconnected.');
72
+ } catch (e) {
73
+ if (e instanceof Error) {
74
+ console.log(`Connection failed: ${e.message}`);
75
+ }
76
+ console.log(
77
+ '\nMake sure Intiface Central is running with the server started.'
78
+ );
79
+ }
80
+
81
+ await waitForEnter('\nPress Enter to exit...');
82
+ }
83
+
84
+ main().catch(console.error);
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "./dist",
10
+ "rootDir": "."
11
+ },
12
+ "include": ["*.ts"],
13
+ "exclude": ["node_modules", "dist"]
14
+ }
@@ -0,0 +1,197 @@
1
+ // Buttplug Web - Complete Application Example
2
+ //
3
+ // This is a complete, working example that demonstrates the full workflow
4
+ // of a Buttplug application in a browser. If you're new to Buttplug, start here!
5
+ //
6
+ // Prerequisites:
7
+ // 1. Install Intiface Central: https://intiface.com/central
8
+ // 2. Start the server in Intiface Central (click "Start Server")
9
+ // 3. Include Buttplug via CDN in your HTML:
10
+ // <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
11
+ // 4. Call runApplicationExample() from your page
12
+
13
+ async function runApplicationExample() {
14
+ console.log("===========================================");
15
+ console.log(" Buttplug Web Application Example");
16
+ console.log("===========================================\n");
17
+
18
+ // Step 1: Create a client
19
+ // The client name identifies your application to the server.
20
+ const client = new Buttplug.ButtplugClient("My Buttplug Application");
21
+
22
+ // Step 2: Set up event handlers
23
+ // Always do this BEFORE connecting to avoid missing events.
24
+ client.addListener("deviceadded", (device) => {
25
+ console.log(`[+] Device connected: ${device.name}`);
26
+ });
27
+
28
+ client.addListener("deviceremoved", (device) => {
29
+ console.log(`[-] Device disconnected: ${device.name}`);
30
+ });
31
+
32
+ client.addListener("disconnect", () => {
33
+ console.log("[!] Server connection lost!");
34
+ });
35
+
36
+ // Step 3: Connect to the server
37
+ console.log("Connecting to Intiface Central...");
38
+ try {
39
+ const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector(
40
+ "ws://127.0.0.1:12345"
41
+ );
42
+ await client.connect(connector);
43
+ } catch (e) {
44
+ if (e instanceof Buttplug.ButtplugClientConnectorException) {
45
+ alert(
46
+ "Could not connect to Intiface Central!\n\n" +
47
+ "Make sure Intiface Central is running and the server is started.\n" +
48
+ "Default address: ws://127.0.0.1:12345"
49
+ );
50
+ console.log("ERROR: Could not connect to Intiface Central!");
51
+ return;
52
+ }
53
+ throw e;
54
+ }
55
+ console.log("Connected!\n");
56
+
57
+ // Step 4: Scan for devices
58
+ console.log("Scanning for devices...");
59
+ console.log("Turn on your Bluetooth/USB devices now.\n");
60
+ await client.startScanning();
61
+
62
+ // Wait for devices (using alert/confirm for browser interaction)
63
+ alert("Scanning for devices...\n\nTurn on your devices, then click OK when ready.");
64
+ await client.stopScanning();
65
+
66
+ // Step 5: Check what devices we found
67
+ const devices = Array.from(client.devices.values());
68
+ if (devices.length === 0) {
69
+ alert(
70
+ "No devices found!\n\n" +
71
+ "Make sure your device is:\n" +
72
+ "- Turned on\n" +
73
+ "- In pairing/discoverable mode\n" +
74
+ "- Supported by Buttplug (check https://iostindex.com)"
75
+ );
76
+ console.log("No devices found.");
77
+ await client.disconnect();
78
+ return;
79
+ }
80
+
81
+ console.log(`\nFound ${devices.length} device(s):\n`);
82
+
83
+ // Step 6: Display device capabilities
84
+ for (const device of devices) {
85
+ console.log(` ${device.name}`);
86
+
87
+ // Check output capabilities
88
+ const outputs = [];
89
+ if (device.hasOutput(Buttplug.OutputType.Vibrate)) outputs.push("Vibrate");
90
+ if (device.hasOutput(Buttplug.OutputType.Rotate)) outputs.push("Rotate");
91
+ if (device.hasOutput(Buttplug.OutputType.Oscillate)) outputs.push("Oscillate");
92
+ if (device.hasOutput(Buttplug.OutputType.Position)) outputs.push("Position");
93
+ if (device.hasOutput(Buttplug.OutputType.Constrict)) outputs.push("Constrict");
94
+
95
+ if (outputs.length > 0) {
96
+ console.log(` Outputs: ${outputs.join(", ")}`);
97
+ }
98
+
99
+ // Check input capabilities
100
+ const inputs = [];
101
+ if (device.hasInput(Buttplug.InputType.Battery)) inputs.push("Battery");
102
+ if (device.hasInput(Buttplug.InputType.RSSI)) inputs.push("RSSI");
103
+
104
+ if (inputs.length > 0) {
105
+ console.log(` Inputs: ${inputs.join(", ")}`);
106
+ }
107
+ }
108
+
109
+ // Step 7: Interactive device control
110
+ console.log("\n=== Interactive Control ===");
111
+ console.log("Use the prompts to control devices.");
112
+
113
+ let running = true;
114
+ while (running) {
115
+ const input = prompt(
116
+ "Commands:\n" +
117
+ " v <0-100> - Vibrate all devices at percentage\n" +
118
+ " s - Stop all devices\n" +
119
+ " b - Read battery levels\n" +
120
+ " q - Quit\n\n" +
121
+ "Enter command:"
122
+ );
123
+
124
+ if (input === null) {
125
+ // User clicked Cancel
126
+ running = false;
127
+ continue;
128
+ }
129
+
130
+ const cmd = input.trim().toLowerCase();
131
+
132
+ if (!cmd) continue;
133
+
134
+ try {
135
+ if (cmd.startsWith("v ")) {
136
+ // Vibrate command
137
+ const percentStr = cmd.slice(2);
138
+ const percent = parseInt(percentStr, 10);
139
+ if (!isNaN(percent) && percent >= 0 && percent <= 100) {
140
+ const intensity = percent / 100.0;
141
+ for (const device of devices) {
142
+ if (device.hasOutput(Buttplug.OutputType.Vibrate)) {
143
+ await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(intensity));
144
+ console.log(` ${device.name}: vibrating at ${percent}%`);
145
+ }
146
+ }
147
+ } else {
148
+ alert("Usage: v <0-100>");
149
+ }
150
+ } else if (cmd === "s") {
151
+ // Stop all devices
152
+ await client.stopAllDevices();
153
+ console.log(" All devices stopped.");
154
+ } else if (cmd === "b") {
155
+ // Read battery levels
156
+ let batteryInfo = "Battery Levels:\n\n";
157
+ for (const device of devices) {
158
+ if (device.hasInput(Buttplug.InputType.Battery)) {
159
+ try {
160
+ const battery = await device.battery();
161
+ const msg = `${device.name}: ${(battery * 100).toFixed(0)}%`;
162
+ console.log(` ${msg}`);
163
+ batteryInfo += msg + "\n";
164
+ } catch (e) {
165
+ console.log(` ${device.name}: could not read battery`);
166
+ batteryInfo += `${device.name}: could not read battery\n`;
167
+ }
168
+ } else {
169
+ console.log(` ${device.name}: no battery sensor`);
170
+ batteryInfo += `${device.name}: no battery sensor\n`;
171
+ }
172
+ }
173
+ alert(batteryInfo);
174
+ } else if (cmd === "q") {
175
+ running = false;
176
+ } else {
177
+ alert("Unknown command. Use v, s, b, or q.");
178
+ }
179
+ } catch (e) {
180
+ if (e instanceof Buttplug.ButtplugDeviceError) {
181
+ console.log(` Device error: ${e.message}`);
182
+ alert(`Device error: ${e.message}`);
183
+ } else if (e instanceof Buttplug.ButtplugError) {
184
+ console.log(` Error: ${e.message}`);
185
+ alert(`Error: ${e.message}`);
186
+ } else {
187
+ throw e;
188
+ }
189
+ }
190
+ }
191
+
192
+ // Step 8: Clean up
193
+ console.log("\nStopping devices and disconnecting...");
194
+ await client.stopAllDevices();
195
+ await client.disconnect();
196
+ console.log("Goodbye!");
197
+ }
@@ -0,0 +1,90 @@
1
+ // Buttplug Web - Async Patterns Example
2
+ //
3
+ // This example demonstrates async/await patterns and event handling
4
+ // in the Buttplug library. The library is fully async - all operations
5
+ // that might block (network, device communication) use async/await.
6
+ //
7
+ // Include Buttplug via CDN:
8
+ // <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
9
+
10
+ async function runAsyncExample() {
11
+ console.log("Running async example");
12
+
13
+ const client = new Buttplug.ButtplugClient("Async Example");
14
+
15
+ // Events in buttplug-js use EventEmitter3.
16
+ // You can use addListener or on to subscribe to events.
17
+
18
+ // 'deviceadded' is fired when a new device connects
19
+ client.addListener("deviceadded", async (device) => {
20
+ // Note: Event handlers can be async!
21
+ console.log(`[Event] Device added: ${device.name}`);
22
+
23
+ // You can interact with the device in the event handler
24
+ if (device.hasOutput(Buttplug.OutputType.Vibrate)) {
25
+ console.log(" Sending welcome vibration...");
26
+ await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(0.25));
27
+ await new Promise(r => setTimeout(r, 200));
28
+ await device.stop();
29
+ }
30
+ });
31
+
32
+ // 'deviceremoved' is fired when a device disconnects
33
+ client.addListener("deviceremoved", (device) => {
34
+ console.log(`[Event] Device removed: ${device.name}`);
35
+ });
36
+
37
+ // 'scanningfinished' is fired when scanning completes
38
+ // (some protocols scan continuously until stopped)
39
+ client.addListener("scanningfinished", () => {
40
+ console.log("[Event] Scanning finished");
41
+ });
42
+
43
+ // 'disconnect' is fired when the server connection drops
44
+ client.addListener("disconnect", () => {
45
+ console.log("[Event] Server disconnected!");
46
+ });
47
+
48
+ // 'inputreading' is fired when subscribed sensor data arrives
49
+ client.addListener("inputreading", (reading) => {
50
+ console.log(`[Event] Input reading: ${JSON.stringify(reading)}`);
51
+ });
52
+
53
+ // Connect asynchronously - this may take time due to network
54
+ console.log("Connecting to server...");
55
+ const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345");
56
+ await client.connect(connector);
57
+ console.log("Connected!");
58
+
59
+ // Scanning is also async - we start it and wait for events
60
+ console.log("Starting scan. Turn on devices now...");
61
+ console.log("(Events will be printed as devices connect)");
62
+ await client.startScanning();
63
+
64
+ // Demonstrate concurrent operations after 5 seconds
65
+ setTimeout(async () => {
66
+ console.log("\nDemonstrating concurrent device control...");
67
+
68
+ // Convert devices Map to array
69
+ const devices = Array.from(client.devices.values());
70
+
71
+ if (devices.length > 0) {
72
+ // Send commands to all devices concurrently
73
+ const tasks = devices
74
+ .filter((d) => d.hasOutput(Buttplug.OutputType.Vibrate))
75
+ .map(async (device) => {
76
+ console.log(` Vibrating ${device.name}...`);
77
+ await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(0.5));
78
+ await new Promise(r => setTimeout(r, 500));
79
+ await device.stop();
80
+ console.log(` ${device.name} stopped.`);
81
+ });
82
+
83
+ // Wait for all commands to complete
84
+ await Promise.all(tasks);
85
+ console.log("All devices stopped.");
86
+ } else {
87
+ console.log("No devices connected.");
88
+ }
89
+ }, 5000);
90
+ }
@@ -0,0 +1,87 @@
1
+ // Buttplug Web - Device Control Example
2
+ //
3
+ // This example demonstrates how to send commands to devices,
4
+ // query device capabilities, and use the v4 command builder API.
5
+ //
6
+ // Include Buttplug via CDN:
7
+ // <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
8
+
9
+ async function runDeviceControlExample() {
10
+ const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345");
11
+ const client = new Buttplug.ButtplugClient("Device Control Example");
12
+
13
+ // Set up event handlers before connecting
14
+ client.addListener("deviceadded", async (device) => {
15
+ console.log(`Device connected: ${device.name}`);
16
+
17
+ // Show currently connected devices (client.devices is a Map in v4)
18
+ console.log("Currently connected devices:");
19
+ for (const [index, dev] of client.devices) {
20
+ console.log(` - ${dev.name} (Index: ${index})`);
21
+ }
22
+
23
+ // Check if device supports vibration using v4 API
24
+ if (!device.hasOutput(Buttplug.OutputType.Vibrate)) {
25
+ console.log("Device does not support vibration, skipping control demo.");
26
+ return;
27
+ }
28
+
29
+ console.log("Device supports vibration. Sending commands...");
30
+
31
+ try {
32
+ // Use the v4 command builder API
33
+ console.log("Vibrating at 100%...");
34
+ await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(1.0));
35
+
36
+ await new Promise(r => setTimeout(r, 1000));
37
+
38
+ console.log("Vibrating at 50%...");
39
+ await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(0.5));
40
+
41
+ await new Promise(r => setTimeout(r, 1000));
42
+
43
+ console.log("Stopping device...");
44
+ await device.stop();
45
+ } catch (e) {
46
+ console.log("Error sending command:", e);
47
+ if (e instanceof Buttplug.ButtplugDeviceError) {
48
+ console.log("This is a device error - device may have disconnected.");
49
+ }
50
+ }
51
+
52
+ // Check for battery support using v4 API
53
+ if (device.hasInput(Buttplug.InputType.Battery)) {
54
+ try {
55
+ const level = await device.battery();
56
+ console.log(`${device.name} Battery Level: ${(level * 100).toFixed(0)}%`);
57
+ } catch (e) {
58
+ console.log("Could not read battery level:", e);
59
+ }
60
+ }
61
+
62
+ // Demonstrate other output types if available
63
+ if (device.hasOutput(Buttplug.OutputType.Rotate)) {
64
+ console.log("Device supports rotation. Rotating at 50%...");
65
+ await device.runOutput(Buttplug.DeviceOutput.Rotate.percent(0.5));
66
+ await new Promise(r => setTimeout(r, 1000));
67
+ await device.stop();
68
+ }
69
+
70
+ if (device.hasOutput(Buttplug.OutputType.Position)) {
71
+ console.log("Device supports position control. Moving...");
72
+ await device.runOutput(Buttplug.DeviceOutput.PositionWithDuration.percent(1.0, 500));
73
+ await new Promise(r => setTimeout(r, 1000));
74
+ await device.runOutput(Buttplug.DeviceOutput.PositionWithDuration.percent(0.0, 500));
75
+ }
76
+ });
77
+
78
+ client.addListener("deviceremoved", (device) => {
79
+ console.log(`Device disconnected: ${device.name}`);
80
+ });
81
+
82
+ console.log("Connecting...");
83
+ await client.connect(connector);
84
+ console.log("Connected! Scanning for devices...");
85
+
86
+ await client.startScanning();
87
+ }
@@ -0,0 +1,49 @@
1
+ // Buttplug Web - Device Enumeration Example
2
+ //
3
+ // This example demonstrates how to scan for devices and handle
4
+ // device connection/disconnection events.
5
+ //
6
+ // Include Buttplug via CDN:
7
+ // <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
8
+
9
+ async function runDeviceEnumerationExample() {
10
+ const client = new Buttplug.ButtplugClient("Device Enumeration Example");
11
+
12
+ // Set up event handlers BEFORE connecting.
13
+ // This ensures we don't miss any events, including devices
14
+ // that are already connected to the server.
15
+
16
+ client.addListener("deviceadded", (device) => {
17
+ console.log(`Device connected: ${device.name}`);
18
+
19
+ // The client maintains a Map of all known devices.
20
+ // In v4, client.devices is a Map<number, ButtplugClientDevice>
21
+ console.log("Currently connected devices:");
22
+ for (const [index, dev] of client.devices) {
23
+ console.log(` - ${dev.name} (Index: ${index})`);
24
+ }
25
+ });
26
+
27
+ client.addListener("deviceremoved", (device) => {
28
+ console.log(`Device disconnected: ${device.name}`);
29
+ });
30
+
31
+ client.addListener("scanningfinished", () => {
32
+ console.log("Scanning finished.");
33
+ });
34
+
35
+ // Connect to the server (requires Intiface Central running)
36
+ const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://localhost:12345");
37
+
38
+ console.log("Connecting...");
39
+ await client.connect(connector);
40
+ console.log("Connected!");
41
+
42
+ // Start scanning for devices.
43
+ // Devices will be announced via the 'deviceadded' event.
44
+ console.log("Starting device scan... Turn on your devices now!");
45
+ await client.startScanning();
46
+
47
+ // Note: In a real application, you would call client.stopScanning()
48
+ // when you're done scanning, and client.disconnect() when finished.
49
+ }
@@ -0,0 +1,100 @@
1
+ // Buttplug Web - Device Info Example
2
+ //
3
+ // This example demonstrates how to introspect device features
4
+ // and capabilities in detail using the v4 API.
5
+ //
6
+ // Include Buttplug via CDN:
7
+ // <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
8
+
9
+ function printDeviceInfo(device) {
10
+ console.log("==================================================");
11
+ console.log(`Device: ${device.name}`);
12
+ if (device.displayName) {
13
+ console.log(`Display Name: ${device.displayName}`);
14
+ }
15
+ console.log(`Index: ${device.index}`);
16
+ if (device.messageTimingGap !== undefined) {
17
+ console.log(`Message Timing Gap: ${device.messageTimingGap}ms`);
18
+ }
19
+ console.log("==================================================");
20
+
21
+ // Collect output capabilities
22
+ const outputTypes = [];
23
+ if (device.hasOutput(Buttplug.OutputType.Vibrate)) outputTypes.push("Vibrate");
24
+ if (device.hasOutput(Buttplug.OutputType.Rotate)) outputTypes.push("Rotate");
25
+ if (device.hasOutput(Buttplug.OutputType.Oscillate)) outputTypes.push("Oscillate");
26
+ if (device.hasOutput(Buttplug.OutputType.Position)) outputTypes.push("Position");
27
+ if (device.hasOutput(Buttplug.OutputType.Constrict)) outputTypes.push("Constrict");
28
+ if (device.hasOutput(Buttplug.OutputType.Inflate)) outputTypes.push("Inflate");
29
+ if (device.hasOutput(Buttplug.OutputType.Temperature)) outputTypes.push("Temperature");
30
+ if (device.hasOutput(Buttplug.OutputType.Led)) outputTypes.push("LED");
31
+
32
+ if (outputTypes.length > 0) {
33
+ console.log(`\nOutput Capabilities: ${outputTypes.join(", ")}`);
34
+ }
35
+
36
+ // Collect input capabilities
37
+ const inputTypes = [];
38
+ if (device.hasInput(Buttplug.InputType.Battery)) inputTypes.push("Battery");
39
+ if (device.hasInput(Buttplug.InputType.RSSI)) inputTypes.push("RSSI");
40
+ if (device.hasInput(Buttplug.InputType.Button)) inputTypes.push("Button");
41
+ if (device.hasInput(Buttplug.InputType.Pressure)) inputTypes.push("Pressure");
42
+
43
+ if (inputTypes.length > 0) {
44
+ console.log(`Input Capabilities: ${inputTypes.join(", ")}`);
45
+ }
46
+
47
+ // Detailed feature breakdown
48
+ console.log("\nDetailed Features:");
49
+ for (const [index, feature] of device.features) {
50
+ // Access the underlying feature definition
51
+ const def = feature._feature;
52
+ console.log(`\n Feature ${index}: ${def.FeatureDescriptor}`);
53
+
54
+ if (def.Output) {
55
+ console.log(" Outputs:");
56
+ for (const [type, config] of Object.entries(def.Output)) {
57
+ console.log(` - ${type}: steps ${config.Value[0]}-${config.Value[1]}`);
58
+ }
59
+ }
60
+
61
+ if (def.Input) {
62
+ console.log(" Inputs:");
63
+ for (const [type, config] of Object.entries(def.Input)) {
64
+ console.log(` - ${type}: commands [${config.Command.join(", ")}]`);
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ async function runDeviceInfoExample() {
71
+ const client = new Buttplug.ButtplugClient("Device Info Example");
72
+
73
+ // Connect to the server
74
+ const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345");
75
+
76
+ console.log("Connecting...");
77
+ await client.connect(connector);
78
+ console.log("Connected! Scanning for devices...");
79
+ console.log("Turn on your devices now. Info will be printed as they connect.\n");
80
+
81
+ // Set up device event to print info when devices connect
82
+ client.addListener("deviceadded", (device) => {
83
+ printDeviceInfo(device);
84
+ });
85
+
86
+ await client.startScanning();
87
+
88
+ // After a few seconds, also show summary of all connected devices
89
+ setTimeout(() => {
90
+ console.log("\n\n========== SUMMARY ==========");
91
+ if (client.devices.size === 0) {
92
+ console.log("No devices connected.");
93
+ } else {
94
+ console.log(`Found ${client.devices.size} device(s):`);
95
+ for (const [index, device] of client.devices) {
96
+ console.log(` ${index}: ${device.name}`);
97
+ }
98
+ }
99
+ }, 5000);
100
+ }