@kieransimkin/dancemoves 3.2.0 → 3.3.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/README.md CHANGED
@@ -1,7 +1,22 @@
1
1
  # DanceMoves
2
2
 
3
- **3.2.0** adds native, non-looping playback of StemLab/DanceRudiments audio-derived movement recordings. `runtime.recordings` composes the existing audio clock, shared player mapping, accessibility preferences and lifecycle. Captured BPM must match page metadata; samples retain their original integer-pip clock and never wrap. See [recording playback](docs/audio-recording-playback.md).
3
+ **3.3.0** adds source-bound beat alignment, connecting saved StemLab BPM/first-beat readings
4
+ to the shared audio clock. WordPress's **EPK Timing** panel stores the reading
5
+ and verifies its selected master attachment by SHA-256. Procedural rudiments,
6
+ audio interval starts, pulses and sprite cycles use its fractional phase after
7
+ clip/preroll mapping; audio and lyric/cue timestamps keep their original clock.
8
+ Detector phase and fitted BPM remain labelled estimates. See
9
+ [beat-alignment setup, APIs and verification](docs/beat-alignment.md).
10
+
11
+ ![Actual DanceMoves 3.3.0 example paused on the first beat: source time 0.125 seconds and rhythmic position zero](docs/screenshots/beat-alignment-first-beat.png)
12
+
13
+ The original synthetic click example starts its first beat at 0.125 seconds.
14
+ The blue source clock and amber rhythmic clock remain separately inspectable.
15
+ [Watch the actual browser demonstration](docs/videos/beat-alignment-browser.mp4)
16
+ (silent; native bounce, pulse and clock readings advance while lyric timestamps
17
+ retain source time). Capture context and hashes: [media receipt](docs/beat-alignment-media.json).
4
18
 
19
+ **3.2.0** adds native, non-looping playback of StemLab/DanceRudiments audio-derived movement recordings. `runtime.recordings` composes the existing audio clock, shared player mapping, accessibility preferences and lifecycle. Captured BPM must match page metadata; samples retain their original integer-pip clock and never wrap. See [recording playback](docs/audio-recording-playback.md).
5
20
 
6
21
  **3.1.23** secures WordPress motion-capture writes with authenticated
7
22
  `manage_options` authorization. The private capture administration UI uses the
