Python SDK for driving Hapbeat haptic devices over Wi-Fi UDP
Project description
Hapbeat Python SDK
Drive Hapbeat haptic devices from Python over Wi-Fi UDP. For researchers (PsychoPy / Jupyter / ROS), media artists, and anyone prototyping haptics in Python.
A script can drive Hapbeat with a few lines. The fire side (play / stop)
and the tuning side (EventMap) are kept orthogonal and linked only by
event id.
Install
pip install hapbeat-python-sdk # core (zero dependencies, stdlib socket only)
pip install "hapbeat-python-sdk[osc]" # + generic OSC bridge (TouchOSC / Max / TD)
With pipx you get the hapbeat CLI (including the launchpad below) in an
isolated environment: pipx install hapbeat-python-sdk. Note that pipx does not make
import hapbeat available to your own scripts — for the examples/ use a
normal pip install in a venv.
Try everything from one page (launchpad)
hapbeat launchpad # opens http://127.0.0.1:7100 in your browser
A single local web page to fire events, run a metronome, a breathing pacer,
or send Morse — start and stop them live, no per-example launching. It serves
a tiny stdlib HTTP server that relays button presses to the device over UDP
(browsers can't send UDP directly). Works great with pipx install hapbeat-python-sdk.
Quick start
import hapbeat
hb = hapbeat.connect(app_name="MyExperiment") # opens UDP broadcast + keep-alive
hb.play("impact.hit", gain=0.3) # fire event "impact.hit" at gain 0.3
hb.play("impact.hit") # gain omitted -> kit baseline intensity
hb.stop("impact.hit")
hb.stop_all()
hb.close()
or as a context manager:
with hapbeat.connect(app_name="MyExperiment") as hb:
hb.play("impact.hit")
"impact.hit" must be an event id present in the kit deployed to the
device (via Hapbeat Studio). The SDK sends
the instruction; the waveform lives in the kit on the device.
Discovery
for dev in hb.discover(timeout=1.5):
print(dev.ip, dev.address, dev.firmware_version)
EventMap — the tuning side (optional)
Keep per-event default gains in one place and let play("id") resolve them,
so firing code never hard-codes intensities:
em = hapbeat.EventMap.from_manifest("my-kit/my-kit-manifest.json")
hb = hapbeat.connect(event_map=em)
hb.play("impact.hit") # uses the kit manifest's intensity for this event
EventMap reads the kit manifest (schema 2.0.0) intensity as the baseline
gain. You can also build one by hand: EventMap.from_dict({"impact.hit": 0.5}).
Haptic file — add targeting on top of the kit
The Studio-generated manifest holds kit content (intensity / clip), but not
app-side concerns like which device/body part an event goes to. Put those
in a haptic file (an EventMap overlay that references the kit), so play(id)
resolves the target without the caller passing it:
// haptics.json
{
"kit": "kits/my-kit",
"events": {
"impact.hit": { "target": "player_1/chest", "gain": 0.8 },
"rain.loop": { "target": "*/back" }
}
}
hb = hapbeat.connect(app_name="MyApp", haptics="haptics.json")
hb.play("impact.hit") # goes to player_1/chest at gain 0.8 — from the file
Two playback modes: command and clip
The same play(id) call branches on the manifest:
| Manifest bucket | Mode | What happens |
|---|---|---|
events |
command | the SDK sends a PLAY; the device plays its installed clip |
stream_events |
clip | the SDK reads the WAV from the kit's stream-clips/ and streams it over UDP |
Put the kit inside your project and call events by id — the per-event details (intensity, loop, command vs clip, which WAV) live in the kit, not your code:
my-app/
app.py
kits/my-kit/
my-kit-manifest.json # the "haptic file" -> EventMap
install-clips/ # command clips (flashed to the device via Studio)
stream-clips/*.wav # clip-mode WAVs the SDK streams
import hapbeat
hb = hapbeat.connect(app_name="MyApp", kit="kits/my-kit")
hb.play("impact.hit") # command -> device plays its installed clip
hb.play("rain.loop") # clip -> SDK streams stream-clips/<wav> over UDP
hb.stop("rain.loop") # ends the active stream
You can also stream an ad-hoc PCM16 buffer (e.g. a synthesized stereo cue where L/R amplitude conveys direction):
hb.stream_pcm(pcm_bytes, sample_rate=16000, channels=2)
Author clips as 16 kHz mono PCM16 (the device plays at 16 kHz; the SDK does not resample). A full runnable example is in examples/clip_project/.
Generic OSC bridge
Any OSC tool (TouchOSC, Max/MSP, TouchDesigner, a DAW) can drive Hapbeat
without code. Run the bridge and send /hapbeat/play <event_id> [target] [time] [gain]:
hapbeat osc-bridge --listen 7702
See docs/osc.md for the address spec.
CLI
hapbeat scan # list devices on the LAN
hapbeat play impact.hit --gain 0.3
hapbeat stop-all
hapbeat launchpad # browser UI for all of the above
Examples
Ready-to-run sample applications live in examples/: a psychophysics experiment, a breathing pacer, a haptic metronome, a live trigger pad, a task-completion notifier, and a Morse transmitter. Each is a single stdlib-only file — see examples/README.md.
For AI coding agents
Working with Claude / Cursor / Copilot? Hand your agent AGENTS.md — a single self-contained file with the SDK's model, API, project layout, and pitfalls. One file is enough to get the whole picture.
Use the Hapbeat Python SDK. Read
AGENTS.mdand follow its API and best practices.
License
MIT © Hapbeat
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hapbeat_python_sdk-0.1.0.tar.gz.
File metadata
- Download URL: hapbeat_python_sdk-0.1.0.tar.gz
- Upload date:
- Size: 42.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12eb8c14c6a4f2c9809f567bd785fe08182df63384d3d5cbbfcd390b77b98599
|
|
| MD5 |
aba9ac283b9dfd8d2c5b14dfdea4219c
|
|
| BLAKE2b-256 |
6bfff4e60090dca4f488cd2ca0e6d7196b569b58f15d41ae6260d58fdc8850db
|
Provenance
The following attestation bundles were made for hapbeat_python_sdk-0.1.0.tar.gz:
Publisher:
publish.yml on hapbeat/hapbeat-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hapbeat_python_sdk-0.1.0.tar.gz -
Subject digest:
12eb8c14c6a4f2c9809f567bd785fe08182df63384d3d5cbbfcd390b77b98599 - Sigstore transparency entry: 1885388975
- Sigstore integration time:
-
Permalink:
hapbeat/hapbeat-python-sdk@f46c093903724ad09b7609370cf10700ac8ce0f6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/hapbeat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f46c093903724ad09b7609370cf10700ac8ce0f6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hapbeat_python_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: hapbeat_python_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c99351146341e0e6c6fd35bfbab59c0639d525451015882ab38b6507beb8eb2b
|
|
| MD5 |
1375699f5c188958266ac4c1ae946478
|
|
| BLAKE2b-256 |
95cd067436c6fb43fbe496a4c058196ca06c6e16a3303645aa024eabd1418ffd
|
Provenance
The following attestation bundles were made for hapbeat_python_sdk-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on hapbeat/hapbeat-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hapbeat_python_sdk-0.1.0-py3-none-any.whl -
Subject digest:
c99351146341e0e6c6fd35bfbab59c0639d525451015882ab38b6507beb8eb2b - Sigstore transparency entry: 1885388999
- Sigstore integration time:
-
Permalink:
hapbeat/hapbeat-python-sdk@f46c093903724ad09b7609370cf10700ac8ce0f6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/hapbeat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f46c093903724ad09b7609370cf10700ac8ce0f6 -
Trigger Event:
push
-
Statement type: