@kieransimkin/dance-rudiments 0.2.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -7,3 +7,75 @@
7
7
  - Keep credentials, account data, private media and rights records out of source, fixtures, logs and packages. Use synthetic fixtures or explicitly authorised public examples and preserve their provenance/licences.
8
8
  - Use [CONTRIBUTING.md](CONTRIBUTING.md) for review. Maintainers publish accepted, validated improvements as a fresh matching GitHub release and verify configured registry destinations. Preserve existing tags and release assets; publication and deployment remain subject to applicable authorisation.
9
9
  - Website: https://kieransimkin.co.uk/danceflow/
10
+
11
+ ## Keep README documentation current
12
+
13
+ - Whenever a feature is added or changed, update the relevant README.md in the same change to reflect the resulting behaviour. This applies to every feature addition or modification, including APIs, commands, configuration, defaults, integrations and removals.
14
+ - Update affected feature descriptions, usage instructions, options, examples and limitations. For tools or packages with their own README.md, update that README as well as the repository README when its overview or usage is affected.
15
+ - Check the README against the implemented and verified behaviour before committing, opening or merging a PR, publishing a release or handing off the work. A feature change is incomplete until its README documentation is current; a changelog or other documentation does not replace this requirement.
16
+
17
+ ## Released viewers and coordinated CI/CD
18
+
19
+ - Read [docs/released-viewers.md](docs/released-viewers.md) before changing dependency, build or release behaviour. The sibling layout is `DanceRudiments/`, `react-timeline-sequence/`, and `stemlab/` under one parent.
20
+ - Release the two companions first (React Timeline Sequence, then DanceRudiments), verify their configured publication workflows and public registries, then synchronize/rebuild/test/release StemLab. A merge or tag alone is not a verified release.
21
+ - StemLab must target the **latest stable official releases**. No unreleased main commit, mutable development override, local `file:` archive or vendor package may substitute for a missing release. Latest is resolved before the build and locked to exact published versions, release commits and registry hashes for that run; fail visibly on stale or incompatible dependencies rather than falling back silently.
22
+ - Use the canonical `stemlab/scripts/Release-DanceFlow.ps1` coordinator from the shared parent directory. Preview first; `-Execute` explicitly performs scoped commits, normal pushes and fresh tags; `-Resume` must preserve source identities and existing tags/assets. Never force-push, move release tags, commit unrelated work, bypass failed checks or change approvals/protections/credentials to manufacture a pass.
23
+ - Update this repository's README.md and AGENTS.md in the same change whenever release policy, dependency rules, automation, commands, controls or validation change. Keep relevant package/feature READMEs current too. A separate guide or changelog does not replace the root README update.
24
+ - Preserve the master-plus-drums/percussion beat-routing contract, 64-pips-per-beat native recording clock, per-dimension bars and combined waveform/spectrogram lanes. New UI features must be supplied by released shared APIs and genuinely rebuilt frontend assets, not copied engines or marker strings.
25
+ - Distinguish source CI, package publication, full-song inference, browser/audio QA, artifact packaging, actual Pages deployment and live URL/audio verification. Keep all four Arcadians pages together; do not report unexecuted, skipped or older-commit checks as success. CI playback evidence is not subjective listening QA.
26
+
27
+ ## Full ecosystem and release preflight
28
+
29
+ Before every new workflow run, check the latest stable official release and observe the actual runtime used by the job. Follow [the shared preflight](https://github.com/kieransimkin/DanceFlow/blob/main/docs/workflows/release-preflight.md) and this project's [people-and-agent guide](docs/ECOSYSTEM.md). Review the complete relevant capability inventory rather than only a familiar command. Consider every DanceFlow component against the actual task; use and compose all applicable supported capabilities, and improve a concrete reusable gap in its canonical repository. Record why existing capabilities suffice when no change is justified. No catalogue checklist expands the task, authorises model downloads/training, or proves integration. Preserve exact source/package identity, clocks, model-local storage, privacy, costs, immutable releases and separate deployment gates.
30
+
31
+ ## Release mesh demos and Pages
32
+
33
+ - Read `docs/release-demo.md` and `docs/mesh-demos.md` before changing demo builds or deployment. Keep the root native visualizer and `meshes/` gallery together in `dist/pages`. `demo-release.yml` is the sole Pages publisher; main/PR `visualizer.yml` runs remain artifact-only and must not erase a released mesh route.
34
+ - Build from the exact validated tag and commit. Use tag pushes or manual dispatch for an existing compatible published tag; do not depend on a `release.published` event created with `GITHUB_TOKEN`. Old tags without the gallery cannot be retrofitted, moved or overwritten.
35
+ - Retain the `DANCERUDIMENTS_PAGES_ENABLED == 'true'` guard, `github-pages` environment, approvals and protections. Read Pages configuration without enabling or changing it. Only the latest stable official release may deploy, with a second latest-release check after waiting for the shared deployment concurrency slot. Older-tag attachment builds must report a Pages skip accurately.
36
+ - Keep original mesh geometry separate from captured source motion. The selected two-source builder may download only its explicitly requested, pinned files and must retain CMU/converter terms, hashes, units, axes and unverified musical timing. Optional motion files must remain outside the default catalogue and base package artifacts.
37
+ - Run `npm test`, `test_mesh_demo_assets.py`, `test_release_pages.py`, the existing native visualizer/MIDI browser gates, and `tools/test_mesh_demo_browser.py` for the complete site before sealing release assets. Preserve the shared native 64-pip sampler, exact profile bindings, lazy scene loading and resource disposal. A `--gallery-only` receipt is local evidence and cannot seal a complete release site.
38
+ - Bind browser evidence to every packaged site file and the exact release identity. Keep archives outside the Pages tree. Existing release assets are immutable: compare every collision before upload, retain identical bytes and refuse changed assets; never use `--clobber` for demo releases.
39
+ - Distinguish source tests, browser QA, sealed artifacts, attachment verification, actual Pages deployment and live route/asset verification. Check hosted precompressed motion bytes without HTTP content decoding. Do not report a successful main preview or older-commit deployment as a verified mesh release.
40
+
41
+ ## Rigify motion validation
42
+
43
+ For rig-motion changes, read `docs/rig-motion.md`, `docs/rigify-catalogue.md` and
44
+ `docs/motion-sources.md`. Keep native 64-pip playback and the existing normalized
45
+ Recording contract; do not introduce another live sampler. Preserve each saved
46
+ profile's numbered channels and fingerprint. Regenerate built-in profiles only
47
+ with the explicitly pinned Blender/Rigify source, and label contextual components
48
+ and custom rigs accurately. Run the `test_motion*.py` and `test_rig*.py` suites
49
+ and `tools/test_blender_rigify_bridge.py` in the pinned `bpy` environment for
50
+ Blender-facing changes. For interchange changes, also run
51
+ `tools/test_blender_motion_imports.py --output-dir .cache/blender-imports`.
52
+ The `Rigify motion` workflow supplies that optional
53
+ integration gate. Use synthetic fixtures; research catalogue entries do not
54
+ authorize downloading or bundling third-party motion, models or media.
55
+
56
+ ## Optional motion packages
57
+
58
+ Read `docs/motion-packages.md` and `docs/blender-motion-import.md` for changes to
59
+ optional model recordings. Keep motion payloads in ignored `motion-packs/`,
60
+ outside base npm/Python/native artifacts and the default catalogue. Do not add
61
+ automatic downloads, global data registration or a second live sampler.
62
+ Source-package downloads require task authorization and source-specific rights;
63
+ retain licence, attribution, source hash and conversion changes with every pack.
64
+ Never label a source skeleton as a Rigify retarget or time-only data as musical
65
+ beat alignment. Preserve complete-action pip bounds and distinguish action counts
66
+ from chunk counts.
67
+
68
+ Run `test_motion_packages.py`, `test_bvh_import.py`, the TypeScript package/page
69
+ tests via `npm test`, and the existing rig/recording tests. Blender import changes
70
+ also require `tools/test_blender_motion_batch.py` in the pinned runtime. The
71
+ `motion-import` extra supplies NumPy only for offline BVH conversion. Verify
72
+ base-package file lists exclude generated motion data before packaging; npm's
73
+ separate recording WASM asset must match its checked-in source hashes.
74
+
75
+ ## Preflight temporary-directory access
76
+
77
+ Before any long, costly, model-backed, media-rendering, build, test, packaging or release command that creates private or atomic temporary directories, run a disposable preflight with the exact runtime, user or sandbox, and intended output parent. The probe must create a unique directory, write and read a file, atomically rename it, then remove the file and directory.
78
+
79
+ Keep temporary data and caches under the owning project on `Z:`; model weights and model-specific caches remain under that project's ignored `models/`. If the probe returns `WinError 5`, access denied, a rename failure or a cleanup failure, stop before the expensive command. Preserve the exact error and use the documented narrowly approved unrestricted recovery from the outset only when the task requires it. Use a fresh output directory and do not repeat the already-failing full job in the restricted shell.
80
+
81
+ After any unrestricted recovery, verify that the final output is readable and writable from the normal managed environment. If it is not, copy the completed bytes into a pre-created project-local directory that passed the probe, verify hashes, and retain the original failure and recovery evidence. Do not edit global ACLs, switch caches to `C:`, terminate unrelated processes or claim the underlying permission problem is fixed. Repositories that own temporary-directory creation should provide and test a reusable preflight helper rather than relying only on this instruction.
package/CONTRIBUTING.md CHANGED
@@ -10,3 +10,11 @@ Agents and people are welcome to improve DanceRudiments. Review its current capa
10
10
  Maintainers review accepted changes, reserve a fresh version and publish a matching GitHub release from the validated source. They verify installable assets, checksums and each configured registry separately. Existing tags and release assets remain immutable. A submitted PR is a contribution awaiting review, not a published release or permission for unrelated deployment.
11
11
 
12
12
  Website: [https://kieransimkin.co.uk/danceflow/](https://kieransimkin.co.uk/danceflow/).
13
+
14
+ ## Before every new workflow
15
+
16
+ Check the latest stable official release and the actual installed/imported version before starting; do not infer currency from a directory name or a development checkout. Read the current release notes, tagged capability documentation and relevant Potential problems. Use the [DanceFlow release preflight](https://github.com/kieransimkin/DanceFlow/blob/main/docs/workflows/release-preflight.md) and [complete capability references](https://github.com/kieransimkin/DanceFlow/blob/main/docs/capabilities/index.md).
17
+
18
+ People and agents should consider the full ecosystem, use all capabilities that materially serve the task, compose supported files/APIs, and improve a demonstrated reusable gap in its canonical tool. Record why no worthwhile change is justified when that is the result. Keep independent tool identities, compatibility, source clocks, privacy, model/download costs and publication/deployment permissions intact. Store weights and model-specific caches in the owning project's ignored `models/`.
19
+
20
+ Read [the people-and-agent ecosystem guide](docs/ECOSYSTEM.md) before selecting or extending a tool.
package/README.md CHANGED
@@ -13,18 +13,21 @@ By **[Kieran Simkin — My Songs](https://kieransimkin.co.uk/my-songs/)** · Par
13
13
 
14
14
  <a id="visualizer"></a>
15
15
 
16
+ ## Before every new workflow
16
17
 
17
- ## Agents and contributors
18
+ Check the latest stable official release and the actual installed/imported version before starting; do not infer currency from a directory name or a development checkout. Read the current release notes, tagged capability documentation and relevant Potential problems. Use the [DanceFlow release preflight](https://github.com/kieransimkin/DanceFlow/blob/main/docs/workflows/release-preflight.md) and [complete capability references](https://github.com/kieransimkin/DanceFlow/blob/main/docs/capabilities/index.md).
18
19
 
19
- Agents using DanceRudiments should inspect its available capabilities, use them fully where they fit the task, and look for useful improvements wherever possible. When a required feature is missing, or a reusable reliability, usability, performance or documentation gap is found, improve this tool rather than maintaining a separate workaround. If no worthwhile change is justified, explain why.
20
+ People and agents should consider the full ecosystem, use all capabilities that materially serve the task, compose supported files/APIs, and improve a demonstrated reusable gap in its canonical tool. Record why no worthwhile change is justified when that is the result. Keep independent tool identities, compatibility, source clocks, privacy, model/download costs and publication/deployment permissions intact. Store weights and model-specific caches in the owning project's ignored `models/`.
20
21
 
21
- Submit every improvement as a pull request to [DanceRudiments](https://github.com/kieransimkin/DanceRudiments/pulls), with relevant tests, documentation and a reproducible example. Follow [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) for the contribution and validation workflow.
22
+ ## Find your route
22
23
 
23
- Project website: [https://kieransimkin.co.uk/danceflow/](https://kieransimkin.co.uk/danceflow/).
24
+ [▶ Try the pattern visualizer](#-try-the-pattern-visualizer) · [3D dance examples](#3d-dance-examples) · [Which package should I use?](#which-package-should-i-use) · [Included rudiments](#included-rudiments) · [Default collections](#default-collections) · [Dancefloor 06](#dancefloor-06) · [BPM-synchronised N-dimensional recordings and comparison harness](#bpm-synchronised-n-dimensional-recordings-and-comparison-harness) · [Rigify character motion](#rigify-character-motion) · [Curve and event authoring](#curve-and-event-authoring) · [Language bindings](#language-bindings) · [Harness](#harness)
24
25
 
25
26
  ## ▶ Try the pattern visualizer
26
27
 
27
- **[Download the self-contained visualizer — HTML](https://github.com/kieransimkin/DanceRudiments/raw/refs/heads/main/harness/index.html)**
28
+ **[▶ Open the movement visualiser](https://kieransimkin.github.io/DanceRudiments/)**
29
+
30
+ [Download the self-contained HTML for offline use](https://github.com/kieransimkin/DanceRudiments/raw/refs/heads/main/harness/index.html)
28
31
 
29
32
  Save the file and open it in a browser. **No install, server, CDN, soundfont or
30
33
  separate WASM file is required.** The complete 1,731-movement catalogue includes a
@@ -38,19 +41,77 @@ together. Compare any movements, or use **Only matching movements** and
38
41
  Sound is synthesised from note events, not the original Amen recording.
39
42
 
40
43
  The downloadable file is the checked-in snapshot; the **Pattern visualizer**
41
- workflow also rebuilds a fresh version from every pushed native catalogue.
44
+ workflow also rebuilds and tests a fresh artifact from every pushed native catalogue.
45
+ The **Release demo** workflow publishes the complete tagged site, including the
46
+ 3D examples below, when Pages is enabled. Main-branch visualizer builds do not
47
+ replace that released site.
42
48
  [Beat player, rebuilding, release downloads and optional live hosting](docs/midi-harness.md).
43
49
 
44
- [![Four Amen-based movements compared in the real self-contained visualizer](https://raw.githubusercontent.com/kieransimkin/DanceRudiments/main/docs/images/visualizer-amen-desktop.png)](https://github.com/kieransimkin/DanceRudiments/raw/refs/heads/main/harness/index.html)
50
+ [![Four Amen-based movements compared in the real self-contained visualizer](https://raw.githubusercontent.com/kieransimkin/DanceRudiments/main/docs/images/visualizer-amen-desktop.png)](https://kieransimkin.github.io/DanceRudiments/)
45
51
 
46
52
  *Captured from the running C++/WebAssembly visualizer at beat 2.75. Audio was not started during this screenshot.*
47
53
 
54
+ ## 3D dance examples
55
+
56
+ The release build adds a separate **`meshes/` gallery** beside the pattern
57
+ visualizer. It contains two original low-poly skinned characters with different
58
+ captured dances:
59
+
60
+ | Character | Movement | Source recording |
61
+ | --- | --- | --- |
62
+ | Boxbot | Salsa | CMU 60_01, with the documented 60 fps source timing restored |
63
+ | Prism | Ballet: attitude, arabesque, turning jump and back bend | CMU 05_18 |
48
64
 
65
+ Each character has its own optional motion package and independently bound rig
66
+ profile. Loading a scene fetches only its own rig, profile and selected recording
67
+ chunk. Play, pause, seek, restart and playback-rate controls use the existing
68
+ native C++/WASM sampler. Unloading releases that scene's requests, recordings and
69
+ GPU resources. The gallery uses actual weighted triangle meshes; no model or
70
+ motion data is added to the base package or the site's pattern page.
49
71
 
50
- DanceRudiments is a C++17 library of deterministic rhythmic position functions. One integer pip is `1/64` of a beat. Built-in and custom patterns each keep their own loop period. Every sampler wraps positive or negative input into its own loop before sampling.
72
+ These are complete source recordings with **original timing**, including their
73
+ calibration frame. They have no verified musical beat/downbeat annotations and
74
+ are not presented as beat-matched to a song. The CMU source terms, attribution,
75
+ source hashes and conversion details accompany the examples.
76
+
77
+ The release workflow builds and browser-tests both characters, attaches a
78
+ separate gallery ZIP and a complete-site ZIP, and deploys the existing visualizer
79
+ and gallery together. Pages must already use GitHub Actions with
80
+ `DANCERUDIMENTS_PAGES_ENABLED=true`; environment approvals remain in effect.
81
+ The gallery becomes live at
82
+ [`https://kieransimkin.github.io/DanceRudiments/meshes/`](https://kieransimkin.github.io/DanceRudiments/meshes/)
83
+ after the first successful release containing these tools. Applying source
84
+ changes alone does not deploy the website. See [building and validating the
85
+ mesh demos](docs/mesh-demos.md) and the [release workflow guide](docs/release-demo.md).
86
+
87
+
88
+
89
+ DanceRudiments is a C++17 library of deterministic rhythmic position functions. One integer pip is `1/64` of a beat. Built-in and custom patterns each keep their own loop period. Every legacy pattern sampler wraps positive or negative input into its own loop before sampling.
51
90
 
52
91
  Outputs are dimensionless offsets, normally in `[-1, 1]`. The caller chooses pixels, CSS units, metres, or another scale. There is deliberately no time interpolation in the public API: renderers advance with integer pips and get one exact sample per pip.
53
92
 
93
+ ## Which package should I use?
94
+
95
+ | You are building | Install or download | What you get |
96
+ | --- | --- | --- |
97
+ | C# / .NET application | `dotnet add package DanceRudiments` from [NuGet.org](https://www.nuget.org/packages/DanceRudiments) after its first release | Managed .NET 8+ wrapper and x64/ARM64 native assets for Windows, Linux and macOS |
98
+ | Python application | `pip install dancerudiments` from [PyPI](https://pypi.org/project/dancerudiments/) | Native Python extension and the catalogue/sample API |
99
+ | TypeScript or JavaScript application | `npm install @kieransimkin/dance-rudiments` from [npm](https://www.npmjs.com/package/@kieransimkin/dance-rudiments) | TypeScript declarations, JavaScript wrapper, and WebAssembly module |
100
+ | C++ application using a listed release platform | Download the matching `DanceRudiments-cpp-<version>-<platform>-static.zip` from [GitHub Releases](https://github.com/kieransimkin/DanceRudiments/releases) | Headers, static library, CMake package files, licence, platform manifest, and instructions |
101
+ | C++ application using another toolchain or architecture | Build from source or use `conan create` with `conanfile.py` | A library compiled for your own settings |
102
+
103
+ GitHub automatically adds “Source code” ZIP and tar.gz links to every release; those are repository snapshots, not precompiled packages. Python wheels belong on PyPI, the C# package on NuGet.org (mirrored to GitHub Packages), and the TypeScript/WASM package on npm, while GitHub release attachments include C++ archives and the separately generated HTML demos, screenshots and checksums.
104
+
105
+ ## Included rudiments
106
+
107
+ The general motions are `bounce`, `sway`, `circle`, `figure_eight`, `step_touch`, `box_step`, `helix`, and `clay_background`.
108
+
109
+ The first drum-derived set is `single_stroke_roll`, `multiple_bounce_roll`, `double_stroke_roll`, `single_paradiddle`, `flam`, `drag`, and `five_stroke_roll`. The first six mirror the fundamentals in Vic Firth's Tier One learning sequence and collectively cover the roll, diddle, flam, and drag families in the Percussive Arts Society's 40 International Drum Rudiments. A right-hand stroke moves right, a left-hand stroke moves left, and both rise slightly. Every stroke is a raised-cosine (`sin²`) gesture: zero displacement at the start, smooth attack, a rounded peak, and smooth decay back to zero before the next motion. Accents use greater amplitude rather than an instantaneous position jump.
110
+
111
+ Source references: [Percussive Arts Society International Drum Rudiments](https://pas.org/rudiments/) and [Vic Firth 40 Essential Rudiments](https://ae.vicfirth.com/education/40-essential-rudiments/), accessed 28 September 2026.
112
+
113
+ `clay_background` preserves the translation waypoints from the Clay/Stars `ks-particle-dance` background treatment as a normalized 256-pip lookup table. The source effect's opacity, rotation, and scale are not position offsets, so they are intentionally excluded.
114
+
54
115
  ## Default collections
55
116
 
56
117
  The default catalogue contains **1,731 movements**: 15 original routines, 28 Initial 01,
@@ -87,6 +148,124 @@ python tools/build_default_catalogue.py --check
87
148
  The release workflow builds the complete native catalogue demo plus an offline,
88
149
  audio-enabled 68-rhythm / 16-mapping comparison page. All live motion comes from C++/WASM.
89
150
 
151
+ ## BPM-synchronised N-dimensional recordings and comparison harness
152
+
153
+ The additive `dancerudiments.recording` format stores **any number of named
154
+ float64 dimensions** at **64 pips per beat**, with a mandatory BPM estimate or
155
+ confirmed value and separate beat-phase provenance. `SampledRecording` provides
156
+ native non-looping C++/Python playback, including captures beyond the old
157
+ 65,535-pip loop length; existing XYZ patterns and their wrapping rules are unchanged.
158
+
159
+ ```python
160
+ from dancerudiments_authoring import load_recording
161
+ from dancerudiments_authoring.harness import build_recording_harness
162
+ r = load_recording("output/recordings/audio_recording.json")
163
+ values = r.to_native().sample(r.clock.start_pip) # every dimension, real C++
164
+ build_recording_harness([r], "output/index.html")
165
+ ```
166
+
167
+ The exported page uses **the same packaged visualizer assets as catalogue/release
168
+ pages**, with native WASM sampling, shared transport, four-card comparison and
169
+ review import/export. Recording mode adds arbitrary-axis X/Y/Z selection, locked
170
+ BPM/origin and non-looping completion. The tiny generic WASM sampler is bundled;
171
+ no compiler or CDN is needed at export time. StemLab's `record-rudiment` and
172
+ `generate-batch` produce individual or varied stem/filter combinations using this
173
+ API without copying it. Music is not bundled unless explicitly requested.
174
+
175
+ See **[recording format, harness, native API and compatibility](docs/recordings.md)**.
176
+ Build the updated source to use this unreleased API; earlier releases lack it.
177
+
178
+ ## Rigify character motion
179
+
180
+ Typed rig motions now bind the native N-dimensional recording sampler to **Blender
181
+ Rigify character controls**. The pinned Blender **5.2.2 LTS** catalogue covers all
182
+ **eight built-in metarig presets** and **28 rig component types**, with numbered
183
+ channel manifests generated from actual rigs. Each channel identifies its bone,
184
+ property, component, physical units, range, neutral value and interpolation.
185
+ The [catalogue guide](docs/rigify-catalogue.md) records exact counts and any
186
+ component context; custom/generated characters can export their own profiles.
187
+
188
+ Model types use a hierarchy such as
189
+ `syn://type/danceflow/motion/rigify/metarig/human` and
190
+ `syn://type/danceflow/motion/rigify/component/limbs/arm`.
191
+ `synny://` is an equivalent spelling, not another type. Channel numbers persist
192
+ across explicit profile extensions; profile hashes prevent applying a recording
193
+ to an incompatible skeleton, rest basis or control layout.
194
+
195
+ ```sh
196
+ python tools/rig_motion.py catalogue
197
+ python tools/rig_motion.py profile human --output generated/human.profile.json
198
+ python tools/rig_motion.py channels generated/human.profile.json --output generated/human.channels.csv
199
+ python examples/rig-motion/quickstart.py --output generated/rig-motion --native
200
+ ```
201
+
202
+ The installed CLI is `dancerudiments-rig`. The optional Blender bridge imports
203
+ local **BVH, FBX and glTF/GLB**, captures animation already retargeted/baked onto
204
+ Rigify controls, and applies or bakes motion using the actual native sampler.
205
+ `dancerudiments.rig-motion` combines an exact profile with the unchanged normalized
206
+ Recording format: float64 `[-1,1]`, 64 pips/beat, explicit bounds and non-looping
207
+ playback. Scalar controls interpolate linearly during authoring, quaternion
208
+ groups use shortest-path SLERP, and discrete switches hold their values.
209
+
210
+ Source BPM/phase or measured beat anchors control compilation. A separate target
211
+ beat map permits variable-tempo playback, absolute seeking and explicit
212
+ half/double-time without accumulating frame-clock drift. The existing XYZ
213
+ catalogue and C++ playback engine remain the movement authority.
214
+
215
+ Read the **[complete rig-motion guide](docs/rig-motion.md)** for capture, compile,
216
+ native playback, Blender baking, actual model mappings and compatibility. The
217
+ **[motion-source research](docs/motion-sources.md)** records motion libraries and
218
+ their format/licence/access constraints. The
219
+ **[Blender import guide](docs/blender-motion-import.md)** covers multiple Actions,
220
+ source-skeleton reconstruction and explicit Rigify FK mappings. Musical beat
221
+ detection and foot-contact/transition repair remain separate authoring steps.
222
+ The dedicated **Rigify motion** CI checks native playback and an
223
+ actual skinned mesh using the pinned Blender runtime. These APIs require this
224
+ development revision until a new stable package is released.
225
+
226
+ ### Optional model-specific motion packages
227
+
228
+ Large character recordings are **independent optional packages**. They are not
229
+ added to the 1,731 default rudiments, fetched at startup or loaded site-wide.
230
+ Each package shares one exact numbered rig profile and stores individual
231
+ compressed recordings with hashes, timing, source attribution and licence.
232
+ Only the selected page or scene loads its requested clips.
233
+
234
+ The new TypeScript `./motion-packages` subpath provides a lazy, scene-owned loader
235
+ and the existing native C++/WASM recording accessor. The
236
+ [page lifecycle example](examples/motion-packages/page-motion.mjs) follows the
237
+ host's integer beat clock, keeps one recording chunk loaded, handles seeking and
238
+ releases requests/memory on route exit. Rig application remains the consuming
239
+ scene's responsibility; the existing XYZ visualizer does not become a mesh renderer.
240
+
241
+ Python provides `MotionPackage`, `MotionPackageBuilder` and the explicit
242
+ `dancerudiments-motion-pack` install/inspect/export CLI. Offline BVH import uses
243
+ the optional `motion-import` extra; the base package does not acquire NumPy or
244
+ Blender dependencies. Public source plans and reproducible import tools produce
245
+ external data under ignored `motion-packs/`; the base npm/Python/native packages
246
+ exclude those assets.
247
+
248
+ Reproducible source recipes cover ACCAD human actions, 100STYLE locomotion,
249
+ Lifelike Agility dog captures, Space-XR dance/movement recordings, a deduplicated
250
+ CMU dance subset and all 14
251
+ Actions of Quaternius' CC0 robot. The [source plan index](motion-packages/README.md)
252
+ records separate data terms and acquisition commands. A collection can be large
253
+ without increasing the base package or its startup work.
254
+
255
+ ```sh
256
+ python -m pip install '.[motion-import]'
257
+ python tools/import_motion_collection.py download --sources accad
258
+ python tools/import_motion_collection.py build --sources accad
259
+ python tools/motion_package.py list --root ./motion-packs
260
+ ```
261
+
262
+ Complete source actions can span contiguous bounded chunks. Unknown musical
263
+ timing is labelled **time-only**: a 60 BPM seconds coordinate is not an observed
264
+ music tempo. Supply source tempo and beat phase or measured beat anchors before
265
+ claiming musical alignment. The [optional-package guide](docs/motion-packages.md)
266
+ describes formats, hosting, exact profile compatibility, source conventions,
267
+ native playback and separate package licences.
268
+
90
269
  ## Curve and event authoring
91
270
 
92
271
  The optional **Python authoring tools** compile LFOs, segmented curves, sampled
@@ -106,38 +285,6 @@ formats, event anchoring, loop validation, generated functions, Python playback,
106
285
  WASM loading, provenance and testing. These are original infrastructure examples,
107
286
  not imported third-party preset banks.
108
287
 
109
- ## DanceFlow ecosystem
110
-
111
- DanceRudiments is the reusable motion-vocabulary layer in Kieran Simkin's DanceFlow BPM and motion-response ecosystem:
112
-
113
- - **StemLab** is the music-understanding layer. It analyses audio to produce BPM, beat, structure, stem, lyric, harmony, and related timing evidence.
114
- - **DanceRudiments** turns integer musical positions at 64 pips per beat into deterministic 1D, 2D, or 3D position offsets.
115
- - **DanceMoves** is the WordPress EPK motion runtime. It schedules and applies BPM-, cue-, and lyric-timed effects on public pages.
116
-
117
- The three components can also be used independently. They exchange explicit timing and analysis data rather than depending directly on one another. DanceRudiments' 64-pips-per-beat sampling convention is intentionally higher resolution and is not the same unit as DanceMoves' 16-ticks-per-beat runtime clock.
118
-
119
- ## Which package should I use?
120
-
121
- | You are building | Install or download | What you get |
122
- | --- | --- | --- |
123
- | C# / .NET application | `dotnet add package DanceRudiments` from [NuGet.org](https://www.nuget.org/packages/DanceRudiments) after its first release | Managed .NET 8+ wrapper and x64/ARM64 native assets for Windows, Linux and macOS |
124
- | Python application | `pip install dancerudiments` from [PyPI](https://pypi.org/project/dancerudiments/) | Native Python extension and the catalogue/sample API |
125
- | TypeScript or JavaScript application | `npm install @kieransimkin/dance-rudiments` from [npm](https://www.npmjs.com/package/@kieransimkin/dance-rudiments) | TypeScript declarations, JavaScript wrapper, and WebAssembly module |
126
- | C++ application using a listed release platform | Download the matching `DanceRudiments-cpp-<version>-<platform>-static.zip` from [GitHub Releases](https://github.com/kieransimkin/DanceRudiments/releases) | Headers, static library, CMake package files, licence, platform manifest, and instructions |
127
- | C++ application using another toolchain or architecture | Build from source or use `conan create` with `conanfile.py` | A library compiled for your own settings |
128
-
129
- GitHub automatically adds “Source code” ZIP and tar.gz links to every release; those are repository snapshots, not precompiled packages. Python wheels belong on PyPI, the C# package on NuGet.org (mirrored to GitHub Packages), and the TypeScript/WASM package on npm, while GitHub release attachments include C++ archives and the separately generated HTML demos, screenshots and checksums.
130
-
131
- ## Included rudiments
132
-
133
- The general motions are `bounce`, `sway`, `circle`, `figure_eight`, `step_touch`, `box_step`, `helix`, and `clay_background`.
134
-
135
- The first drum-derived set is `single_stroke_roll`, `multiple_bounce_roll`, `double_stroke_roll`, `single_paradiddle`, `flam`, `drag`, and `five_stroke_roll`. The first six mirror the fundamentals in Vic Firth's Tier One learning sequence and collectively cover the roll, diddle, flam, and drag families in the Percussive Arts Society's 40 International Drum Rudiments. A right-hand stroke moves right, a left-hand stroke moves left, and both rise slightly. Every stroke is a raised-cosine (`sin²`) gesture: zero displacement at the start, smooth attack, a rounded peak, and smooth decay back to zero before the next motion. Accents use greater amplitude rather than an instantaneous position jump.
136
-
137
- Source references: [Percussive Arts Society International Drum Rudiments](https://pas.org/rudiments/) and [Vic Firth 40 Essential Rudiments](https://ae.vicfirth.com/education/40-essential-rudiments/), accessed 28 September 2026.
138
-
139
- `clay_background` preserves the translation waypoints from the Clay/Stars `ks-particle-dance` background treatment as a normalized 256-pip lookup table. The source effect's opacity, rotation, and scale are not position offsets, so they are intentionally excluded.
140
-
141
288
  ## Language bindings
142
289
 
143
290
  All four language interfaces sample the **same C++ runtime**. Choose the interface, not
@@ -152,7 +299,7 @@ another movement implementation. The examples below are checked into
152
299
  | TypeScript / JavaScript | `catalogue` (an array, not a function) | `sample(name, pip)` after `bindNative()` | `info.periodPips` | Call the custom bank's `dispose()` |
153
300
 
154
301
  **One beat is 64 pips.** Supply a signed 32-bit integer, not milliseconds or a
155
- floating-point beat number. Every sampler wraps negative as well as positive
302
+ floating-point beat number. Every legacy pattern sampler wraps negative as well as positive
156
303
  positions into its own loop. Offsets are `{x, y, z}`, dimensionless and bounded to
157
304
  `[-1, 1]`; choose the pixel/metre scale in your application. There is no automatic
158
305
  interpolation, BPM detection or audio playback inside a binding.
@@ -485,6 +632,34 @@ after installing this checkout's native extension. The builder also needs
485
632
  `clang++` and `wasm-ld`; screenshot automation needs Playwright/Chromium. Those
486
633
  are build-time requirements, not dependencies of the downloaded HTML.
487
634
 
635
+ ## DanceFlow ecosystem
636
+
637
+ DanceRudiments is the reusable motion-vocabulary layer in Kieran Simkin's DanceFlow BPM and motion-response ecosystem:
638
+
639
+ - **StemLab** is the music-understanding layer. It analyses audio to produce BPM, beat, structure, stem, lyric, harmony, and related timing evidence.
640
+ - **DanceRudiments** turns integer musical positions at 64 pips per beat into deterministic 1D, 2D, or 3D position offsets.
641
+ - **DanceMoves** is the WordPress EPK motion runtime. It schedules and applies BPM-, cue-, and lyric-timed effects on public pages.
642
+
643
+ The three components can also be used independently. They exchange explicit timing and analysis data rather than depending directly on one another. DanceRudiments' 64-pips-per-beat sampling convention is intentionally higher resolution and is not the same unit as DanceMoves' 16-ticks-per-beat runtime clock.
644
+
645
+ ## Motion safety
646
+
647
+ Apply an output to a bounded subject. DanceRudiments changes position only; it must not be used to add a repetitive full-frame tint, brightness, flash, or colour-grade effect. Under `prefers-reduced-motion`, do not autoplay the harness or production motion.
648
+
649
+ ## Troubleshooting history
650
+
651
+ See [build and release troubleshooting](docs/troubleshooting.md) for prior failures, causes and fixes.
652
+
653
+ ### Switch the shared visualizer between trajectories and bars
654
+
655
+ Use **Movement view → X–Y plot / Bar graph**. Bar view uses the same native
656
+ C++/WebAssembly sample and the existing clock, shows **every dimension** as a
657
+ separate signed bar, and keeps comparison cards on one common scale. Switching
658
+ views does not interrupt playback or change the underlying recording. The
659
+ selection is local to your browser; long dimension sets scroll horizontally.
660
+ This applies to catalogue/release pages and recording harnesses exported by
661
+ StemLab. Rebuild old generated pages to include the control. See
662
+ [recording visualizer controls](docs/recordings.md#trajectory-or-all-dimension-bars).
488
663
 
489
664
  ## Continuous integration and releases
490
665
 
@@ -523,10 +698,51 @@ One-time registry configuration is required before the first release:
523
698
 
524
699
  The PyPI publishing job requests short-lived OIDC identity. npm can use Trusted Publishing when configured; the workflow retains `NPM_TOKEN` as a bootstrap/fallback credential. See the official [PyPI Trusted Publisher](https://docs.pypi.org/trusted-publishers/using-a-publisher/) and [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/) documentation.
525
700
 
526
- ## Motion safety
701
+ ## Coordinated releases and latest-release dependencies
527
702
 
528
- Apply an output to a bounded subject. DanceRudiments changes position only; it must not be used to add a repetitive full-frame tint, brightness, flash, or colour-grade effect. Under `prefers-reduced-motion`, do not autoplay the harness or production motion.
703
+ Keep `DanceRudiments`, `react-timeline-sequence`, and `stemlab` as sibling
704
+ checkouts. The release order is **React Timeline Sequence → DanceRudiments →
705
+ StemLab**: publish and verify the companions before updating the consuming app.
706
+ StemLab must use their **latest stable official releases**, not an unreleased
707
+ commit, sibling source package or vendored npm archive. Each build records exact
708
+ released versions/commits/integrity after latest-release resolution so all its
709
+ jobs use the same bytes; CI fails clearly when that snapshot is stale.
529
710
 
530
- ## Troubleshooting history
711
+ From the parent folder, preview and then explicitly execute:
531
712
 
532
- See [build and release troubleshooting](docs/troubleshooting.md) for prior failures, causes and fixes.
713
+ ```powershell
714
+ .\stemlab\scripts\Release-DanceFlow.ps1 -ProjectsRoot .
715
+ .\stemlab\scripts\Release-DanceFlow.ps1 -ProjectsRoot . -Execute
716
+ ```
717
+
718
+ For the first migration use the same commands with
719
+ `.\release-kit\Release-DanceFlow.ps1` after extracting the complete kit. It
720
+ applies the three repository patches, updates versions, performs scoped commits
721
+ and normal pushes, waits for exact-commit CI, then creates **new** release tags.
722
+ The existing GitHub Actions workflows publish packages; no protection rules,
723
+ credentials, old tags or assets are changed. The initial expected next-minor
724
+ versions are only a preview proposal, never a claim that they are published.
725
+
726
+ Use Node.js 24, Python 3.11+, PowerShell 5.1+, Git and authenticated GitHub CLI.
727
+ Required main/registry/Pages jobs must pass; missing approvals and partial
728
+ publication are blockers, not success. The default script releases all three
729
+ projects, is opt-in via `-Execute`, and supports a saved exact-source `-Resume`
730
+ session. A changed checkout or pre-commit build failure requires review rather
731
+ than an automatic stash/reset or guessed recovery.
732
+
733
+ StemLab's helper updates npm manifests/lock, optional native dependency minimum,
734
+ release/build metadata and the genuinely rebuilt JS/CSS together. Its daily
735
+ release-update workflow proposes subsequent updates by PR without auto-merging.
736
+ A tagged StemLab release generates all four Arcadians pages and validates actual
737
+ Pages deployment, live HTML and seekable audio. Do not start a duplicate manual
738
+ Arcadians analysis during that tagged build. Read
739
+ **[the full release, resume, verification and troubleshooting guide](docs/released-viewers.md)**
740
+ before running it. Keep this README and AGENTS.md synchronized with future changes.
741
+
742
+ ## Agents and contributors
743
+
744
+ Agents using DanceRudiments should inspect its available capabilities, use them fully where they fit the task, and look for useful improvements wherever possible. When a required feature is missing, or a reusable reliability, usability, performance or documentation gap is found, improve this tool rather than maintaining a separate workaround. If no worthwhile change is justified, explain why.
745
+
746
+ Submit every improvement as a pull request to [DanceRudiments](https://github.com/kieransimkin/DanceRudiments/pulls), with relevant tests, documentation and a reproducible example. Follow [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) for the contribution and validation workflow.
747
+
748
+ Project website: [https://kieransimkin.co.uk/danceflow/](https://kieransimkin.co.uk/danceflow/).
Binary file
@@ -0,0 +1,5 @@
1
+ {
2
+ "tools/recording_wasm.cpp": "f4713cc7c773fa065715383fc68dccd91398fff08cd89167c5f24e64c0cecea9",
3
+ "include/dancerudiments/recording_view.hpp": "19dd73a150a82c4d9074fe4b9ba4c2f09d41e206028a6a6dc922d94e00dc4b8d",
4
+ "wasm_sha256": "d4cd976156860aa7a5c9665b27d2fda3cf6a0fa0da3dc0b9df365e425f1c6e29"
5
+ }
@@ -1,4 +1,6 @@
1
1
  import { ApprovedDefaultName } from "./defaults.js";
2
+ export { createMotionPackageLoader, createRecordingWasmAdapter } from "./motion-packages.js";
3
+ export type { MotionJson, MotionJsonObject, MotionPackageAsset, MotionPackageClip, MotionPackageManifest, MotionRigChannel, MotionRigProfile, MotionRecordingClock, MotionRecording, NativeMotionRecording, NativeMotionRecordingFactory, MotionPackageTarget, MotionLoadOptions, MotionPackageLoaderOptions, LoadedRigMotion, MotionPackageLoader, } from "./motion-packages.js";
2
4
  export type Offset3 = Readonly<{
3
5
  x: number;
4
6
  y: number;
@@ -43,4 +45,3 @@ export type PatternLibraryHandle = Readonly<{
43
45
  }>;
44
46
  /** Load compiled JSON into a private C++ bank. No JavaScript motion fallback. */
45
47
  export declare function createPatternLibrary(document: unknown): PatternLibraryHandle;
46
- export {};
@@ -1,4 +1,5 @@
1
1
  import { approvedDefaults } from "./defaults.js";
2
+ export { createMotionPackageLoader, createRecordingWasmAdapter } from "./motion-packages.js";
2
3
  // Widen metadata before spreading thousands of literal records. Keep the name
3
4
  // union precise, without asking TypeScript to construct a huge object union.
4
5
  const generatedCatalogue = approvedDefaults;
@@ -0,0 +1,125 @@
1
+ /** Optional, scene-owned rig recordings. No assets are fetched at module import. */
2
+ export type MotionJson = null | boolean | number | string | readonly MotionJson[] | MotionJsonObject;
3
+ export type MotionJsonObject = {
4
+ readonly [key: string]: MotionJson;
5
+ };
6
+ export type MotionPackageAsset = Readonly<{
7
+ path: string;
8
+ sha256: string;
9
+ byte_length: number;
10
+ }>;
11
+ export type MotionPackageClip = MotionPackageAsset & Readonly<{
12
+ id: string;
13
+ decoded_byte_length: number;
14
+ encoding: "json" | "gzip";
15
+ start_pip: number;
16
+ sample_count: number;
17
+ metadata?: MotionJsonObject;
18
+ }>;
19
+ export type MotionPackageManifest = Readonly<{
20
+ format: "dancerudiments.motion-package";
21
+ schema_version: 1;
22
+ id: string;
23
+ version: string;
24
+ title: string;
25
+ type_uri: string;
26
+ profile_sha256: string;
27
+ dimensions: readonly string[];
28
+ profile: MotionPackageAsset;
29
+ clips: readonly MotionPackageClip[];
30
+ license: MotionJsonObject;
31
+ provenance: MotionJsonObject;
32
+ }>;
33
+ export type MotionRigChannel = Readonly<{
34
+ number: number;
35
+ name: string;
36
+ bone: string;
37
+ data_path: string;
38
+ array_index: number;
39
+ unit: string;
40
+ minimum: number;
41
+ maximum: number;
42
+ neutral: number;
43
+ value_type: "float" | "integer" | "boolean";
44
+ interpolation: "linear" | "step" | "quaternion";
45
+ rotation_mode: string;
46
+ enum_items: readonly (readonly [number, string])[];
47
+ }>;
48
+ export type MotionRigProfile = Readonly<{
49
+ format: "dancerudiments.rig-profile";
50
+ schema_version: 1;
51
+ type_uri: string;
52
+ model: string;
53
+ version: number;
54
+ channels: readonly MotionRigChannel[];
55
+ source: MotionJsonObject;
56
+ }>;
57
+ export type MotionRecordingClock = Readonly<{
58
+ bpm: number;
59
+ bpm_source: string;
60
+ bpm_status: "estimated" | "confirmed";
61
+ beat_zero_seconds: number;
62
+ phase_status: "unverified" | "estimated" | "supplied";
63
+ start_pip: number;
64
+ }>;
65
+ export type MotionRecording = Readonly<{
66
+ format: "dancerudiments.recording";
67
+ schema_version: 1;
68
+ pips_per_beat: 64;
69
+ sample_dtype: "float64";
70
+ sample_decimals: 12;
71
+ name: string;
72
+ dimensions: readonly string[];
73
+ clock: MotionRecordingClock;
74
+ samples: readonly (readonly number[])[];
75
+ provenance: MotionJsonObject;
76
+ }>;
77
+ export type NativeMotionRecording = Readonly<{
78
+ sample(pip: number): readonly number[];
79
+ dispose(): void;
80
+ }>;
81
+ export type NativeMotionRecordingFactory = (recording: MotionRecording, options: Readonly<{
82
+ signal: AbortSignal;
83
+ }>) => NativeMotionRecording | Promise<NativeMotionRecording>;
84
+ export type MotionPackageTarget = Readonly<{
85
+ typeUri: string;
86
+ sha256: string;
87
+ dimensions: readonly string[];
88
+ }>;
89
+ export type MotionLoadOptions = Readonly<{
90
+ signal?: AbortSignal;
91
+ }>;
92
+ export type MotionPackageLoaderOptions = Readonly<{
93
+ manifestUrl: string | URL;
94
+ packageId: string;
95
+ expectedProfile: MotionPackageTarget;
96
+ nativeFactory: NativeMotionRecordingFactory;
97
+ fetch?: typeof fetch;
98
+ manifestSha256?: string;
99
+ }>;
100
+ export type LoadedRigMotion = Readonly<{
101
+ id: string;
102
+ profile: MotionRigProfile;
103
+ profileSha256: string;
104
+ dimensions: readonly string[];
105
+ clock: MotionRecordingClock;
106
+ startPip: number;
107
+ sampleCount: number;
108
+ metadata: MotionJsonObject;
109
+ readonly disposed: boolean;
110
+ sampleNormalized(pip: number): readonly number[];
111
+ sample(pip: number): readonly (number | boolean)[];
112
+ }>;
113
+ export type MotionPackageLoader = Readonly<{
114
+ catalogue(options?: MotionLoadOptions): Promise<MotionPackageManifest>;
115
+ load(id: string, options?: MotionLoadOptions): Promise<LoadedRigMotion>;
116
+ unload(id: string): void;
117
+ dispose(): void;
118
+ }>;
119
+ /** Construct an inert loader owned by one page/scene. No global motion registry. */
120
+ export declare function createMotionPackageLoader(options: MotionPackageLoaderOptions): MotionPackageLoader;
121
+ /** Use the existing recording_wasm.cpp runtime, supplied explicitly by the app.
122
+ * Each clip owns an isolated WASM memory, released when its handle is disposed.
123
+ * Compilation/fetching of the module is an explicit caller operation.
124
+ */
125
+ export declare function createRecordingWasmAdapter(module: WebAssembly.Module): NativeMotionRecordingFactory;