This library reads and writes PinPoint swing files (.ppsw), the binary replacement for PinPoint Studio's swing.json.
A recorded swing's document holds its capture manifest, sensor streams, pose, club and ball tracks, phases and metrics. As JSON it was 30–65 MB per swing, and about 58% of that was indentation. As .ppsw it is about 2–4 MB. It is lossless: every number comes back bit-for-bit. It is also lazy: the session, review and metric scalars load without touching the pose tracks.
| JSON (indented) | .ppsw lossless |
.ppsw display-f32 |
|
|---|---|---|---|
| 2026-07-04 swing 1 (face-on) | 35.1 MB | 3.35 MB (10.5×) | 1.93 MB (18.2×) |
The format is specified in docs/specification/ppsw-format.md, and the design is described in docs/design.md. In short:
- a 40-byte header, then zstd-compressed chunks, then a table of contents;
- each chunk holds a subtree of the document, encoded as CBOR;
- numeric arrays become typed, byte-shuffled ndarrays;
- arrays of objects become column-wise tables.
include/ppswing/,src/: the C++17 library,ppswing::ppswing. Its only dependency is zstd 1.5.7, vendored inthird_party/zstd.tools/ppsw.cpp: theppswcommand line tool:ppsw convert swing.json [-o swing.ppsw] [--policy lossless|display-f32] ppsw dump swing.ppsw [--indent] # back to JSON ppsw info swing.ppsw # chunk table ppsw verify swing.json swing.ppsw # lossless check (spec §1.1)python/ppswing: a pure-Python reader, independent of the C++ code and with no required dependencies. It uses the stdlib zstd on Python 3.14+, orpip install zstandardon older versions. numpy is optional.import ppswing doc = ppswing.load_swing("…/swing_0001") # a swing dir, swing.json or swing.ppsw r = ppswing.Reader("swing.ppsw"); r.root() # the cheap read: no pose decoded
tools/corpus_check.py: converts a library of swings and proves the round trip with both decoders.tools/make_fixture.py: trims and anonymises a real swing into a test fixture.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j8
ctest --test-dir build
Tests and tools build only when this is the top-level project. Embedded with add_subdirectory or FetchContent, only the library builds, and the consumer's build is unchanged.
The sanitizer build is:
cmake -S . -B build-asan -DPPSW_ENABLE_ASAN=ON -DPPSW_ENABLE_UBSAN=ON
MIT. The vendored zstd is BSD-3-Clause (third_party/zstd/LICENSE).