Haply Inverse SDK 3.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 `configure` map for one-shot commands β basis, preset, mount, force_gate, damping per device, plus profile and basis per session, now all live in configure β 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 to custom.Named command fields β position, vector, angles, torques replace the generic values array.set_angular_torques replaces set_angular_torque (singular deprecated).Session frame extensions β v3.0 and v3.1 session frames now carry extensible config, state, and status objects; new output fields include current_cursor_force, current_cursor_position, current_angular_torques, current_angular_position, control_domain, control_mode, transform, transform_velocity, richer config.*, and status.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 /settings and /settings/* β full key-value settings API.GET /sessions/{session} and GET/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__ITALIC_italic-1__/... for all Inverse-family devices).Unified request/response shape β POST/GET bodies use the same command_data JSON shapes as WebSocket; code written against one transport works against the other.Opt-in envelope via ?format=json on any route; /settings* and GET /home_return default to {ok, error, data}. Use ?format=plain for 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.gain over 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_interfaces setting.Device-selector wildcards use prefix syntax (e.g. inverse* matches all Inverse-family devices).Damping commands moved into the configure map alongside force_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_position no 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_basis` matrix 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_id` was serialized as 0 in some outgoing payloads.On Windows, --log-level is now respected when combined with --dev (previously silently reset to debug).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_warning field in the response β clients that strictly validate response schemas should allow the extra field.The values field in WebSocket command_data is 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.