v3.5.0
Our largest release since the API rewrite a year ago. 3.5.0 introduces a unified 3D math layer, full Minverse support, a typed event stream, a complete settings API, and a cleaner HTTP surface — alongside a year of bug fixes and quality-of-life improvements.
Highlights
- Unified 3D math layer — a composable transformation pipeline with first-class primitives for device basis (frame), mount transform, workspace transform, and navigation transform, plus explicit conversions between local, session, application, and internal spaces.
- Bubble Navigation — navigate large virtual workspaces through shaped zones (SDF primitives) with velocity-mapped rate control, hysteresis-aware collision detection, and optional drift-toward-cursor. Fully configurable over HTTP and WebSocket with app-space round-trip.
- Typed event stream — a dedicated WebSocket event channel for device lifecycle, safety alerts, calibration, battery, control-rate warnings, and deprecation hints.
- Settings API — a complete key-value settings system with HTTP CRUD, type hints, range constraints, and descriptions, replacing the old nested config file.
- Consistent device configuration — one set of HTTP routes for every device:
basis,mount,preset,transform,filters,handedness,torque_scaling,gravity_compensation,home_return. - Synchronized Minverse + pen calibration — the device and its pen now calibrate together; calibration stays locked until a grip is physically attached.
- Quality-of-life HTTP — index-based device selectors (target a device by index, no ID needed), a unified request/response shape shared with WebSocket, an opt-in
{ok, error, data}envelope (?format=json), and wildcard session selectors.
New features
Devices
- Minverse — official support shipped with this release: detection, ready sequence, safety notifications, and the synchronized calibration workflow.
- Ruko and Kingfisher recognized as official grip product types.
- Device simulator support — detect and talk to software-simulated devices alongside real hardware.
- Connection-loop protection — misbehaving ports are automatically blocked; reset with
POST /ports/{port}/reset. - Pen attachment heartbeat — reliable grip attach/detach detection with debounce.
Sessions, commands & WebSocket
- Session profile filtering and persistence — sessions declare a profile name and required SDK version that the service remembers across reconnects; clients and monitoring tools can filter and target sessions by that profile.
- Per-session command buffers — one slow session can no longer stall another.
- Explicit
configuremap for one-shot commands —basis,preset,mount,force_gate,dampingper device, plusprofileandbasisper session, now all live inconfigure— aligned with the output config map so what you send round-trips with what you read back. - Customizable device mount — pick a built-in workspace preset (
defaults,arm_front,arm_front_centered,led_front,led_front_centered) or send an explicit transform; manual mount changes automatically flip the preset tocustom. - Named command fields —
position,vector,angles,torquesreplace the genericvaluesarray. set_angular_torquesreplacesset_angular_torque(singular deprecated).- Session frame extensions — v3.0 and v3.1 session frames now carry extensible
config,state, andstatusobjects; new output fields includecurrent_cursor_force,current_cursor_position,current_angular_torques,current_angular_position,control_domain,control_mode,transform,transform_velocity, richerconfig.*, andstatus.safety(hidden by default). - Partial transform updates — send only the sub-fields you want to change (
position,rotation,scale) on mount, workspace transform, and navigation shape.
HTTP
GET /— service version.GET/POST/DELETE /settingsand/settings/*— full key-value settings API.GET /sessions/{session}andGET/POST/DELETE /sessions/{session}/profile.GET /devices?session=<selector>— convert device coordinates into a given session's application space.- Index-based device selectors — target any device by index without knowing its ID (
/inverse3/0/...for the first Inverse3;/inverse*/*/...for all Inverse-family devices). - Unified request/response shape — POST/GET bodies use the same
command_dataJSON shapes as WebSocket; code written against one transport works against the other. - Opt-in envelope via
?format=jsonon any route;/settings*andGET /home_returndefault to{ok, error, data}. Use?format=plainfor the raw shape. - Session selector wildcards —
*(any sequence) and?(single char) in profile names. - Percent-decoded selectors —
%2A,%3A, etc. are decoded before routing.
Events
- Dedicated WebSocket event stream on
communication/events/port. - 24 typed event categories including device lifecycle, safety (e-brake, foreign-object detection, stall), calibration failures, battery alerts, session warnings, low/critical control rate, input validation, and deprecation hints.
Observability
- Log messages forwarded to Tracy with level-based colors when profiling.
- Tracy zones on every HTTP handler.
- Main-loop timing statistics events.
- Configurable log directory and server hostname (Docker-friendly).
Coming in 3.6
- SDF Haptic Effects (SDF HFX) — the groundwork has landed in 3.5 (module, lifecycle, module-contributed command/state serialization) and the public API will ship with full documentation in 3.6.
Improvements
- Force oscillation filtered — per-axis oscillation detection, 8-stage graduated recovery, entry vote with hysteresis, and asymmetric release windows.
- Runtime force-gate filter — configurable via
configure.force_gate.gainover WebSocket or HTTP with a persistent default. - Main loop maximum frequency raised to 32 kHz for precision applications.
- Smaller WebSocket payloads — identity-default transform sub-fields (
position = 0,rotation = identity,scale = 1) are omitted from output by default, cutting payload size and restoring compatibility with the 4 KB message limit of older Unity packages. Two advanced settings (serialization/explicit_fields,serialization/force_complete_transforms) reinstate every field for consumers that need it. - Lower main-loop jitter — WebSocket message processing no longer blocks the main-loop tick during JSON parsing and network send; session tick scheduling moved ahead of response serialization.
- Servers default to localhost-only — opt in to network access with the
communication/bind_all_interfacessetting. - Device-selector wildcards use prefix syntax (e.g.
inverse*matches all Inverse-family devices). - Damping commands moved into the
configuremap alongsideforce_gate. - Rotating file logger replaces the previous one, with configurable directory.
- Module-contributed commands and state — modules can inject their own commands, configure fields, and state output into the WebSocket frame without touching the core schema.
Fixes
A year of bug fixes; the most impactful are below.
- Erratic session velocity under certain conditions.
- GripHook (Verse Grip Stopper) did not cleanly release when no simulation was running.
- Inverse3 timeouts were too aggressive and caused disconnection loops on slow-booting devices.
- Unclean service stop on Windows — the HTTP server was not always cleaned up on shutdown.
- Reconnection loop when the service sent unsupported commands to older firmware versions.
- Bluetooth device enumeration flooded the log on systems with Bluetooth adapters.
- Crash when restarting the service multiple times in a row.
- Wireless Verse Grip dongle freeze on Ubuntu laptops after sleep/resume.
- Wireless Verse Grip handshake on Linux and macOS now falls back correctly when the first detection attempt fails.
- MacOS config file location — config is now stored in
~/Library/Application Support/instead of the wrong path. - SIGSEGV signal handling on Linux and macOS — the process no longer loops on fatal signals when multi-thread crash capture is enabled.
- Cross-session command overwrite — config commands from one session could be silently replaced by commands from another; they are now filtered and merged correctly.
- Probe commands overwriting config — monitoring sessions (e.g. Haply Hub) sending
probe_positionno longer silently overwrite pending basis / preset / profile changes. - Prototype grips display — prototype hardware incorrectly appeared as a standard grip instead of a custom one.
- Legacy
set_basismatrix convention honored again for clients that had not migrated. - Inverse3 force kick on session disconnect no longer produces a residual force spike.
- WebSocket connection lost race during rapid connect/disconnect cycles.
- WebSocket
session_idwas serialized as0in some outgoing payloads. - On Windows,
--log-levelis now respected when combined with--dev(previously silently reset todebug).
Deprecations
Still functional, but will be removed in a future major version. Responses include a deprecation_warning field where applicable.
| Deprecated | Replacement |
|---|---|
POST /force_scale | POST /settings/devices/inverse*/filters/force_scale/gain |
POST /gravity_compensation | POST /{device}/{id}/config/gravity_compensation |
POST /torque_scaling | POST /{device}/{id}/config/torque_scaling |
POST /device_handedness | POST /{device}/{id}/config/handedness |
POST /serial_enable | POST /settings/communication/serial/enabled |
POST /experimental/features/grip_dropped_simulation_stopper | Settings API |
POST /experimental/features/screensaver_enable | Settings API |
WebSocket command_data.values | position, vector, angles, torques |
WebSocket set_angular_torque | set_angular_torques |
WebSocket probe_cursor_position | probe_position |
WebSocket set_coordinate_origin | configure.preset |
WebSocket session-level set_basis | configure.basis |
Compatibility notes
No hard breaking changes against 3.4.19. Two soft notes for existing integrations:
- Deprecated HTTP endpoints now include a
deprecation_warningfield in the response — clients that strictly validate response schemas should allow the extra field. - The
valuesfield in WebSocketcommand_datais deprecated but still parsed; prefer the named fields.
Tutorials & documentation
- New tutorials: 05 Position Control, 06 Combined (Inverse3 + Verse Grip), 07 Basis and Mount, 08 HTTP Remote Configurator, 09 WebSocket Remote Control, 10 Event Stream Listener.
- New Glaze variant of every C++ tutorial (
cpp-glz/) alongside the existing nlohmann/json variant. - All tutorials rewritten for the v3.1 API (port 10001,
configure.preset, named command fields,print_state()helpers). - Removed the old Verse Grip Stopper tutorial — replaced by the new Combined tutorial.
- Public documentation refreshed across the SDK guides, API reference, and hardware pages.