JavaScript/TypeScript utilities for reading and writing SLEAP .slp files with streaming-friendly access patterns and a lightweight data model. This is the JS companion to the Python library at https://github.com/talmolab/sleap-io.
- Make SLP parsing available in browsers and serverless runtimes.
- Support streaming-first workflows for large
.slp/.pkg.slpfiles. - Provide a minimal data model and codecs that mirror sleap-io behavior.
- Enable client-side visualization and analysis pipelines.
- SLP read/write with format compatibility (format 1.0–2.2, including embedded frames via HDF5 video datasets).
- Browser-compatible SLP writing via
saveSlpToBytes(). - Streaming-friendly file access (URL,
File,FileSystemFileHandle,Blob). - Core data model (
Labels,LabeledFrame,Instance,Skeleton,Video,Centroid,Identity,Instance3D, etc.). - ROI, segmentation mask, bounding box, and label image annotations with GeoJSON I/O.
- Browser-safe segmentation rendering:
SegmentationMask.contours()boundary tracing (real outlines, not just the bbox) plusdrawMasks/drawLabelImageraster compositing for client-side UIs. - Ultralytics YOLO dataset reader/writer (pose, detection, segmentation; Node.js).
- JABS (Jackson Lab) pose-file reader (predicted poses + static-object ROIs; Node.js).
- 3D pose data structures with cross-library interop (Python sleap-io, luc3d).
- Video backends accept
string,File, orBlobsources. - Browser-safe: Node.js-only dependencies (
skia-canvas,child_process) are dynamically imported, so bundlers can tree-shake them. - Dictionary and numpy codecs for interchange.
- SLEAP Analysis CSV export (
labelsToCsv/saveLabelsCsv), with optional full-video-span padding. - Demo app for quick inspection.
npm install @talmolab/sleap-io.jsimport { loadSlp, saveSlp, saveSlpToBytes } from "@talmolab/sleap-io.js";
const labels = await loadSlp("/path/to/session.slp", { openVideos: false });
// Save to file (Node.js/Electron)
await saveSlp(labels, "/tmp/session-roundtrip.slp", { embed: false });
// Save to bytes (works in browsers too)
const bytes: Uint8Array = await saveSlpToBytes(labels);import { loadUltralytics, saveUltralytics } from "@talmolab/sleap-io.js";
// Read a split; the per-line format (pose/detection/segmentation) is auto-detected
const labels = loadUltralytics("/path/to/yolo_dataset", { split: "train" });
// Write back out (task: "pose" default, or "detect" / "segment")
await saveUltralytics(labels, "/tmp/yolo_out", { splitRatios: { train: 0.8, val: 0.2 } });Node.js only (directory-based datasets). See docs/api.md for label-line formats and lower-level helpers.
import { loadJabs } from "@talmolab/sleap-io.js";
// Read a JABS pose file (HDF5). Returns PredictedInstance objects.
const labels = await loadJabs("/path/to/recording_pose_est_v5.h5");
labels.labeledFrames; // PredictedInstance poses, one Track per JABS identity
labels.staticRois; // arena corners / lixit / food hopper as UserROI (source: "jabs")Node.js only (JABS files are HDF5). Pose versions 2–6 are supported.
import { loadVideo, Mp4BoxVideoBackend } from "@talmolab/sleap-io.js";
// From file path (Node.js) or URL (browser)
const video = await loadVideo("/path/to/video.mp4", { openBackend: false });
video.close();
// Mp4BoxVideoBackend also accepts File or Blob (browser)
const backend = new Mp4BoxVideoBackend(file); // File or BlobFor environments that don't support WebAssembly compilation (e.g., Cloudflare Workers), use the /lite entry point:
import { loadSlpMetadata, validateSlpBuffer } from "@talmolab/sleap-io.js/lite";
// Load metadata without pose coordinates
const metadata = await loadSlpMetadata(buffer);
console.log(metadata.skeletons); // Full skeleton definitions
console.log(metadata.counts); // { labeledFrames, instances, points, predictedPoints }
console.log(metadata.provenance); // { sleap_version, ... }
// Quick validation
validateSlpBuffer(buffer); // throws on invalidThe lite module uses jsfive (pure JavaScript) instead of h5wasm (WebAssembly), enabling use in restricted environments. It can read all metadata but not pose coordinates or video frames.
- I/O layer:
loadSlp/saveSlpwrap the HDF5 reader/writer insrc/codecs/slp. - Data model:
src/modelmirrors sleap-io classes and supports numpy/dict codecs. - Backends:
src/videoprovides browser media and embedded HDF5 decoding. - Streaming:
src/codecs/slp/h5.tsselects URL/File/FS handle strategies.
- Env1 (Static SPA): Browser-only usage with URL streaming (CORS + Range) or the File System Access API.
- Env2 (Server/Worker): Server-side or worker environments that stream
.slpfrom URLs or byte buffers. - Env3 (Local Node/Electron): Optional local filesystem access for Node/Electron.
Streaming can be tuned with:
await loadSlp(url, { h5: { stream: "auto", filenameHint: "session.slp" } });The demo in demo/ loads the built package from dist/. Build first, then serve the repo with a static server and open demo/index.html:
bun run buildThis repo uses Bun (pinned to bun@1.3.14 via the packageManager field) as its package manager, script runner, and test runner. After installing Bun:
bun install # install dependencies (uses the committed bun.lock)
bun run build # bundle to dist/ with tsup
bun run lint # type-check with tsc --noEmit
bun test # run the unit suite (bun's native test runner)See CONTRIBUTING.md for more detail on the toolchain.
The published package is plain ESM on the npm registry, so consumers can install it with any package manager (
npm,pnpm,yarn, orbun) — thenpm installline above works as-is.
Day-to-day development uses Bun, but releases still publish to the npm registry (bun publish does not support npm's OIDC trusted publishing / provenance). The first publish must be done manually to unlock the npm package settings:
- First-time publish (one-time):
npm login
npm publish --access public- Enable Trusted Publisher at
https://www.npmjs.com/package/@talmolab/sleap-io.js/access.
After that, GitHub Releases trigger the publish workflow automatically.
- Python sleap-io: https://github.com/talmolab/sleap-io
- Docs: https://io.sleap.ai