@@ -0,0 +1,99 @@
1
+ {
2
+ "context": "DanceMoves 3.3.0 source-bound beat alignment example in actual Edge browser",
3
+ "input": "Original synthetic 120 BPM click fixture; first beat 0.125 s; offset -16 pips",
4
+ "screenshot": "Paused first-beat seek: blue source 0.125 s, amber rhythmic tick zero",
5
+ "video": "Silent actual browser screenshots at retained wall-clock capture cadence; not frame-accurate performance evidence",
6
+ "transcription": "The native DanceRudiments bounce, playback pulse, source-time and rhythmic-time readings advance during playback. Lyric text remains attached to original source timestamps.",
7
+ "frame_count": 16,
8
+ "frame_ledger": [
9
+ {
10
+ "frame": 0,
11
+ "wallMilliseconds": 1792120075634,
12
+ "sourceSeconds": 1.235186
13
+ },
14
+ {
15
+ "frame": 1,
16
+ "wallMilliseconds": 1792120075772,
17
+ "sourceSeconds": 1.365459
18
+ },
19
+ {
20
+ "frame": 2,
21
+ "wallMilliseconds": 1792120075897,
22
+ "sourceSeconds": 1.499385
23
+ },
24
+ {
25
+ "frame": 3,
26
+ "wallMilliseconds": 1792120076076,
27
+ "sourceSeconds": 1.632385
28
+ },
29
+ {
30
+ "frame": 4,
31
+ "wallMilliseconds": 1792120076224,
32
+ "sourceSeconds": 1.765944
33
+ },
34
+ {
35
+ "frame": 5,
36
+ "wallMilliseconds": 1792120076271,
37
+ "sourceSeconds": 1.882867
38
+ },
39
+ {
40
+ "frame": 6,
41
+ "wallMilliseconds": 1792120076411,
42
+ "sourceSeconds": 1.999107
43
+ },
44
+ {
45
+ "frame": 7,
46
+ "wallMilliseconds": 1792120076534,
47
+ "sourceSeconds": 2.13241
48
+ },
49
+ {
50
+ "frame": 8,
51
+ "wallMilliseconds": 1792120076675,
52
+ "sourceSeconds": 2.268592
53
+ },
54
+ {
55
+ "frame": 9,
56
+ "wallMilliseconds": 1792120076800,
57
+ "sourceSeconds": 2.39849
58
+ },
59
+ {
60
+ "frame": 10,
61
+ "wallMilliseconds": 1792120076945,
62
+ "sourceSeconds": 2.532626
63
+ },
64
+ {
65
+ "frame": 11,
66
+ "wallMilliseconds": 1792120077074,
67
+ "sourceSeconds": 2.66667
68
+ },
69
+ {
70
+ "frame": 12,
71
+ "wallMilliseconds": 1792120077212,
72
+ "sourceSeconds": 2.797329
73
+ },
74
+ {
75
+ "frame": 13,
76
+ "wallMilliseconds": 1792120077331,
77
+ "sourceSeconds": 2.931918
78
+ },
79
+ {
80
+ "frame": 14,
81
+ "wallMilliseconds": 1792120077472,
82
+ "sourceSeconds": 3.068549
83
+ },
84
+ {
85
+ "frame": 15,
86
+ "wallMilliseconds": 1792120077613,
87
+ "sourceSeconds": 3.197775
88
+ }
89
+ ],
90
+ "generated_illustration_omission": "Actual interface captures explain this clock contract; a generated illustration adds no useful evidence.",
91
+ "browser_cleanup": {
92
+ "connected": false,
93
+ "contexts": 0
94
+ },
95
+ "files": {
96
+ "docs\\screenshots\\beat-alignment-first-beat.png": "c2c0d9e92706ce594a326c23e372064004e3b534971764dab2bf99fb0b942d0a",
97
+ "docs\\videos\\beat-alignment-browser.mp4": "8115f23dece23fc6c21e1c76f48ebc13e3594a360f464f676445ff1a2f373acf"
98
+ }
99
+ }
@@ -0,0 +1,79 @@
1
+ # Source-bound beat alignment
2
+
3
+ ![Actual first-beat seek in the DanceMoves 3.3.0 synthetic browser example: original source time 0.125 seconds maps to rhythmic tick zero](screenshots/beat-alignment-first-beat.png)
4
+
5
+ [Play the silent browser demonstration](videos/beat-alignment-browser.mp4).
6
+ The native bounce, playback pulse and two clock readings advance together;
7
+ the displayed lyric still follows its original source timestamp. These are
8
+ actual interface captures from an original synthetic 120 BPM click fixture,
9
+ with a first beat at 0.125 seconds and a -16 pip reading. The video preserves
10
+ the screenshot capture cadence; it is an interface demonstration rather than
11
+ frame-accurate musical performance evidence. [Capture provenance](beat-alignment-media.json).
12
+
13
+ WordPress **EPK Timing** has a **Beat alignment reading (StemLab JSON)** field
14
+ and **Analysed Master Audio** attachment selection. Generate the reading from
15
+ saved detector evidence with current StemLab:
16
+
17
+ ```powershell
18
+ stemlab beat-offset RESULTS --output NEW-REPORT --audio EXACT-MASTER.mp3 `
19
+ --alignment-analysis consensus --alignment-bpm-basis canonical
20
+ ```
21
+
22
+ Use `combined_fit` when canonical BPM is unknown and the reviewed constant-grid
23
+ fit supports that choice. Review canonical, saved combined, half/same/double
24
+ interpretations and individual detectors first. A half-time result is a normal
25
+ metrical interpretation. Selecting a fitted tempo does not confirm canonical
26
+ BPM or first-downbeat authority.
27
+
28
+ Paste the exact `beat-alignment.json`, select its exact already public master
29
+ attachment and save through the existing site approval process. WordPress checks
30
+ the local attachment SHA-256, field bounds, numeric/rational consistency, source
31
+ frame bounds and BPM agreement before accepting the reading. Invalid input
32
+ preserves prior EPK timing fields; REST rejects it before content/meta writes.
33
+ Both new properties participate in revisions and the normal edit capability and
34
+ nonce protections. Unrecognized fields/private paths are omitted from public
35
+ configuration. No JSON upload permission or arbitrary filesystem path is added.
36
+
37
+ The attachment URL and normalized reading are localized as
38
+ `danceMovesConfig.beatAlignment`. The browser additionally checks exact rational
39
+ clock identity with BigInt. Native/master playback identity must match the
40
+ selected attachment URL before applying phase. An identified remote master may
41
+ supply `sourceUrl` in its verified master reference. Register a clip with the
42
+ existing `offset`, `duration`, `playerStart` and `masterVerified` mapping first.
43
+
44
+ `rhythmicTime(audio)` subtracts the first beat from the **mapped master time**;
45
+ `sourceTick(audio)` returns its fractional position at 16 ticks per beat. At the
46
+ first beat it is zero; before that it may be negative. This is the same as adding
47
+ the signed 64-pip offset and dividing by four. No integer rounding is introduced.
48
+ Core audio interval scheduling, procedural rudiments, playback pulses and sprite
49
+ cycles share this clock. Page-only clocks retain their own elapsed time.
50
+
51
+ ```js
52
+ const state = runtime.beatAlignmentState(master);
53
+ // applied, status, firstBeatSeconds, offsetPips, sourceSha256, bpmStatus
54
+ const ticks = runtime.sourceTick(master); // also works during paused seek review
55
+ ```
56
+
57
+ The audio, transport `currentTime`, lyric/cue timestamps and captured recording
58
+ sample clocks remain in original song time. The native frame's `sourceBeats`
59
+ remains the mapped source position for recorded movement; `rhythmicBeats`
60
+ exposes the aligned procedural position separately. Existing explicit sprite
61
+ phase offsets are additional choreography; audit them before migrating a page which
62
+ already compensates manually, to avoid applying the same phase twice.
63
+
64
+ Blank metadata means unverified phase. A hash mismatch is not a zero-offset
65
+ confirmation. Estimated phase stays estimated; an analysis-derived working BPM
66
+ has `bpmSource: 'analysis'`, separate from artist-confirmed canonical metadata.
67
+ An explicit stored BPM must agree with the selected reading (within its existing
68
+ three-decimal storage precision); the reading's full tempo precision is used.
69
+ The editor describes an active analysis-derived BPM explicitly; it does not
70
+ label that reading as the 120 BPM fallback. An invalid saved master association
71
+ shows an unavailable reading while retaining its metadata for correction.
72
+ A single page reading applies to its exact master only. Distinct tracks need
73
+ their own verified source association and scope; a title or equal duration is
74
+ insufficient. A constant grid is not proof of variable-tempo or whole-song fit.
75
+
76
+ Software publication does not deploy the WordPress plugin or change any EPK.
77
+ After approved deployment/save, verify installed/served version, fresh selected
78
+ metadata, exact hosted lyric/cue bytes, parser bounds, actual consumers, seek and
79
+ player switching, responsive output and preserved motion/accessibility controls.
package/lib/admin.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{(function(i){"use strict";function a(t){var e=String(t||"").toLowerCase().split(".");return e.length>1?e.pop():""}i(function(){i(document).on("click",".dance-moves-select-file",function(t){t.preventDefault();var e=i(this).closest(".dance-moves-file-field"),o=String(e.data("allowed-extensions")||"").split(",").filter(Boolean),l=wp.media({title:"Choose timing file",button:{text:"Use timing file"},multiple:!1});l.on("select",function(){var n=l.state().get("selection").first().toJSON(),f=a(n.filename);if(o.indexOf(f)===-1){window.alert("Choose a ."+o.join(" or .")+" timing file.");return}e.find("input[type=hidden]").val(n.id),e.find(".dance-moves-file-name").text(n.filename),e.find(".dance-moves-file-url").attr("href",n.url).prop("hidden",!1),e.find(".dance-moves-clear-file").prop("hidden",!1)}),l.open()}),i(document).on("click",".dance-moves-clear-file",function(t){t.preventDefault();var e=i(this).closest(".dance-moves-file-field");e.find("input[type=hidden]").val(""),e.find(".dance-moves-file-name").text("No file selected"),e.find(".dance-moves-file-url").attr("href","#").prop("hidden",!0),i(this).prop("hidden",!0)})})})(jQuery);})();
1
+ (()=>{(function(t){"use strict";function a(n){var e=String(n||"").toLowerCase().split(".");return e.length>1?e.pop():""}t(function(){t(document).on("click",".dance-moves-select-file",function(n){n.preventDefault();var e=t(this).closest(".dance-moves-file-field"),o=String(e.data("allowed-extensions")||"").split(",").filter(Boolean),l=wp.media({title:"Choose "+e.find("label").text(),button:{text:"Use selected file"},multiple:!1});l.on("select",function(){var i=l.state().get("selection").first().toJSON(),f=a(i.filename);if(o.indexOf(f)===-1){window.alert("Choose a ."+o.join(" or .")+" file.");return}e.find("input[type=hidden]").val(i.id),e.find(".dance-moves-file-name").text(i.filename),e.find(".dance-moves-file-url").attr("href",i.url).prop("hidden",!1),e.find(".dance-moves-clear-file").prop("hidden",!1)}),l.open()}),t(document).on("click",".dance-moves-clear-file",function(n){n.preventDefault();var e=t(this).closest(".dance-moves-file-field");e.find("input[type=hidden]").val(""),e.find(".dance-moves-file-name").text("No file selected"),e.find(".dance-moves-file-url").attr("href","#").prop("hidden",!0),t(this).prop("hidden",!0)})})})(jQuery);})();
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schema": "dancemoves-library-build/v1",
3
3
  "name": "@kieransimkin/dancemoves",
4
- "version": "3.2.0",
4
+ "version": "3.3.0",
5
5
  "homepage": "https://kieransimkin.co.uk/my-songs/",
6
6
  "files": [
7
7
  {
8
8
  "path": "admin.min.js",
9
- "bytes": 1157,
10
- "sha256": "db6ca41f28d0943a52c89093d279cc287a74702d412ea54c80b4c741525b9e43"
9
+ "bytes": 1164,
10
+ "sha256": "9f3ca5be76ca369ffb02c3977088d6b9304aa2038cd1bf9787936e518744aa0c"
11
11
  },
12
12
  {
13
13
  "path": "assets/DanceRudiments-build-manifest.json",
@@ -31,28 +31,28 @@
31
31
  },
32
32
  {
33
33
  "path": "dancemoves.min.js",
34
- "bytes": 218383,
35
- "sha256": "9a9afad98cbf15d3c8394a54809596d1ffe784f5ac7ca13484186ace3eb93661"
34
+ "bytes": 221968,
35
+ "sha256": "b10addc676f3e6040f08567659717452218b2a5e643bba9c5884c6b8326fae52"
36
36
  },
37
37
  {
38
38
  "path": "index.cjs",
39
- "bytes": 370576,
40
- "sha256": "ca7ed8da52270ee4a17f94672121f4182fa5cc8c5964c8d095a682978d1b4981"
39
+ "bytes": 376474,
40
+ "sha256": "cf55212b8ebdc691b03c12f8f623937f242744db8a50d24c221224f04379c069"
41
41
  },
42
42
  {
43
43
  "path": "index.d.ts",
44
- "bytes": 14929,
45
- "sha256": "477a8d665f245dbcff92cdc17372f39b54dbe3f9392695a00773f43b92288914"
44
+ "bytes": 15987,
45
+ "sha256": "1fdc5de3107b3f12cadd293c93f124c9ea4fe4ca6c648424d24c6728db454f1a"
46
46
  },
47
47
  {
48
48
  "path": "index.mjs",
49
- "bytes": 369431,
50
- "sha256": "6edacb0ded30311fc26bb80e86c772ba362c1b60c54a68b5ebaa2d3eb484ac16"
49
+ "bytes": 375300,
50
+ "sha256": "5f66f30766ff0199c83b25526cf103a92f5b7278ccfe4737fead1aec4d29895d"
51
51
  },
52
52
  {
53
53
  "path": "react.cjs",
54
- "bytes": 6595,
55
- "sha256": "ed117a524b15a7b28264e74267a80963c0bcb0ce7739d256a9089809cdd3f1bd"
54
+ "bytes": 7147,
55
+ "sha256": "87be24114d28e43ba9c04dc0af3ed239fcf6de5874e68828a1a2b13bc2e4fbff"
56
56
  },
57
57
  {
58
58
  "path": "react.d.ts",
@@ -61,8 +61,8 @@
61
61
  },
62
62
  {
63
63
  "path": "react.mjs",
64
- "bytes": 4909,
65
- "sha256": "9513a1e019df45b7eef1e8e703eabbd063ae6b80e3c5e30852cdd0a510f6a635"
64
+ "bytes": 5383,
65
+ "sha256": "c5882b16ad6660b94ad2f7651c2294fb65b5e1dbc9a053624b23fb4ecde6153b"
66
66
  },
67
67
  {
68
68
  "path": "rudiments.d.ts",
@@ -71,8 +71,8 @@
71
71
  },
72
72
  {
73
73
  "path": "server.cjs",
74
- "bytes": 21735,
75
- "sha256": "2db5e089683bc23768a5b233ff5c35fb4d3b5babe04a63232152d923feb2ab90"
74
+ "bytes": 25715,
75
+ "sha256": "38a59bc5ae969cfcdaf16d3b83020d4148a9a4e7df0b14de98a073bfb24589e0"
76
76
  },
77
77
  {
78
78
  "path": "server.d.ts",
@@ -81,8 +81,8 @@
81
81
  },
82
82
  {
83
83
  "path": "server.mjs",
84
- "bytes": 19290,
85
- "sha256": "cf6a3934f29feffb369ce1e78064e42854e8e10e2b6e457a9b12e41ca0e664af"
84
+ "bytes": 23270,
85
+ "sha256": "03e6f53a9a5d854bc55f762f00f46f767e423090dade9ea13355cd42a2fc6928"
86
86
  },
87
87
  {
88
88
  "path": "styles/clay-stars-effects.css",
@@ -106,8 +106,8 @@
106
106
  },
107
107
  {
108
108
  "path": "wordpress.js",
109
- "bytes": 217191,
110
- "sha256": "1b02054111edf66b3a5766c7da74291fe597d2ed3ac7a89f0f282cfb99c415df"
109
+ "bytes": 221102,
110
+ "sha256": "8fc80531c71a0a342284294e2e5eb0a845f1a7c3b93049e655b1f241f9d55b27"
111
111
  }
112
112
  ]
113
113
  }