EventMap reference
EventMap is the SDK’s tuning side (what to play, and how strongly). It is separate
from the fire side (play / stop / stopAll) and is linked by event id alone. It
reads a kit manifest (schema 2.0.0) and holds each event’s default intensity, loop, and
clip.
By keeping intensity out of your fire code and consolidating it in the EventMap, you can swap “when to play (code)” and “how strongly to play (kit)” independently. For how to use this on the fire side, see Command vs Clip.
Constructors
Section titled “Constructors”import { EventMap } from "@hapbeat/sdk";
// from a parsed kit manifest (recommended)EventMap.fromManifest(manifest: KitManifest): EventMap
// from a hand-written { eventId: gain } map (command only, gain only)EventMap.fromGains(gains: Record<string, number>): EventMap
// pass EventDefs directly (low level)new EventMap(events?: Record<string, EventDef> | Map<string, EventDef>)import { connect, EventMap } from "@hapbeat/sdk";
const manifest = await fetch("/my-kit/my-kit-manifest.json").then((r) => r.json());const hb = await connect({ eventMap: EventMap.fromManifest(manifest) });hb.play("sample-kit.sine_100hz"); // fires at this manifest's intensityfromManifestreads both theevents(command) andstream_events(clip) buckets, taking in each event’sparameters.intensity/loop/device_wiperand its clip name.fromGainsbuilds from a simple map like{ "sample-kit.sine_100hz": 0.5 }; everything becomes command mode,loop: false,streaming: false.
Instance methods
Section titled “Instance methods”em.get("sample-kit.sine_100hz"); // EventDef | undefinedem.gainFor("sample-kit.sine_100hz"); // default gain (intensity). 1.0 if absentem.has("sample-kit.sine_100hz"); // booleanem.ids(); // string[] — all event idsem.size; // number — countgainFor(id) is the default used when play(id) omits gain. Passing an id not in the
EventMap falls back to 1.0 (full gain).
EventDef fields
Section titled “EventDef fields”The EventDef returned by em.get(id):
| Field | Type | Meaning |
|---|---|---|
eventId | string | Event id |
intensity | number | Default gain (the manifest’s parameters.intensity, default 1.0) |
loop | boolean | Whether to loop playback |
deviceWiper? | number | Device-side wiper value (optional) |
streaming | boolean | true = clip mode (from stream_events) |
clip? | string | Clip-mode WAV file name (resolved relative to clipBase) |
note | string | Note |
KitManifest shape and bucket → mode
Section titled “KitManifest shape and bucket → mode”interface KitManifest { schema_version?: string; events?: Record<string, ManifestEntry>; // → command mode stream_events?: Record<string, ManifestEntry>; // → clip mode (streaming: true)}{ "schema_version": "2.0.0", "events": { "sample-kit.sine_100hz": { "clip": "hit.wav", "parameters": { "intensity": 0.8 } } }, "stream_events": { "rain.loop": { "clip": "rain.wav", "parameters": { "intensity": 0.3, "loop": true } } }}eventsbucket →EventDef(streaming: false)= command mode. The SDK sends a PLAY instruction and the device plays its deployed clip.stream_eventsbucket →EventDef(streaming: true, clip: "...")= clip mode. The SDK loads the WAV (clipBase+clipLoader) and streams it over UDP.
For the manifest shape and event-id conventions, see Event ID and Kit; for the mode concept, see Fire vs. Clip.
How play(id) consumes it
Section titled “How play(id) consumes it”When you call play(id), the SDK looks up the eventMap you passed at connect time and:
- If gain is unspecified, defaults it to
gainFor(id)(= the manifest’s intensity). - Inspects that id’s
EventDef.streamingto branch between command and clip.streaming: false→ sends a PLAY instruction (the device plays the clip).streaming: true→ loads theclipWAV viaclipBase+clipLoaderand streams it over UDP as 16 kHz mono PCM16.
- If you don’t pass an
eventMap, every event is treated as command mode and gain is1.0.
Important notes (differences from the Python SDK)
Section titled “Important notes (differences from the Python SDK)”The JS EventMap is manifest-only. The following features that the Python SDK has are
not in JS:
- No haptic-file overlay (per-event target / gain override) — JS has no
from_fileequivalent. The destination is set via the caller’starget=or the connection’sdefaultTarget(Transports — Node UDP / React Native UDP / Browser helper). - No
target/modefield —EventDefcarries no targeting. The command vs. clip decision is made by thestreamingflag alone. - No
kit_dirresolution — clip WAVs are resolved not bykit_dirbut by the connection optionsclipBase(Node: a directory path / Browser: a URL prefix) andclipLoader. - No loop-driven auto-stop —
loop: trueis only retained as manifest-derived metadata; the JSEventMapitself does no stop control. To stop, callstop(id)/stopAll()explicitly.
Next reads
Section titled “Next reads”- Command vs Clip — choosing between command and clip
- Project Structure — laying out kits and clips in your project
- Streaming — clips & ad-hoc PCM — clip-mode streaming