npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@miadi/movement-conductor

v0.3.1

Published

Movement conducted into musical expression — one source, many listeners. Sensor streams become nine-channel frames; each conducted frame is heard simultaneously by Wekinator (/wek/inputs), by the score being recorded (a TLID-named take, corpus-compatible

Readme

@miadi/movement-conductor

Movement conducted into musical expression — one source, many listeners.

The phone's sensors are sections of an orchestra: each reports at its own cadence. The conductor holds the latest frame and, at each beat of the chosen tempo, gives it to every listener at once — the machine-listener (Wekinator, /wek/inputs, nine float channels), the score being recorded, and live meters. Recording and performing are one gesture heard by different listeners.

Carries forward Miadi Chronicle Episode 083 (landbase movement capture to Wekinator): the score format is line-per-packet JSONL with a summary sidecar, field-compatible with the Episode 083 captures — old and new scores are one corpus, and every capture in the chronicle can perform again through ScoreReplaySource.

The frame contract

| Channels | Meaning | Unit | |----------|---------|------| | 1–3 | user acceleration (gravity removed), x y z | g | | 4–6 | rotation rate, x y z | rad/s | | 7–9 | attitude — roll, pitch, azimuth/yaw | rad |

Pieces

  • Conductor — one MovementSource → many MovementSinks, with an optional tempo (fps) that holds each section's last note between beats.
  • Sources: OscListenerSource (the wire — what the Episode 083 listening host was), ScoreReplaySource (the corpus as an instrument); the Android body lives in @miadi/termux-motion.
  • Sinks: WekinatorSink, ScoreRecorder (JSONL + *.summary.json), LiveTap.
  • MovementCaptureDriver — implements @miadi/capture's CaptureDriver, so a movement score is a take: TLID-named, in the take library, with provenance that survives a restart (extension: "jsonl").
  • SummaryAccumulator — the honest reading: per-channel stats, acceleration and rotation magnitudes, and rate fields that keep partial performances truthful.

Reading a score back — the analysis subpath

@miadi/movement-conductor/analysis turns recorded frames into the musical answers the atelier needs: the real new-value rate, per-second magnitudes, onsets, an unwrapped heading, compass sextants, and stillness spans.

Every measure is @miadi/ava8-measure/movement's, ported from the Python and verified against it on nine real captures. This module implements none of them; it is an adapter, re-exports the whole measure set, and owns exactly one thing — the timebase.

import { readFile } from "node:fs/promises"
import { analyzeScoreText } from "@miadi/movement-conductor/analysis"

const a = analyzeScoreText(await readFile(score, "utf8"))
a.timebase.recordedTakeTiming   // true — the score's own t
a.dedupe.heldRatio              // 0.76: the transport, not the body
a.onsets.times                  // where a note is struck
a.stillness.cuts                // where the sections open

The subpath is separate on purpose: importing the package root never loads the measure set.

Dedupe is the first act

A packet whose values equal its predecessor's is a held value, not a measurement — the OSC literature's standard mitigation for UDP's non-assured delivery, which the conductor's tempo mode performs on purpose. Measured on the capture of 2026-08-16 17:14: 1627 packets over 16.6 s, 98 Hz of packets, of which 1232 repeat the previous value. The 395 new values are 23.8 Hz with a 41 ms median gap.

Onsets on the raw stream: 28 attacks spaced 120–133 ms — regular, credible, entirely false. That is the staircase, not a body. Deduped: 15 attacks, 153 to 1481 ms — two bursts around a silence, which is a musical form, and which is his. So analyze dedupes before every measure except rates, which must see the raw stream because the held count is its subject, and reports that it did in analysis.dedupe.

The timebase, which is the whole of the adaptation

MovementFrame carries at: Date and no t. ScoreRecorder.hear() synthesises t as monotonic seconds-since-open; ScoreReplaySource reads that t back and discards it, emitting a fresh at. So t is reconstructed — from the JSONL field when reading a score, from at deltas when handed frames:

| given | t from | the take that was recorded? | |---|---|---| | score JSONL text | the score's own t | yes | | frames declared live | at deltas — arrival is the clock | yes, at ms resolution | | frames declared replay | the replay's arrival times | no | | frames, origin undeclared | at deltas | cannot tell, and it says so |

timebase.recordedTakeTiming is true, false, or null — and null means nobody could tell, never no.

Two facts it carries rather than rediscovers

  • The capture declares no units. Its own field ledger says the channel semantic map is absent, so every number comes back bare. The music is built from ratios, so nothing is lost — a unit invented here would be a claim nobody can support. heading.turnDegrees is the one honest exception: a difference of an unwrapped heading is a ratio of angles.
  • sextants does not need an unwrapped heading. It takes the heading modulo a turn, so wrapped and unwrapped input give the identical sequence — measured, against a widely-repeated claim to the contrary. unwrapHeading stays mandatory for reading the heading as a path: on a synthetic turn the raw channel reports +331° where the body turned −29°.

Specification of record: rispecs/movement-conductor.spec.md in miadisabelle/gmtermux.