dancerudiments 0.2.4__tar.gz → 0.3.0__tar.gz
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.
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.gitattributes +7 -0
- dancerudiments-0.3.0/.github/workflows/recordings.yml +55 -0
- dancerudiments-0.3.0/AGENTS.md +25 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/CMakeLists.txt +4 -1
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/PKG-INFO +87 -5
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/README.md +86 -4
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/DanceRudiments.csproj +1 -1
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/python/module.cpp +11 -0
- dancerudiments-0.3.0/docs/recordings.md +196 -0
- dancerudiments-0.3.0/docs/released-viewers.md +221 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/index.html +1 -1
- dancerudiments-0.3.0/include/dancerudiments/recording.hpp +54 -0
- dancerudiments-0.3.0/include/dancerudiments/recording_view.hpp +19 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/package-lock.json +2 -2
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/package.json +1 -1
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/pyproject.toml +2 -2
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/__init__.py +3 -1
- dancerudiments-0.3.0/python/dancerudiments_authoring/harness.py +128 -0
- {dancerudiments-0.2.4/tools/release_demo_assets → dancerudiments-0.3.0/python/dancerudiments_authoring/harness_assets}/app.js +173 -29
- dancerudiments-0.3.0/python/dancerudiments_authoring/harness_assets/recording.wasm.b64 +1 -0
- dancerudiments-0.3.0/python/dancerudiments_authoring/harness_assets/recording.wasm.json +5 -0
- {dancerudiments-0.2.4/tools/release_demo_assets → dancerudiments-0.3.0/python/dancerudiments_authoring/harness_assets}/style.css +13 -0
- {dancerudiments-0.2.4/tools/release_demo_assets → dancerudiments-0.3.0/python/dancerudiments_authoring/harness_assets}/template.html +1 -0
- dancerudiments-0.3.0/python/dancerudiments_authoring/harness_checks.py +70 -0
- dancerudiments-0.3.0/python/dancerudiments_authoring/recording.py +172 -0
- dancerudiments-0.3.0/tests/cpp/test_recording.cpp +26 -0
- dancerudiments-0.3.0/tests/python/test_harness_display.py +38 -0
- dancerudiments-0.3.0/tests/python/test_recording.py +126 -0
- dancerudiments-0.3.0/tests/python/test_recording_source_eol.py +39 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/typescript/beat-player.test.js +1 -1
- dancerudiments-0.3.0/tools/build_recording_wasm.py +29 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/export_harness_midi.mjs +1 -1
- dancerudiments-0.3.0/tools/recording_wasm.cpp +8 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/release_demo.py +7 -15
- dancerudiments-0.3.0/tools/test_recording_harness.py +157 -0
- dancerudiments-0.2.4/AGENTS.md +0 -9
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/ci.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/csharp.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/demo-release.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/initial-collection.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/nuget-verify.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/patterns.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/release-tag.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/release.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.github/workflows/visualizer.yml +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/.gitignore +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/AUTHORS.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/CHANGELOG.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/CONTRIBUTING.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/LICENSE +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/.gitignore +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/NativeMethods.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/Offset3.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/PatternDefinition.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/PatternLibrary.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/Rudiments.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/native/CMakeLists.txt +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/native/c_api.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/platforms.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/typescript/defaults.ts +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/typescript/index.ts +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/typescript/wasm.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/cmake/DanceRudimentsConfig.cmake.in +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/atlas/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/atlas/atlas.score.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/atlas/definitions.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/atlas/manifest.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/club/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/club/club.score.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/club/definitions.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/club/manifest.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/club/rhythms.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/club/sources.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/continuum/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/continuum/continuum.score.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/continuum/definitions.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/continuum/manifest.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/dancefloor/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/dancefloor/definitions.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/dancefloor/manifest.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/dancefloor/recipes.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/dancefloor/rhythms.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/dancefloor/sources.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/defaults.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/expansion/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/expansion/definitions.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/expansion/expansion.score.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/expansion/manifest.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/THIRD_PARTY_NOTICES.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/definitions.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/initial.score.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/manifest.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/preview_data.inc +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/preview_sampler.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/preview_wasm.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/sources/akwf/AKWF_0001_256.h +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/sources/akwf/AKWF_0010_256.h +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/sources/akwf/AKWF_R_asym_saw_05_256.h +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/sources/akwf/AKWF_R_asym_saw_15_256.h +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/sources/d3-ease/LICENSE +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/collections/initial/sources/groove/1_funk_80_beat_4-4.mid.b64 +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/conanfile.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/authoring.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/bindings.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/branding/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/branding/logo-monochrome.svg +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/branding/logo.png +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/branding/logo.svg +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/ci-reproducibility.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/csharp.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/dancefloor.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/default-library.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/images/capture.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/images/visualizer-amen-desktop.png +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/images/visualizer-midi-score.png +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/images/visualizer-mobile.png +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/midi-harness.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/release-demo.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/docs/troubleshooting.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/cpp/CMakeLists.txt +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/cpp/main.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/csharp/.gitignore +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/csharp/Program.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/csharp/Quickstart.csproj +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/javascript/node.mjs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/pulse.score.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/python/quickstart.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/python/sample_motion.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/typescript/.gitignore +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/typescript/app.ts +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/typescript/index.html +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/typescript/tsconfig.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/bindings/typescript/wasm.d.ts +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/examples/patterns/starter.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/app.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/beats.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/dancerudiments.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/index.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/initial/app.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/initial/style.css +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/initial/template.html +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/initial-collection.html +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/harness/style.css +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/c_api.h +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/collections/atlas.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/collections/club.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/collections/continuum.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/collections/dancefloor.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/collections/expansion.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/collections/initial.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/dance_rudiments.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/detail/default_includes.inc +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/detail/default_registry.inc +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/include/dancerudiments/sampled_pattern.hpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/packaging/CPP_BINARY_README.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/__main__.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/_reproducibility.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/_validation.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/cli.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/collections.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/compiler.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/curves.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/events.py +0 -0
- {dancerudiments-0.2.4/tools/release_demo_assets → dancerudiments-0.3.0/python/dancerudiments_authoring/harness_assets}/beat_player.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/initial_sources.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/io.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/model.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/THIRD_PARTY_NOTICES.md +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/atlas.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/club.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/continuum.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/dancefloor.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/expansion.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/python/dancerudiments_authoring/packs/initial.json +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/release_version-v3.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/src/dance_rudiments.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/src/sampled_pattern.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/browser/test_initial_gallery.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/consumer/CMakeLists.txt +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/consumer/main.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_c_api.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_club.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_continuum.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_dancefloor.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_default_registration.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_initial_collection.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_main.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/cpp/test_sampled_pattern.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/csharp/.gitignore +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/csharp/DanceRudiments.Tests.csproj +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/csharp/Program.cs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/csharp/packaging/test_packaging.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/csharp/packaging/test_publish_verification.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_atlas.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_authoring.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_club.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_continuum.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_dancefloor.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_defaults.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_expansion.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_harness_beats.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_initial_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_native.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_package_docs.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_release_demo_compact.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_release_version.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/python/test_reproducibility.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/typescript/defaults.test.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/typescript/initial-wasm.test.mjs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/typescript/patterns.test.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/typescript/runtime.test.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tests/typescript/wasm-smoke.mjs +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_atlas_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_club_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_club_demo.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_continuum_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_dancefloor_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_dancefloor_demo.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_default_catalogue.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_expansion_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_harness.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/build_initial_collection.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/capture_readme_screenshots.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/check_package_docs.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/check_release_version.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/club_demo_assets/app.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/club_demo_assets/style.css +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/club_demo_assets/template.html +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/compile_patterns.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/csharp_package.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/dancefloor_demo_assets/app.js +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/dancefloor_demo_assets/style.css +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/dancefloor_demo_assets/template.html +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/export_default_catalogue.cpp +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/harness_beats.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/release_version.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/render_club_demo.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/render_dancefloor_demo.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/render_release_demo.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tools/test_midi_harness.py +0 -0
- {dancerudiments-0.2.4 → dancerudiments-0.3.0}/tsconfig.json +0 -0
|
@@ -30,3 +30,10 @@ harness/beats.json text eol=lf
|
|
|
30
30
|
# Keep original DanceFlow artwork byte-identical across platform packages.
|
|
31
31
|
**/branding/*.svg text eol=lf
|
|
32
32
|
**/branding/*.png binary
|
|
33
|
+
|
|
34
|
+
# Recording WASM provenance hashes the actual C++ source bytes. Do not let
|
|
35
|
+
# core.autocrlf turn these into CRLF on Windows; do not weaken the SHA tests.
|
|
36
|
+
tools/recording_wasm.cpp text eol=lf
|
|
37
|
+
include/dancerudiments/recording_view.hpp text eol=lf
|
|
38
|
+
python/dancerudiments_authoring/harness_assets/recording.wasm.json text eol=lf
|
|
39
|
+
python/dancerudiments_authoring/harness_assets/recording.wasm.b64 text eol=lf
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Recording harness and native compatibility
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
jobs:
|
|
10
|
+
recording-harness:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
timeout-minutes: 25
|
|
13
|
+
env:
|
|
14
|
+
DANCERUDIMENTS_REQUIRE_NATIVE: '1'
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- uses: actions/setup-python@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: '3.13'
|
|
20
|
+
- uses: actions/setup-node@v6
|
|
21
|
+
with:
|
|
22
|
+
node-version: 22
|
|
23
|
+
- name: Build and install actual native/authoring package
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install . playwright
|
|
26
|
+
python -m playwright install --with-deps chromium
|
|
27
|
+
- name: Check committed sampler/source hashes and shared package APIs
|
|
28
|
+
run: |
|
|
29
|
+
python -m unittest discover -s tests/python -p test_recording.py -v
|
|
30
|
+
python -m unittest discover -s tests/python -p test_harness_display.py -v
|
|
31
|
+
- name: Check unchanged beat-player contracts after moving shared assets
|
|
32
|
+
run: node --test tests/typescript/beat-player.test.js
|
|
33
|
+
- name: Rebuild the generic native recording accessor
|
|
34
|
+
run: |
|
|
35
|
+
sudo apt-get update
|
|
36
|
+
sudo apt-get install -y clang lld
|
|
37
|
+
python tools/build_recording_wasm.py
|
|
38
|
+
- name: Native C++ recording and existing-pattern regressions
|
|
39
|
+
run: |
|
|
40
|
+
cmake -S . -B build-recordings -DCMAKE_BUILD_TYPE=Release
|
|
41
|
+
cmake --build build-recordings --parallel 2
|
|
42
|
+
ctest --test-dir build-recordings --output-on-failure
|
|
43
|
+
- name: Verify a freshly built recording page with real local-file loading
|
|
44
|
+
env:
|
|
45
|
+
PYTHONPATH: python
|
|
46
|
+
run: python tools/test_recording_harness.py recording-harness/index.html --make-fixture --screenshot recording-comparison.png
|
|
47
|
+
- uses: actions/upload-artifact@v6
|
|
48
|
+
if: always()
|
|
49
|
+
with:
|
|
50
|
+
name: native-recording-harness
|
|
51
|
+
path: |
|
|
52
|
+
recording-harness/
|
|
53
|
+
recording-comparison.png
|
|
54
|
+
recording-comparison-bars.png
|
|
55
|
+
if-no-files-found: warn
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Agent instructions for DanceRudiments
|
|
2
|
+
|
|
3
|
+
- Read README.md, docs/ and the binding examples. Check the native catalogue, integer-pip timing, compositions and the C++, Python, WASM and C# bindings before adding a pattern or adapter.
|
|
4
|
+
- Use the relevant existing capabilities as fully as the task warrants. Always look for a useful improvement to this tool. Fix a reusable gap here rather than copying its engine or carrying a private workaround; record why no change is justified when that is the result.
|
|
5
|
+
- Submit improvements as PRs to https://github.com/kieransimkin/DanceRudiments/pulls. Never leave a completed reusable improvement only in a local fork. Keep changes focused and preserve the tool's identity and compatibility contracts.
|
|
6
|
+
- Add relevant regression coverage, documentation and a reproducible example when behaviour changes. Use tools/release_version.py and tools/check_release_version.py. Run the native and relevant binding tests from .github/workflows/ before packaging.
|
|
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
|
+
- 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
|
+
- 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.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
cmake_minimum_required(VERSION 3.20)
|
|
2
|
-
project(DanceRudiments VERSION 0.
|
|
2
|
+
project(DanceRudiments VERSION 0.3.0
|
|
3
3
|
DESCRIPTION "Deterministic rhythmic position functions for DanceFlow. Music: https://kieransimkin.co.uk/my-songs/"
|
|
4
4
|
HOMEPAGE_URL "https://kieransimkin.co.uk/my-songs/"
|
|
5
5
|
LANGUAGES CXX)
|
|
@@ -59,6 +59,9 @@ endif()
|
|
|
59
59
|
|
|
60
60
|
if(DANCERUDIMENTS_BUILD_TESTS)
|
|
61
61
|
enable_testing()
|
|
62
|
+
add_executable(dancerudiments_recording_tests tests/cpp/test_recording.cpp)
|
|
63
|
+
target_link_libraries(dancerudiments_recording_tests PRIVATE DanceRudiments::DanceRudiments)
|
|
64
|
+
add_test(NAME dancerudiments_recordings COMMAND dancerudiments_recording_tests)
|
|
62
65
|
add_executable(dancerudiments_tests tests/cpp/test_main.cpp)
|
|
63
66
|
target_link_libraries(dancerudiments_tests PRIVATE DanceRudiments::DanceRudiments)
|
|
64
67
|
add_test(NAME dancerudiments_cpp COMMAND dancerudiments_tests)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dancerudiments
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Deterministic rhythmic position functions with C++, Python, TypeScript/WASM and C# bindings. https://kieransimkin.co.uk/my-songs/
|
|
5
5
|
Author: Kieran Simkin
|
|
6
6
|
License-Expression: MIT AND BSD-3-Clause AND CC0-1.0 AND CC-BY-4.0
|
|
@@ -42,7 +42,9 @@ Project website: [https://kieransimkin.co.uk/danceflow/](https://kieransimkin.co
|
|
|
42
42
|
|
|
43
43
|
## ▶ Try the pattern visualizer
|
|
44
44
|
|
|
45
|
-
**[
|
|
45
|
+
**[▶ Open the movement visualiser](https://kieransimkin.github.io/DanceRudiments/)**
|
|
46
|
+
|
|
47
|
+
[Download the self-contained HTML for offline use](https://github.com/kieransimkin/DanceRudiments/raw/refs/heads/main/harness/index.html)
|
|
46
48
|
|
|
47
49
|
Save the file and open it in a browser. **No install, server, CDN, soundfont or
|
|
48
50
|
separate WASM file is required.** The complete 1,731-movement catalogue includes a
|
|
@@ -59,13 +61,13 @@ The downloadable file is the checked-in snapshot; the **Pattern visualizer**
|
|
|
59
61
|
workflow also rebuilds a fresh version from every pushed native catalogue.
|
|
60
62
|
[Beat player, rebuilding, release downloads and optional live hosting](docs/midi-harness.md).
|
|
61
63
|
|
|
62
|
-
[](https://github.
|
|
64
|
+
[](https://kieransimkin.github.io/DanceRudiments/)
|
|
63
65
|
|
|
64
66
|
*Captured from the running C++/WebAssembly visualizer at beat 2.75. Audio was not started during this screenshot.*
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
|
|
68
|
-
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.
|
|
70
|
+
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.
|
|
69
71
|
|
|
70
72
|
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.
|
|
71
73
|
|
|
@@ -105,6 +107,33 @@ python tools/build_default_catalogue.py --check
|
|
|
105
107
|
The release workflow builds the complete native catalogue demo plus an offline,
|
|
106
108
|
audio-enabled 68-rhythm / 16-mapping comparison page. All live motion comes from C++/WASM.
|
|
107
109
|
|
|
110
|
+
## BPM-synchronised N-dimensional recordings and comparison harness
|
|
111
|
+
|
|
112
|
+
The additive `dancerudiments.recording` format stores **any number of named
|
|
113
|
+
float64 dimensions** at **64 pips per beat**, with a mandatory BPM estimate or
|
|
114
|
+
confirmed value and separate beat-phase provenance. `SampledRecording` provides
|
|
115
|
+
native non-looping C++/Python playback, including captures beyond the old
|
|
116
|
+
65,535-pip loop length; existing XYZ patterns and their wrapping rules are unchanged.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from dancerudiments_authoring import load_recording
|
|
120
|
+
from dancerudiments_authoring.harness import build_recording_harness
|
|
121
|
+
r = load_recording("output/recordings/audio_recording.json")
|
|
122
|
+
values = r.to_native().sample(r.clock.start_pip) # every dimension, real C++
|
|
123
|
+
build_recording_harness([r], "output/index.html")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The exported page uses **the same packaged visualizer assets as catalogue/release
|
|
127
|
+
pages**, with native WASM sampling, shared transport, four-card comparison and
|
|
128
|
+
review import/export. Recording mode adds arbitrary-axis X/Y/Z selection, locked
|
|
129
|
+
BPM/origin and non-looping completion. The tiny generic WASM sampler is bundled;
|
|
130
|
+
no compiler or CDN is needed at export time. StemLab's `record-rudiment` and
|
|
131
|
+
`generate-batch` produce individual or varied stem/filter combinations using this
|
|
132
|
+
API without copying it. Music is not bundled unless explicitly requested.
|
|
133
|
+
|
|
134
|
+
See **[recording format, harness, native API and compatibility](docs/recordings.md)**.
|
|
135
|
+
Build the updated source to use this unreleased API; earlier releases lack it.
|
|
136
|
+
|
|
108
137
|
## Curve and event authoring
|
|
109
138
|
|
|
110
139
|
The optional **Python authoring tools** compile LFOs, segmented curves, sampled
|
|
@@ -170,7 +199,7 @@ another movement implementation. The examples below are checked into
|
|
|
170
199
|
| TypeScript / JavaScript | `catalogue` (an array, not a function) | `sample(name, pip)` after `bindNative()` | `info.periodPips` | Call the custom bank's `dispose()` |
|
|
171
200
|
|
|
172
201
|
**One beat is 64 pips.** Supply a signed 32-bit integer, not milliseconds or a
|
|
173
|
-
floating-point beat number. Every sampler wraps negative as well as positive
|
|
202
|
+
floating-point beat number. Every legacy pattern sampler wraps negative as well as positive
|
|
174
203
|
positions into its own loop. Offsets are `{x, y, z}`, dimensionless and bounded to
|
|
175
204
|
`[-1, 1]`; choose the pixel/metre scale in your application. There is no automatic
|
|
176
205
|
interpolation, BPM detection or audio playback inside a binding.
|
|
@@ -548,3 +577,56 @@ Apply an output to a bounded subject. DanceRudiments changes position only; it m
|
|
|
548
577
|
## Troubleshooting history
|
|
549
578
|
|
|
550
579
|
See [build and release troubleshooting](docs/troubleshooting.md) for prior failures, causes and fixes.
|
|
580
|
+
|
|
581
|
+
### Switch the shared visualizer between trajectories and bars
|
|
582
|
+
|
|
583
|
+
Use **Movement view → X–Y plot / Bar graph**. Bar view uses the same native
|
|
584
|
+
C++/WebAssembly sample and the existing clock, shows **every dimension** as a
|
|
585
|
+
separate signed bar, and keeps comparison cards on one common scale. Switching
|
|
586
|
+
views does not interrupt playback or change the underlying recording. The
|
|
587
|
+
selection is local to your browser; long dimension sets scroll horizontally.
|
|
588
|
+
This applies to catalogue/release pages and recording harnesses exported by
|
|
589
|
+
StemLab. Rebuild old generated pages to include the control. See
|
|
590
|
+
[recording visualizer controls](docs/recordings.md#trajectory-or-all-dimension-bars).
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
## Coordinated releases and latest-release dependencies
|
|
594
|
+
|
|
595
|
+
Keep `DanceRudiments`, `react-timeline-sequence`, and `stemlab` as sibling
|
|
596
|
+
checkouts. The release order is **React Timeline Sequence → DanceRudiments →
|
|
597
|
+
StemLab**: publish and verify the companions before updating the consuming app.
|
|
598
|
+
StemLab must use their **latest stable official releases**, not an unreleased
|
|
599
|
+
commit, sibling source package or vendored npm archive. Each build records exact
|
|
600
|
+
released versions/commits/integrity after latest-release resolution so all its
|
|
601
|
+
jobs use the same bytes; CI fails clearly when that snapshot is stale.
|
|
602
|
+
|
|
603
|
+
From the parent folder, preview and then explicitly execute:
|
|
604
|
+
|
|
605
|
+
```powershell
|
|
606
|
+
.\stemlab\scripts\Release-DanceFlow.ps1 -ProjectsRoot .
|
|
607
|
+
.\stemlab\scripts\Release-DanceFlow.ps1 -ProjectsRoot . -Execute
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
For the first migration use the same commands with
|
|
611
|
+
`.\release-kit\Release-DanceFlow.ps1` after extracting the complete kit. It
|
|
612
|
+
applies the three repository patches, updates versions, performs scoped commits
|
|
613
|
+
and normal pushes, waits for exact-commit CI, then creates **new** release tags.
|
|
614
|
+
The existing GitHub Actions workflows publish packages; no protection rules,
|
|
615
|
+
credentials, old tags or assets are changed. The initial expected next-minor
|
|
616
|
+
versions are only a preview proposal, never a claim that they are published.
|
|
617
|
+
|
|
618
|
+
Use Node.js 24, Python 3.11+, PowerShell 5.1+, Git and authenticated GitHub CLI.
|
|
619
|
+
Required main/registry/Pages jobs must pass; missing approvals and partial
|
|
620
|
+
publication are blockers, not success. The default script releases all three
|
|
621
|
+
projects, is opt-in via `-Execute`, and supports a saved exact-source `-Resume`
|
|
622
|
+
session. A changed checkout or pre-commit build failure requires review rather
|
|
623
|
+
than an automatic stash/reset or guessed recovery.
|
|
624
|
+
|
|
625
|
+
StemLab's helper updates npm manifests/lock, optional native dependency minimum,
|
|
626
|
+
release/build metadata and the genuinely rebuilt JS/CSS together. Its daily
|
|
627
|
+
release-update workflow proposes subsequent updates by PR without auto-merging.
|
|
628
|
+
A tagged StemLab release generates all four Arcadians pages and validates actual
|
|
629
|
+
Pages deployment, live HTML and seekable audio. Do not start a duplicate manual
|
|
630
|
+
Arcadians analysis during that tagged build. Read
|
|
631
|
+
**[the full release, resume, verification and troubleshooting guide](docs/released-viewers.md)**
|
|
632
|
+
before running it. Keep this README and AGENTS.md synchronized with future changes.
|
|
@@ -24,7 +24,9 @@ Project website: [https://kieransimkin.co.uk/danceflow/](https://kieransimkin.co
|
|
|
24
24
|
|
|
25
25
|
## ▶ Try the pattern visualizer
|
|
26
26
|
|
|
27
|
-
**[
|
|
27
|
+
**[▶ Open the movement visualiser](https://kieransimkin.github.io/DanceRudiments/)**
|
|
28
|
+
|
|
29
|
+
[Download the self-contained HTML for offline use](https://github.com/kieransimkin/DanceRudiments/raw/refs/heads/main/harness/index.html)
|
|
28
30
|
|
|
29
31
|
Save the file and open it in a browser. **No install, server, CDN, soundfont or
|
|
30
32
|
separate WASM file is required.** The complete 1,731-movement catalogue includes a
|
|
@@ -41,13 +43,13 @@ The downloadable file is the checked-in snapshot; the **Pattern visualizer**
|
|
|
41
43
|
workflow also rebuilds a fresh version from every pushed native catalogue.
|
|
42
44
|
[Beat player, rebuilding, release downloads and optional live hosting](docs/midi-harness.md).
|
|
43
45
|
|
|
44
|
-
[](https://github.
|
|
46
|
+
[](https://kieransimkin.github.io/DanceRudiments/)
|
|
45
47
|
|
|
46
48
|
*Captured from the running C++/WebAssembly visualizer at beat 2.75. Audio was not started during this screenshot.*
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
|
|
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.
|
|
52
|
+
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
53
|
|
|
52
54
|
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
55
|
|
|
@@ -87,6 +89,33 @@ python tools/build_default_catalogue.py --check
|
|
|
87
89
|
The release workflow builds the complete native catalogue demo plus an offline,
|
|
88
90
|
audio-enabled 68-rhythm / 16-mapping comparison page. All live motion comes from C++/WASM.
|
|
89
91
|
|
|
92
|
+
## BPM-synchronised N-dimensional recordings and comparison harness
|
|
93
|
+
|
|
94
|
+
The additive `dancerudiments.recording` format stores **any number of named
|
|
95
|
+
float64 dimensions** at **64 pips per beat**, with a mandatory BPM estimate or
|
|
96
|
+
confirmed value and separate beat-phase provenance. `SampledRecording` provides
|
|
97
|
+
native non-looping C++/Python playback, including captures beyond the old
|
|
98
|
+
65,535-pip loop length; existing XYZ patterns and their wrapping rules are unchanged.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from dancerudiments_authoring import load_recording
|
|
102
|
+
from dancerudiments_authoring.harness import build_recording_harness
|
|
103
|
+
r = load_recording("output/recordings/audio_recording.json")
|
|
104
|
+
values = r.to_native().sample(r.clock.start_pip) # every dimension, real C++
|
|
105
|
+
build_recording_harness([r], "output/index.html")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The exported page uses **the same packaged visualizer assets as catalogue/release
|
|
109
|
+
pages**, with native WASM sampling, shared transport, four-card comparison and
|
|
110
|
+
review import/export. Recording mode adds arbitrary-axis X/Y/Z selection, locked
|
|
111
|
+
BPM/origin and non-looping completion. The tiny generic WASM sampler is bundled;
|
|
112
|
+
no compiler or CDN is needed at export time. StemLab's `record-rudiment` and
|
|
113
|
+
`generate-batch` produce individual or varied stem/filter combinations using this
|
|
114
|
+
API without copying it. Music is not bundled unless explicitly requested.
|
|
115
|
+
|
|
116
|
+
See **[recording format, harness, native API and compatibility](docs/recordings.md)**.
|
|
117
|
+
Build the updated source to use this unreleased API; earlier releases lack it.
|
|
118
|
+
|
|
90
119
|
## Curve and event authoring
|
|
91
120
|
|
|
92
121
|
The optional **Python authoring tools** compile LFOs, segmented curves, sampled
|
|
@@ -152,7 +181,7 @@ another movement implementation. The examples below are checked into
|
|
|
152
181
|
| TypeScript / JavaScript | `catalogue` (an array, not a function) | `sample(name, pip)` after `bindNative()` | `info.periodPips` | Call the custom bank's `dispose()` |
|
|
153
182
|
|
|
154
183
|
**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
|
|
184
|
+
floating-point beat number. Every legacy pattern sampler wraps negative as well as positive
|
|
156
185
|
positions into its own loop. Offsets are `{x, y, z}`, dimensionless and bounded to
|
|
157
186
|
`[-1, 1]`; choose the pixel/metre scale in your application. There is no automatic
|
|
158
187
|
interpolation, BPM detection or audio playback inside a binding.
|
|
@@ -530,3 +559,56 @@ Apply an output to a bounded subject. DanceRudiments changes position only; it m
|
|
|
530
559
|
## Troubleshooting history
|
|
531
560
|
|
|
532
561
|
See [build and release troubleshooting](docs/troubleshooting.md) for prior failures, causes and fixes.
|
|
562
|
+
|
|
563
|
+
### Switch the shared visualizer between trajectories and bars
|
|
564
|
+
|
|
565
|
+
Use **Movement view → X–Y plot / Bar graph**. Bar view uses the same native
|
|
566
|
+
C++/WebAssembly sample and the existing clock, shows **every dimension** as a
|
|
567
|
+
separate signed bar, and keeps comparison cards on one common scale. Switching
|
|
568
|
+
views does not interrupt playback or change the underlying recording. The
|
|
569
|
+
selection is local to your browser; long dimension sets scroll horizontally.
|
|
570
|
+
This applies to catalogue/release pages and recording harnesses exported by
|
|
571
|
+
StemLab. Rebuild old generated pages to include the control. See
|
|
572
|
+
[recording visualizer controls](docs/recordings.md#trajectory-or-all-dimension-bars).
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
## Coordinated releases and latest-release dependencies
|
|
576
|
+
|
|
577
|
+
Keep `DanceRudiments`, `react-timeline-sequence`, and `stemlab` as sibling
|
|
578
|
+
checkouts. The release order is **React Timeline Sequence → DanceRudiments →
|
|
579
|
+
StemLab**: publish and verify the companions before updating the consuming app.
|
|
580
|
+
StemLab must use their **latest stable official releases**, not an unreleased
|
|
581
|
+
commit, sibling source package or vendored npm archive. Each build records exact
|
|
582
|
+
released versions/commits/integrity after latest-release resolution so all its
|
|
583
|
+
jobs use the same bytes; CI fails clearly when that snapshot is stale.
|
|
584
|
+
|
|
585
|
+
From the parent folder, preview and then explicitly execute:
|
|
586
|
+
|
|
587
|
+
```powershell
|
|
588
|
+
.\stemlab\scripts\Release-DanceFlow.ps1 -ProjectsRoot .
|
|
589
|
+
.\stemlab\scripts\Release-DanceFlow.ps1 -ProjectsRoot . -Execute
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
For the first migration use the same commands with
|
|
593
|
+
`.\release-kit\Release-DanceFlow.ps1` after extracting the complete kit. It
|
|
594
|
+
applies the three repository patches, updates versions, performs scoped commits
|
|
595
|
+
and normal pushes, waits for exact-commit CI, then creates **new** release tags.
|
|
596
|
+
The existing GitHub Actions workflows publish packages; no protection rules,
|
|
597
|
+
credentials, old tags or assets are changed. The initial expected next-minor
|
|
598
|
+
versions are only a preview proposal, never a claim that they are published.
|
|
599
|
+
|
|
600
|
+
Use Node.js 24, Python 3.11+, PowerShell 5.1+, Git and authenticated GitHub CLI.
|
|
601
|
+
Required main/registry/Pages jobs must pass; missing approvals and partial
|
|
602
|
+
publication are blockers, not success. The default script releases all three
|
|
603
|
+
projects, is opt-in via `-Execute`, and supports a saved exact-source `-Resume`
|
|
604
|
+
session. A changed checkout or pre-commit build failure requires review rather
|
|
605
|
+
than an automatic stash/reset or guessed recovery.
|
|
606
|
+
|
|
607
|
+
StemLab's helper updates npm manifests/lock, optional native dependency minimum,
|
|
608
|
+
release/build metadata and the genuinely rebuilt JS/CSS together. Its daily
|
|
609
|
+
release-update workflow proposes subsequent updates by PR without auto-merging.
|
|
610
|
+
A tagged StemLab release generates all four Arcadians pages and validates actual
|
|
611
|
+
Pages deployment, live HTML and seekable audio. Do not start a duplicate manual
|
|
612
|
+
Arcadians analysis during that tagged build. Read
|
|
613
|
+
**[the full release, resume, verification and troubleshooting guide](docs/released-viewers.md)**
|
|
614
|
+
before running it. Keep this README and AGENTS.md synchronized with future changes.
|
{dancerudiments-0.2.4 → dancerudiments-0.3.0}/bindings/csharp/DanceRudiments/DanceRudiments.csproj
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<!-- Kieran Simkin / DanceFlow: https://kieransimkin.co.uk/my-songs/ -->
|
|
3
3
|
<PropertyGroup>
|
|
4
4
|
<TargetFramework>net8.0</TargetFramework>
|
|
5
|
-
<Version>0.
|
|
5
|
+
<Version>0.3.0</Version>
|
|
6
6
|
<PackageId>DanceRudiments</PackageId>
|
|
7
7
|
<Authors>Kieran Simkin</Authors>
|
|
8
8
|
<Description>Deterministic rhythmic position functions with native C# bindings. Music: https://kieransimkin.co.uk/my-songs/</Description>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <utility>
|
|
4
4
|
#include "dancerudiments/dance_rudiments.hpp"
|
|
5
5
|
#include "dancerudiments/sampled_pattern.hpp"
|
|
6
|
+
#include "dancerudiments/recording.hpp"
|
|
6
7
|
|
|
7
8
|
namespace py = pybind11;
|
|
8
9
|
using namespace dancerudiments;
|
|
@@ -11,6 +12,16 @@ using namespace pybind11::literals;
|
|
|
11
12
|
PYBIND11_MODULE(dancerudiments, m) {
|
|
12
13
|
m.doc() = "Integer-pip rhythmic position functions";
|
|
13
14
|
m.attr("PIPS_PER_BEAT") = pips_per_beat;
|
|
15
|
+
py::class_<SampledRecording>(m, "SampledRecording")
|
|
16
|
+
.def(py::init<std::string, std::vector<std::string>, const std::vector<std::vector<double>>&, double, double, int>(),
|
|
17
|
+
py::arg("name"), py::arg("dimensions"), py::arg("samples"), py::arg("bpm"), py::arg("beat_zero_seconds")=0., py::arg("start_pip")=0)
|
|
18
|
+
.def_property_readonly("name", &SampledRecording::name)
|
|
19
|
+
.def_property_readonly("dimensions", &SampledRecording::dimensions)
|
|
20
|
+
.def_property_readonly("sample_count", &SampledRecording::sample_count)
|
|
21
|
+
.def_property_readonly("bpm", &SampledRecording::bpm)
|
|
22
|
+
.def_property_readonly("beat_zero_seconds", &SampledRecording::beat_zero_seconds)
|
|
23
|
+
.def_property_readonly("start_pip", &SampledRecording::start_pip)
|
|
24
|
+
.def("sample", &SampledRecording::sample, py::arg("pip").noconvert());
|
|
14
25
|
py::class_<Offset3>(m, "Offset3")
|
|
15
26
|
.def_readonly("x", &Offset3::x).def_readonly("y", &Offset3::y).def_readonly("z", &Offset3::z)
|
|
16
27
|
.def("as_tuple", [](const Offset3& v) { return py::make_tuple(v.x, v.y, v.z); });
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# N-dimensional BPM-synchronised recordings and the shared visualizer
|
|
2
|
+
|
|
3
|
+
This additive API represents **non-looping named dimensions**, sampled at **64
|
|
4
|
+
pips per quarter-note beat**, with mandatory BPM provenance. It does not change
|
|
5
|
+
`Offset3`, the built-in catalogue, existing XYZ compiled-pack schema, or legacy
|
|
6
|
+
loop rules. Audio DSP remains in StemLab, not in this library.
|
|
7
|
+
|
|
8
|
+
## Contract
|
|
9
|
+
|
|
10
|
+
`dancerudiments.recording` schema 1 declares `sample_dtype: float64` and
|
|
11
|
+
`sample_decimals: 12`. Components are finite, within [-1,1], and rounded to twelve
|
|
12
|
+
decimal places. Native code checks the IEEE-754 binary64 contract. JSON numbers
|
|
13
|
+
are not PCM audio samples with a 16/24-bit depth.
|
|
14
|
+
|
|
15
|
+
Each recording requires a finite positive BPM, `bpm_status` (`estimated` or
|
|
16
|
+
`confirmed`), and nonempty `bpm_source`. `phase_status` is separately `unverified`,
|
|
17
|
+
`estimated` or `supplied`; confirming BPM does not confirm the beat origin.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
time(i) = beat_zero_seconds + (start_pip + i) * 60 / (64 * bpm)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A row is one pip window/sample; `start_pip` may be negative. `RecordingClock`
|
|
24
|
+
uses fractions derived from the decimal BPM instead of repeatedly rounded hops.
|
|
25
|
+
The rate in seconds is 128 Hz at 120 BPM. This contract is constant-tempo, not a
|
|
26
|
+
variable-tempo map; no default BPM, automatic beat detection or phase guessing.
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"format": "dancerudiments.recording",
|
|
31
|
+
"schema_version": 1,
|
|
32
|
+
"pips_per_beat": 64,
|
|
33
|
+
"sample_dtype": "float64",
|
|
34
|
+
"sample_decimals": 12,
|
|
35
|
+
"name": "four_axes",
|
|
36
|
+
"dimensions": ["bass", "treble", "drums", "vocals"],
|
|
37
|
+
"clock": {
|
|
38
|
+
"bpm": 145.0,
|
|
39
|
+
"bpm_status": "estimated",
|
|
40
|
+
"bpm_source": "artist estimate",
|
|
41
|
+
"beat_zero_seconds": 0.0,
|
|
42
|
+
"phase_status": "unverified",
|
|
43
|
+
"start_pip": 0
|
|
44
|
+
},
|
|
45
|
+
"samples": [[0.2, 0.6, 0.9, 0.1], [0.3, 0.4, 0.2, 0.7]],
|
|
46
|
+
"provenance": {"producer": "example"}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Dimension identifiers are unique `[a-z][a-z0-9_]{0,127}` strings; every row has
|
|
51
|
+
exactly their number of values, in the declared order. Unknown fields, malformed
|
|
52
|
+
headers, ragged rows, non-finite data/metadata, duplicate JSON keys, missing BPM
|
|
53
|
+
and invalid dimensions fail validation. At least one row/dimension is required.
|
|
54
|
+
The resource guards are 8,388,608 scalar values and 64 MiB per JSON document,
|
|
55
|
+
not a fixed XYZ dimension ceiling. Recordings can exceed 65,535 pips. Clock/index
|
|
56
|
+
validation keeps recorded absolute pips representable by the native int API.
|
|
57
|
+
|
|
58
|
+
## Python and C++ playback
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from dancerudiments_authoring import load_recording, write_recording
|
|
62
|
+
r = load_recording("recordings/four_axes.json")
|
|
63
|
+
write_recording("copy.json", r) # refuses replacement unless explicitly requested
|
|
64
|
+
native = r.to_native() # real C++ SampledRecording, not a Python fallback
|
|
65
|
+
values = native.sample(r.clock.start_pip)
|
|
66
|
+
assert len(values) == len(r.dimensions)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`SampledRecording` owns and validates the data and returns **all dimensions**.
|
|
70
|
+
An out-of-range absolute pip raises instead of looping. Name, dimensions, count,
|
|
71
|
+
BPM, beat origin and first pip are readonly metadata. A moved-from object cannot
|
|
72
|
+
be sampled. Data I/O is standard-library-only; Python native playback needs the
|
|
73
|
+
updated extension, and raises clearly with an older/missing build.
|
|
74
|
+
|
|
75
|
+
```cpp
|
|
76
|
+
#include <dancerudiments/recording.hpp>
|
|
77
|
+
using namespace dancerudiments;
|
|
78
|
+
SampledRecording r("four_axes", {"bass","treble","drums","vocals"},
|
|
79
|
+
{{.2,.6,.9,.1}, {.3,.4,.2,.7}}, 145.0, 0.0, 0);
|
|
80
|
+
auto values = r.sample(1); // four doubles, non-looping
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`recording_view.hpp` supplies the dependency-free `recording_component` accessor
|
|
84
|
+
shared by this C++ object and the generic recording WASM. The browser does not
|
|
85
|
+
regenerate mathematical curves or run a JavaScript motion fallback.
|
|
86
|
+
|
|
87
|
+
## Generate the actual DanceRudiments comparison harness
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from pathlib import Path
|
|
91
|
+
from dancerudiments_authoring.harness import build_recording_harness
|
|
92
|
+
from dancerudiments_authoring import load_recording
|
|
93
|
+
paths = sorted(Path("output/recordings").glob("*.json"))
|
|
94
|
+
report = build_recording_harness((load_recording(p) for p in paths),
|
|
95
|
+
"output/index.html", collection_id="my-audio-batch")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
All candidates must share the exact clock and captured extent; their dimension
|
|
99
|
+
counts can differ. Input is consumed one recording at a time. Duplicate float64
|
|
100
|
+
columns are pooled by checksum, retaining all samples without repeating the same
|
|
101
|
+
stem/filter data for every candidate. Bounds are 1024 candidates and 128 MiB of
|
|
102
|
+
unique binary sample columns. The audit JSON reports native WASM/data/page hashes,
|
|
103
|
+
clock, counts, unique columns and byte size.
|
|
104
|
+
|
|
105
|
+
The builder uses **the same template, CSS, beat player and app as release/catalogue
|
|
106
|
+
pages**. Their former `tools/release_demo_assets` files now live under packaged
|
|
107
|
+
`python/dancerudiments_authoring/harness_assets`; `tools/release_demo.py` delegates
|
|
108
|
+
to this shared `render_template`. Do not create another renderer in StemLab.
|
|
109
|
+
|
|
110
|
+
The page retains search, original four-card comparison, review choices/notes and
|
|
111
|
+
review JSON import/download. Recording mode adds any-axis X/Y/Z projections and
|
|
112
|
+
JSON download links for files under the sibling `recordings/` directory. It locks
|
|
113
|
+
exported tempo/beat origin and stops at the end. Nothing autoplays. Paths are not
|
|
114
|
+
closed across a non-looping seam. Display-decimated traces do not change full
|
|
115
|
+
native samples. The exported JSON keeps axes not currently visible in the view.
|
|
116
|
+
|
|
117
|
+
Optional `audio` metadata may include a **plain local basename** `relative_path`
|
|
118
|
+
for a caller-copied track, plus its source hash and extent. The exporter does not
|
|
119
|
+
copy or upload music. Without included audio, the existing local-file picker or
|
|
120
|
+
silent transport can be used. Media playback uses the audio-element clock.
|
|
121
|
+
Source codec/security support is a browser concern; do not disable browser policy
|
|
122
|
+
to force loading. Review local storage is best-effort; download JSON for portability.
|
|
123
|
+
|
|
124
|
+
All HTML/JS/CSS, native WASM and sampled columns are embedded. No compiler/CDN or
|
|
125
|
+
external request is required to build/use a recording page. Keep any optional
|
|
126
|
+
media and recording JSON companions with the HTML for their controls to work.
|
|
127
|
+
The page is control-data inspection, not proof of comfortable full-body choreography.
|
|
128
|
+
|
|
129
|
+
## Rebuilding the tiny generic native sampler
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
python tools/build_recording_wasm.py
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This uses clang++/wasm-ld, targets freestanding wasm32, and stores base64 bytes plus
|
|
136
|
+
source/binary hashes in packaged assets. Rebuild when `recording_view.hpp` or
|
|
137
|
+
`tools/recording_wasm.cpp` changes. Normal exports verify the bundled WASM checksum;
|
|
138
|
+
end users need no compiler. CI rebuilds and checks for a stale committed asset.
|
|
139
|
+
The existing catalogue export still follows its original native snapshot workflow.
|
|
140
|
+
|
|
141
|
+
## Explicit legacy XYZ conversion
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from pathlib import Path
|
|
145
|
+
from dancerudiments_authoring import emit_json
|
|
146
|
+
pack = r.to_compiled_pack(dimensions=("bass", "treble"), start=0, count=2)
|
|
147
|
+
Path("xy.compiled.json").write_text(emit_json(pack), encoding="utf-8")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Select 1..3 axes and at most 65,535 samples; missing XYZ components become zero.
|
|
151
|
+
A larger recording requires explicit axis/excerpt selection, never truncation.
|
|
152
|
+
The legacy sampler loops, so conversion retains a seam warning and source clock;
|
|
153
|
+
it does not smooth/close an arbitrary excerpt. The new native recording API does
|
|
154
|
+
not loop. Existing C#/TypeScript XYZ interfaces remain unchanged; this addition
|
|
155
|
+
provides N-D C++/Python and the recording harness, not new general N-D wrappers
|
|
156
|
+
for all languages.
|
|
157
|
+
|
|
158
|
+
## Validation
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
PYTHONPATH=python python -m unittest discover -s tests/python -p test_recording.py -v
|
|
162
|
+
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
|
163
|
+
cmake --build build --config Release
|
|
164
|
+
ctest --test-dir build -C Release --output-on-failure
|
|
165
|
+
node --test tests/typescript/beat-player.test.js
|
|
166
|
+
python tools/test_recording_harness.py ./test-harness/index.html --make-fixture
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Browser testing requires Playwright/Chromium. Normal mode tests local-file loading;
|
|
170
|
+
`--in-memory` is an explicitly labelled fallback only for restricted environments.
|
|
171
|
+
With copied audio, that fallback hydrates the exact bytes into the existing audio
|
|
172
|
+
element as a Blob, retaining actual decoding/transport/renderer/native WASM. Its
|
|
173
|
+
report does not claim file loading or audible listening QA. The checker samples
|
|
174
|
+
every candidate against retained JSON and tests transport, arbitrary-axis
|
|
175
|
+
projection, non-looping bounds, no autoplay, search/comparison and review download.
|
|
176
|
+
Set `DANCERUDIMENTS_REQUIRE_NATIVE=1` to reject missing native tests rather than skip.
|
|
177
|
+
|
|
178
|
+
Existing versions/tags are unchanged by this patch. Publish a fresh matching
|
|
179
|
+
release only after review and CI. This source API is not present in earlier
|
|
180
|
+
published packages.
|
|
181
|
+
|
|
182
|
+
## Trajectory or all-dimension bars
|
|
183
|
+
|
|
184
|
+
The shared harness has a **Movement view** selector. X–Y plot is the default and
|
|
185
|
+
retains its existing selectable X/Y/Z projection. **Bar graph** draws one
|
|
186
|
+
signed bar for every recorded dimension (X/Y/Z for native catalogue patterns),
|
|
187
|
+
not just the selected projection. Positive values extend above zero and negative
|
|
188
|
+
values below it. The numerical value is the actual native sample; the existing
|
|
189
|
+
amplitude slider scales the geometry only. All bars share the same fixed scale.
|
|
190
|
+
Long channel sets scroll horizontally; no channels are silently dropped.
|
|
191
|
+
|
|
192
|
+
The selector affects catalogue and comparison cards without seeking, pausing,
|
|
193
|
+
changing the selected MIDI beat, changing review choices or rewriting recordings.
|
|
194
|
+
It is remembered per collection when browser storage is available. Offscreen bars
|
|
195
|
+
are released and reconstructed on demand, just like the existing canvas cache.
|
|
196
|
+
Rebuild exported HTML to get a new UI: already-published snapshots are immutable.
|