@kieransimkin/dancemoves 3.0.2

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.
Files changed (50) hide show
  1. package/LICENSE +338 -0
  2. package/README.md +893 -0
  3. package/RUDIMENTS-API.md +394 -0
  4. package/docs/README.md +73 -0
  5. package/docs/api/adapters.md +400 -0
  6. package/docs/api/downloads.md +158 -0
  7. package/docs/api/effects.md +463 -0
  8. package/docs/api/javascript.md +500 -0
  9. package/docs/api/paper-planes.md +167 -0
  10. package/docs/api/styling.md +292 -0
  11. package/docs/api/surface.json +446 -0
  12. package/docs/api/wordpress.md +365 -0
  13. package/docs/clay-transform-validation.md +84 -0
  14. package/docs/development.md +254 -0
  15. package/docs/guide.md +288 -0
  16. package/docs/javascript-api.md +292 -0
  17. package/docs/javascript-server.md +150 -0
  18. package/docs/react-next.md +185 -0
  19. package/docs/releasing-shared.md +162 -0
  20. package/docs/rudiments-source-integrity.md +80 -0
  21. package/docs/shared-feature-coverage.md +34 -0
  22. package/docs/shared-runtime-migration.md +111 -0
  23. package/docs/source-audit.md +120 -0
  24. package/docs/validation-setup.md +102 -0
  25. package/docs/wordpress-examples.md +206 -0
  26. package/docs/wordpress-shared-runtime.md +133 -0
  27. package/lib/admin.min.js +1 -0
  28. package/lib/assets/DanceRudiments-LICENSE +21 -0
  29. package/lib/assets/DanceRudiments-build-manifest.json +21 -0
  30. package/lib/assets/paper-dreams-plane-atlas.png +0 -0
  31. package/lib/build-manifest.json +117 -0
  32. package/lib/dancemoves.css +9 -0
  33. package/lib/dancemoves.min.js +5 -0
  34. package/lib/index.cjs +4802 -0
  35. package/lib/index.d.ts +71 -0
  36. package/lib/index.mjs +4780 -0
  37. package/lib/react.cjs +154 -0
  38. package/lib/react.d.ts +12 -0
  39. package/lib/react.mjs +135 -0
  40. package/lib/rudiments.d.ts +124 -0
  41. package/lib/server.cjs +411 -0
  42. package/lib/server.d.ts +11 -0
  43. package/lib/server.mjs +367 -0
  44. package/lib/styles/clay-stars-effects.css +1 -0
  45. package/lib/styles/clay-stars-rudiments.css +1 -0
  46. package/lib/styles/dance-moves-core.css +1 -0
  47. package/lib/styles/ks-epk-device-orientation.css +1 -0
  48. package/lib/styles/paper-dreams-flight.css +1 -0
  49. package/lib/wordpress.js +5 -0
  50. package/package.json +101 -0
@@ -0,0 +1,254 @@
1
+ # Development, validation and operations
2
+
3
+ [Documentation index](README.md) · [Source audit](source-audit.md)
4
+
5
+ This guide describes the checked-in 2.8.0 tools, not a claim that a particular
6
+ machine, deployment or physical device has passed them. The authoritative
7
+ publication requirements remain [TEST-PLAN.md](../TEST-PLAN.md). The
8
+ [HARNESS-IMPLEMENTATION-PLAN.md](../HARNESS-IMPLEMENTATION-PLAN.md) contains planned
9
+ and staged work; its existence does not make every proposed feature a production
10
+ API or an implemented test command.
11
+
12
+ ## Repository layout
13
+
14
+ | Path | Role |
15
+ | --- | --- |
16
+ | `kieran-epk-device-orientation.php` | Plugin identity, page configuration, editor UI, REST capture, signed downloads and content transforms. |
17
+ | `assets/` | Production timing, catalogue, orientation, shared effects, paper-plane sprites, Clay/Stars and admin assets. |
18
+ | `docs/` | User guide and source-audited API reference. |
19
+ | `tests/` | Node contracts, PHP transform checks, integration fixtures and mobile capture/conformance utilities. |
20
+ | `tests/harness/plugin-core/` | Shared local harness assets/contracts. |
21
+ | `tests/harness/clay-stars/`, `tests/harness/california-screamin/` | Release-specific harness configurations. |
22
+ | `tools/` | Validation, preview building, read-only audits and packaging utilities. |
23
+ | `migration/`, `qa/` | Staged migration data and dated evidence. Do not interpret a historical result as approval for a new artifact. |
24
+ | `dist/` | Versioned WordPress ZIPs and manifests. These are not automatically regenerated by documentation edits. |
25
+
26
+ ## Normal unit validation
27
+
28
+ The existing coordinator is [tools/validate.ps1](../tools/validate.ps1), with:
29
+
30
+ | Argument | Meaning |
31
+ | --- | --- |
32
+ | `-Mode Unit` | Default. Lint, contracts, encoding, transforms and scaffold checks, without rebuilding migration/package artifacts. |
33
+ | `-Mode Package` | Explicitly rebuild migration and distribution artifacts and check package identity/layout. |
34
+ | `-Mode All` | Run Unit, then Package. This is not a read-only documentation check. |
35
+ | `-ReleasesRoot` | Optional release-workspace root forwarded to the migration builder in Package/All mode. Unit mode does not need it. |
36
+ | `-IncludeFailureFixture` | Deliberately exercise a syntax failure; valid only when Unit runs. Not a normal passing test run. |
37
+
38
+ The scripts assume the repository's Windows/PowerShell workflow, with `php`,
39
+ `node` and `python` on PATH. The source does not declare a definitive minimum
40
+ version matrix for these tools or for WordPress/PHP. Record actual versions used
41
+ rather than inventing a support guarantee. In particular, Package mode invokes
42
+ `powershell` explicitly and some paths/exclusions are Windows-specific.
43
+
44
+ ```powershell
45
+ powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\validate.ps1 -Mode Unit
46
+ ```
47
+
48
+ The process-scoped execution-policy argument does not change machine-wide
49
+ policy. Inspect scripts before running them. Unit mode performs PHP lint,
50
+ JavaScript syntax checks, sequential direct execution of each top-level
51
+ `tests/*.test.cjs`, PHP Clay transform/collision and download-path checks, shared/Clay harness
52
+ scaffold validation, UTF-8/null/replacement-character checks and plugin
53
+ name/version checks. It deliberately excludes the failing fixture from the
54
+ normal syntax scan.
55
+
56
+ **California Screamin' caveat:** the coordinator treats its full-page scaffold
57
+ audit failure as a warning because the page retains known width/background-position
58
+ blockers. Passing Unit is therefore not a statement that every release's browser,
59
+ visual, accessibility or performance gate passed.
60
+
61
+ The coordinator runs each Node contract as `node path/to/file.test.cjs`, not one
62
+ parallel `node --test` invocation. That is also the appropriate focused pattern:
63
+
64
+ ```sh
65
+ node tests/dance-moves-core.test.cjs
66
+ node tests/dance-moves-diagnostics.test.cjs
67
+ node tests/timed-lyric-popover.test.cjs
68
+ node tests/exact-cue-seek.test.cjs
69
+ node tests/cue-timeline.test.cjs
70
+ node tests/effects-primitives.test.cjs
71
+ node tests/epk-download-contract.test.cjs
72
+ node tests/paper-dreams-flight.test.cjs
73
+ node tests/catalogue-timing.test.cjs
74
+ node tests/clay-adapter.test.cjs
75
+ node tests/sensor-raf-scheduler.test.cjs
76
+ node tests/runtime.test.cjs
77
+ node tests/california-adapter.test.cjs
78
+ php tests/validate-clay-transform.php
79
+ php tests/validate-clay-legacy-collision.php
80
+ php tests/validate-epk-download-paths.php
81
+ ```
82
+
83
+ These focused commands do **not** replace the coordinator. Other checked-in
84
+ contract files cover WordPress metadata/uploads, shared component timing,
85
+ orientation maths, mobile API parity, capture duration and harness foundations.
86
+ See [tests/](../tests/) for the inventory. Use
87
+ [tools/test-validator-failure.ps1](../tools/test-validator-failure.ps1) when
88
+ verifying that the deliberate failure is correctly attributed and returns a
89
+ nonzero exit status.
90
+
91
+ ## Local harness workflow
92
+
93
+ Serve the repository rather than opening timing-fetch fixtures through `file:`:
94
+
95
+ ```sh
96
+ python -m http.server 8765 --bind 127.0.0.1
97
+ ```
98
+
99
+ From the resulting local site, open the appropriate checked-in fixture under
100
+ `tests/`, such as `dance-moves-integration.html`, `shared-component-timing.html`
101
+ or `mobile-harness.html`, plus `effects-primitives-preview.html` and
102
+ `paper-dreams-flight-preview.html`, or follow the release harness's own files. Supply only
103
+ approved, locally available media/manifests; repository fixtures are not proof
104
+ that an external canonical master exists on your machine. A local HTTP server
105
+ does not make a LAN-served page a secure physical-phone sensor origin.
106
+
107
+ The shared harness validation commands used by the coordinator are:
108
+
109
+ ```sh
110
+ python -X utf8 tools/validate-effect-harness.py tests/harness/plugin-core --mode scaffold
111
+ python -X utf8 tools/validate-effect-harness.py tests/harness/clay-stars --mode scaffold --manifest-file tests/harness/clay-stars/clay-stars.json --shared-root tests/harness/plugin-core
112
+ python -X utf8 tools/validate-effect-harness.py tests/harness/california-screamin --mode scaffold --manifest-file tests/harness/california-screamin/california-screamin.json --shared-root tests/harness/plugin-core
113
+ ```
114
+
115
+ The [validator source](../tools/validate-effect-harness.py), release manifests and
116
+ [test plan](../TEST-PLAN.md) define their expected evidence. Manifest-driven
117
+ master/timing/effect controls, deterministic input/cue simulation, attributed
118
+ handler timing, CSS-property audits and release snapshots are development
119
+ facilities. They are not an additional public production control plane.
120
+ `EPKEffectHarnessProbe`, simulated orientation events and capture/conformance
121
+ utilities under `tests/` must not be shipped as front-end dependencies.
122
+
123
+ When instrumenting the core, set `danceMovesConfig.diagnostics = true` **before**
124
+ the core asset executes, then install a bounded `setDiagnosticsSink()` receiver.
125
+ Give every cue/lyric/interval effect a stable attribution ID. The normal
126
+ WordPress configuration does not enable diagnostics. See
127
+ [diagnostics API](api/javascript.md#diagnostics) for the payloads and limits.
128
+
129
+ ## Release selection before changing documentation
130
+
131
+ Do not infer the latest plugin from the default branch. At this audit, `main`
132
+ remains 2.4.0 while the latest published tag is **v2.8.0**. The release commit is
133
+ `4cb6a71f60459b5579be87d7e55ac8b1426c578e`; the current staging branch is one
134
+ publication-evidence commit ahead, with identical production source and README.
135
+ Compare tags, release assets and staging before selecting a baseline.
136
+
137
+ This patch replaces the earlier 2.4.0 documentation patch; it is not incremental.
138
+ Apply to a clean 2.8.0/staging checkout without the previous patch's added `docs/`.
139
+ For example, after saving local work and placing the patch outside the checkout:
140
+
141
+ ```sh
142
+ git fetch origin timed-lyrics-staging-2026-09-20 --tags
143
+ git switch -c docs/complete-api-reference-v2.8.0 origin/timed-lyrics-staging-2026-09-20
144
+ git apply --check /path/to/DanceMoves-2.8.0-documentation.patch
145
+ git apply /path/to/DanceMoves-2.8.0-documentation.patch
146
+ ```
147
+
148
+ For an immutable release-based branch, use `v2.8.0` as the start point instead.
149
+ Review any newly fetched changes before applying. The commands do not push,
150
+ merge, rebuild a ZIP or write to WordPress. No PHP/JavaScript version bump is
151
+ required for a source-documentation change.
152
+
153
+ ## Acceptance checks for an integration
154
+
155
+ Exercise ordinary playback, pause/resume, end/replay, playback-rate changes,
156
+ forward/backward seeks, more than one player, absent/invalid timing files,
157
+ blank/repeated/long lyric lines and a dynamically inserted audio element. Check
158
+ that only master-length players bind and call `discoverAudio()` after deliberate
159
+ dynamic insertion. Recreate interval subscriptions around backward seeks when
160
+ required by the documented scheduling caveat.
161
+
162
+ For shared timelines, test zero-time cues, default/opt-in playing and paused
163
+ landings, duplicate IDs, overlapping intervals, gap discontinuities, rate changes,
164
+ callback failures and repeated teardown. Confirm full interval reconstruction,
165
+ not merely a transient class firing. The core landing policy is different from
166
+ the timeline's opt-in policy. Verify every `next*` and `nextVisible*` field across
167
+ blank cues and the final line.
168
+
169
+ For downloads, test real GET/HEAD and invalid signatures, local-file availability,
170
+ Unicode filenames, cached page links and the original player's seek behaviour.
171
+ For paper planes, test hero clipping/stacking, compact counts, offscreen pause,
172
+ reduced-motion hiding and the forced-colour CSS-versus-loop distinction. For the
173
+ shared quality controller, test a preference already active at initial mount.
174
+
175
+ Test at desktop, tablet and narrow-mobile widths, signed out, with reduced motion
176
+ and forced colours. Preserve complete readable lyrics, keyboard focus, controls,
177
+ safe areas and static artwork. Test both permissions granted and denied on actual
178
+ supported devices, plus hidden-tab/page lifecycle changes. Confirm the adapter's
179
+ root identity before interpreting diagnostic attributes.
180
+
181
+ Performance acceptance requires sustained-load measurements and recovery trials,
182
+ not merely a snapshot of `profile: "full"`. Record the exact plugin/source or
183
+ package hash, browser/device, viewport, time and evidence location. Synthetic
184
+ orientation events verify contracts, not native trust, physical-device smoothness
185
+ or input-to-display latency. The motion-capture schema stores orientation/parity
186
+ data; it does not contain all the physical performance telemetry required by the
187
+ test plan.
188
+
189
+ The plugin release gate and the EPK pre-live gate are independent. `BLOCKED` and
190
+ `NOT RUN` are not `PASS`. No WordPress upload, page-meta write, timing-media upload
191
+ or legacy-plugin deactivation is authorised merely by running a local test.
192
+
193
+ ## Packaging and upgrade identity
194
+
195
+ Only run the following for an intentional package/migration rebuild:
196
+
197
+ ```powershell
198
+ powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\validate.ps1 -Mode Package
199
+ ```
200
+
201
+ [tools/package.ps1](../tools/package.ps1) reads the version from the PHP header,
202
+ uses the root `kieran-epk-device-orientation/`, and includes **only** the entrypoint,
203
+ root `README.md` and `assets/`. It writes `dist/DanceMoves-<version>.zip` and the
204
+ matching package manifest, including ZIP/file hashes and layout checks. The
205
+ manifest builder is a separate step invoked by Package mode.
206
+
207
+ `docs/`, tests, tools, QA, migration evidence and master audio are not copied into
208
+ the WordPress ZIP by the current allowlist. The complete API reference lives in
209
+ the source repository; the root README links to it online for packaged readers.
210
+ This documentation patch deliberately does not alter that packaging policy,
211
+ regenerate immutable evidence, overwrite existing ZIPs or bump runtime versions.
212
+ A later intentional package rebuild will include the updated root README.
213
+
214
+ Do not rename the internal folder or PHP entrypoint to `DanceMoves`: WordPress
215
+ must recognise the same installed plugin on upgrade. Check both the artifact
216
+ identity and package layout before deployment. Preserve an exact rollback ZIP
217
+ and its checksum. Reactivating the old Clay/Stars effects plugin suppresses the
218
+ new page-252 takeover when its `KS_CLAY_STARS_EFFECTS_VERSION` constant is defined;
219
+ it is not a general rollback for the shared timing core.
220
+
221
+ ## Troubleshooting
222
+
223
+ | Symptom | Check / documented limitation |
224
+ | --- | --- |
225
+ | `DanceMoves` undefined | Script dependency/order, whether the request is a WordPress Page, footer output and browser console. The core has no public ready event or load promise; `dance-moves-effects-ready` belongs to the separate shared-effects layer. |
226
+ | Page shows fallback BPM | Metadata must be finite and within 20–400; blank/invalid values use 120 without claiming a known tempo. |
227
+ | Cue file has no entries | Use bracketed LRC-style timestamps, not CD `TRACK`/`INDEX` syntax. Blank cue labels are ignored. |
228
+ | Fetch failure looks like status `none` | Final initialisation overwrites the temporary `unavailable` marker. Inspect network/console and entry counts, not status alone. |
229
+ | Cue behaviour differs between integrations | Core LRC playback arms one cue within 50 ms, including at zero; the shared timeline fires crossings and has opt-in playing seek landings. Initialize persistent timeline state in render. |
230
+ | New audio does not follow cues | Insert it before discovery or call `discoverAudio()` after insertion; confirm metadata/duration and then normal playback events. |
231
+ | Repeating interval waits after backward seek | A retained interval boundary is not fully rebased; remove and recreate the subscription for that seek. |
232
+ | Custom lyric output remains visible on pause | `onLyric()` is not a complete playback-state stream. Handle pause/end for your custom renderer. |
233
+ | Lyric CSS does not match | The generated layer is under `body`, outside `.ks-epk`; component-local defaults also outrank merely inherited palette variables. |
234
+ | Phone UI absent | Production mobile/secure-context/sensor gate, root selector, adapter mapping, reduced motion and permission support. |
235
+ | Performance never reaches a fixed 60 FPS | Identify the controller: Clay uses median/p95 and probation; shared quality uses frame-count windows and fixed cooldowns. Neither proves physical refresh rate. |
236
+ | Paper snapshot reports 2.6.3 | This is the adapter-local marker; plugin `DanceMoves.version` is 2.8.0. |
237
+ | MP3 opens inline | Confirm the anchor has `download`, passed through main Page `the_content`, and matched the upload base. Direct player URLs intentionally stay inline. |
238
+ | Untouched assets fail byte hashes | Check `.gitattributes`, checkout line-ending conversion and the exact locked production bytes; never update locks merely to silence a mismatch. |
239
+ | A gate passes on a simulator but not a phone | Keep synthetic contracts and real physical-device evidence separate. |
240
+
241
+ For additional read-only inspection and preview utilities, inspect the commands
242
+ and assumptions in [tools/](../tools/): `audit-live-epk-motion.mjs`,
243
+ `capture-public-viewports.mjs`, `inspect-phone-epk.mjs`,
244
+ `build-clay-stars-preview.ps1` and `build-california-screamin-preview.ps1`.
245
+ No generic install command or undocumented command-line flags are implied here.
246
+
247
+ ## Documentation maintenance
248
+
249
+ Keep troubleshooting limited to reproducible current plugin or integration problems,
250
+ with checks and links to the relevant API contract. Put test prerequisites beside
251
+ the commands they affect. Do not accumulate one-time shell/automation mistakes,
252
+ resolved fixture bugs, private workspace notes or dated success reports in the
253
+ README. Retain release provenance in existing version-control and migration/QA
254
+ records; changing documentation is not a new deployment or validation result.
package/docs/guide.md ADDED
@@ -0,0 +1,288 @@
1
+ # User and integration guide
2
+
3
+ [Documentation index](README.md) · [JavaScript API](api/javascript.md) ·
4
+ [WordPress API](api/wordpress.md)
5
+
6
+ Source: [plugin entrypoint](../kieran-epk-device-orientation.php),
7
+ [timing runtime](../assets/dance-moves-core.js),
8
+ [catalogue adopter](../assets/dance-moves-catalogue-timing.js).
9
+ Baseline: **2.8.0 / `4cb6a71f60459b5579be87d7e55ac8b1426c578e`**.
10
+
11
+ ## Install and upgrade
12
+
13
+ Use the reviewed release asset `DanceMoves-2.8.0.zip` (also kept in `dist/`),
14
+ not a GitHub source archive, for a
15
+ WordPress installation. Confirm its matching manifest and hashes before upload.
16
+ The visible plugin name is **DanceMoves**, but the installed folder and entrypoint
17
+ remain `kieran-epk-device-orientation/kieran-epk-device-orientation.php`. Keep that
18
+ identity when upgrading; renaming the folder can create a parallel installation.
19
+
20
+ The plugin header does not declare a minimum WordPress or PHP version. Do not
21
+ infer a supported-version matrix from that absence. Verify the site's PHP,
22
+ WordPress metadata/revision behaviour and target browsers in staging. The browser
23
+ runtime uses modern DOM, Promise/fetch, animation-frame and Web Animations APIs.
24
+ Phone input also needs a supported, secure browser context.
25
+
26
+ The shared CSS, core JavaScript, shared effect primitives and catalogue adopter are enqueued on singular
27
+ WordPress **Pages**, not arbitrary posts or archive screens. Orientation is
28
+ additionally limited by the configured page-ID map. The plugin does not create an
29
+ EPK, a music player, a lyrics transcript, or a chapter-navigation interface.
30
+
31
+ ## Set page properties
32
+
33
+ Open the Page editor's **EPK Timing** meta box.
34
+
35
+ | Field | Input | Behaviour |
36
+ | --- | --- | --- |
37
+ | BPM | Finite 20–400, up to three stored decimal places | Blank clears the stored value. Unknown/invalid stored BPM resolves to 120 with `bpmSource: "fallback"`, not an assertion that the song is 120 BPM. |
38
+ | Lyric Timing File | Media Library `.lrc` attachment | The attachment ID is saved; its current URL is resolved when the page renders. |
39
+ | Cue Timing File | Media Library `.lrc` or `.cue` attachment | Uses the same bracketed timestamp grammar as LRC. |
40
+ | Timed lyric pop-ups | Checkbox, initially off | Enables the neutral built-in visual layer; it does not replace the complete readable lyric section. |
41
+ | Ambient effect | None or Paper planes | Stores `_dance_moves_effect` as `""` or `"paper-planes"`. Only the latter enqueues the plane assets; the page must supply `.ks-epk .epk-hero`. |
42
+
43
+ The hidden `_dance_moves_master_duration_ms` value is positive milliseconds, up to
44
+ one day, and is maintained through trusted server-side code rather than the meta
45
+ box or the standard page REST response. All six keys are registered for revision
46
+ support. See the [metadata reference](api/wordpress.md#page-metadata).
47
+
48
+ Editor saves require the plugin nonce, `edit_post` permission and a non-autosave
49
+ request. An invalid nonblank BPM or invalid timing attachment preserves that
50
+ field's previous value and queues an admin error; clearing a selection deletes
51
+ its metadata but **does not delete the shared Media Library attachment**. Fields
52
+ are saved independently, not as an atomic transaction. The checkbox is not
53
+ programmatically prevented from being enabled without a valid lyric file, so the
54
+ release review remains an explicit workflow requirement.
55
+
56
+ ## Prepare cue and lyric files
57
+
58
+ Files selected through the editor must be readable local Media Library
59
+ attachments, no larger than **1,048,576 bytes**, with strict UTF-8 and no null or
60
+ replacement characters. There must be at least one bracketed timestamp, and all
61
+ timestamp tokens in file order must be nondecreasing. Equal timestamps are
62
+ allowed. Lyric files use `.lrc`; cue files use `.lrc` or `.cue`.
63
+
64
+ Accepted timestamp syntax is `[M:SS]`, `[MM:SS.ff]`, `[MMM:SS.fff]`, or the same
65
+ fraction introduced with `:`. Minutes have one to three digits, seconds exactly
66
+ two, and fractions one to three. Fractions are decimal seconds, **not frames**.
67
+ Use seconds 00–59 in authored files even though the current parser's pattern does
68
+ not independently reject a higher two-digit seconds field.
69
+
70
+ Example cue file:
71
+
72
+ ```text
73
+ [00:04.000][SECTION: VERSE 1]
74
+ [00:20.000][SECTION: CHORUS 1]
75
+ [00:36.000]BREAK
76
+ ```
77
+
78
+ Example lyric file:
79
+
80
+ ```text
81
+ [00:00.000]
82
+ [00:04.000]First sung line
83
+ [00:08.000]Second sung line
84
+ [00:12.000]
85
+ [00:20.000]The repeated hook
86
+ [00:24.000]The repeated hook
87
+ ```
88
+
89
+ A blank timed lyric clears the display. It is ignored by the cue parser. Multiple
90
+ timestamps on one line generate multiple entries; make sure their physical order
91
+ still satisfies the server's monotonic check. The browser sorts parsed entries,
92
+ but that does not make an out-of-order upload valid in the editor.
93
+
94
+ Metadata-only lines are ignored by the browser parsers. LRC offset tags, enhanced
95
+ word-by-word timing and conventional CD `FILE`/`TRACK`/`INDEX` cuesheet syntax are
96
+ not implemented. Timing text is data, never executable code or HTML.
97
+
98
+ The two files are fetched separately using same-origin credentials and
99
+ `cache: "no-cache"`. Cross-origin hosting needs the browser to permit the fetch.
100
+ The browser parser itself does not repeat the server's byte-size or monotonicity
101
+ validation. REST/programmatic attachment assignments need explicit validation;
102
+ see [WordPress validation](api/wordpress.md#timing-attachment-validation).
103
+
104
+ ## Understand ticks before writing effects
105
+
106
+ One tick is **one sixteenth of a beat**, not a conventional sixteenth note:
107
+
108
+ ```text
109
+ one tick = 3750 / BPM milliseconds
110
+ one beat = 16 ticks
111
+ one 4/4 bar = 64 ticks
112
+ at 120 BPM = 31.25 ms/tick, 500 ms/beat, 2000 ms/bar
113
+ ```
114
+
115
+ Visual durations are rounded half upward to a positive integer tick. Results
116
+ above 16 are then rounded to the nearest multiple of 16, again half upward.
117
+ Consequently 17 duration ticks become 16; 24 become 32. Interval spacing uses
118
+ positive integer ticks without that long-duration quantisation. Use
119
+ `durationMilliseconds()` and the published CSS timing variables rather than
120
+ independent millisecond guesses.
121
+
122
+ The page clock starts when the core script evaluates. Playback interval helpers
123
+ wait for an active, matching audio element. `currentTick({clock: "audio"})` is a
124
+ special case: when no supplied/active audio is currently playing, it falls back to
125
+ the page clock. A paused song must therefore be guarded explicitly in a canvas
126
+ animation, rather than assuming that this call returns a frozen audio position.
127
+
128
+ There is no beat-offset, time-signature, variable-tempo or tempo-map setting. The
129
+ grid is anchored to audio time zero at a single BPM. For another meter, choose an
130
+ explicit interval, for example 48 ticks for three beats.
131
+
132
+ ## Connect audio
133
+
134
+ Ordinary `<audio>` elements are discovered after both timing-file loads settle.
135
+ The preferred matching reference is the configured master duration. Otherwise the
136
+ runtime uses the first element in document order matching
137
+ `audio[data-dance-moves-master], #ks-clay-stars-audio`, otherwise the first audio
138
+ element. Mark the canonical
139
+ player explicitly when a page contains previews or unrelated audio:
140
+
141
+ ```html
142
+ <audio id="release-audio" data-dance-moves-master controls preload="metadata">
143
+ <source src="/media/release-full-length.mp3" type="audio/mpeg">
144
+ </audio>
145
+ ```
146
+
147
+ A positive finite duration matches when the absolute difference is at most
148
+ `max(0.25, audio.duration / 100000)` seconds. A preview, differently trimmed master
149
+ or live/infinite-duration stream is not safely interchangeable with the canonical
150
+ programme. This is a duration check, not audio fingerprinting or beat alignment.
151
+
152
+ Matching players are marked `data-dance-moves-timing="master-length"`. Each has its
153
+ own cue cursor; interval helpers use the player most recently started via
154
+ `play`/`playing`. Owned animations follow playback-rate changes. Seeking reindexes
155
+ the cue cursor without replaying skipped cues; lyrics resume at the current line.
156
+ The core arms the earliest cue within 50 ms of an initial/seek position, including
157
+ a cue at zero. It dispatches that pending cue once at playback start, or when a
158
+ playing seek completes. Other skipped cues are not replayed. This is not general
159
+ state reconstruction: use `DanceMovesEffects.cueTimeline()` for active intervals
160
+ and deterministic seek restoration, and initialise persistent visuals in its
161
+ `render` callback. The two cue mechanisms have different landing policies; see
162
+ [core cue landings](api/javascript.md#exact-cue-landings) and
163
+ [cue timelines](api/effects.md#cuetimelineoptions).
164
+
165
+ For dynamically inserted audio, call `DanceMoves.discoverAudio()` after insertion.
166
+ There is no global audio MutationObserver. Install integrations before starting
167
+ playback; discovery is not a transport-control or automatic-play API. Avoid
168
+ simultaneous players: cues are per-player, but the lyric layer, ownership resets
169
+ and active interval clock are shared.
170
+
171
+ ## Subscribe and clean up
172
+
173
+ Enqueue a page script with `dance-moves-core` as a WordPress dependency. The global
174
+ is available when that script executes, but asynchronous timing fetches may still
175
+ be pending. There is no `DanceMoves.ready()` method or ready event.
176
+
177
+ ```js
178
+ (() => {
179
+ const dm = window.DanceMoves;
180
+ const root = document.querySelector('.ks-epk');
181
+ if (!dm || !root) return;
182
+
183
+ const disposers = [
184
+ dm.onCue('CHORUS 1', detail => {
185
+ root.dataset.section = detail.normalisedName;
186
+ }, { id: 'release:chorus-state' }),
187
+ dm.onEveryInterval(detail => {
188
+ root.dataset.barTick = String(detail.boundaryTick);
189
+ }, 64, { id: 'release:bar-state' })
190
+ ];
191
+
192
+ window.addEventListener('pagehide', () => {
193
+ disposers.forEach(remove => remove());
194
+ }, { once: true });
195
+ })();
196
+ ```
197
+
198
+ This simple example assumes a normal page load; an application restoring a page
199
+ from the back-forward cache must re-register its own disposed handlers on
200
+ `pageshow`. Keep stable diagnostic IDs, and prefer `onCue()`/`onLyric()` over a
201
+ second parser or clock. For DOM listeners, register on `document`: cue and lyric
202
+ events are dispatched there, not on each EPK child.
203
+
204
+ ## Adopt timed lyrics
205
+
206
+ A selected lyric file powers `onLyric()` even while the built-in pop-up is off.
207
+ The built-in layer is one body-level `.dance-moves-lyric-popover` containing a
208
+ `.dance-moves-lyric-popover__text`. It uses `textContent`, is noninteractive and
209
+ `aria-hidden`, hides on pause/end, and clears on a blank lyric. Reduced motion
210
+ keeps the words but removes entry/exit movement; forced colours have a fallback.
211
+
212
+ Before enabling it for a release, inspect that song's artwork and visual-language
213
+ record, distinguish observed/inferred/proposed/adopted decisions, and document a
214
+ distinctive treatment. Keep real text, full readable lyrics, safe areas and player
215
+ clearance. Test normal and long lines, blank clears, repeated hooks, seeking,
216
+ pause/resume/end, narrow screens, reduced motion and forced colours. A generic
217
+ checkbox-only adoption is not the approved workflow.
218
+
219
+ The renderer is appended to `body`, not inside `.ks-epk`. A selector such as
220
+ `.ks-epk .dance-moves-lyric-popover` will not reach it. Scope release styling through
221
+ an appropriate body page class or other release-specific ancestor context. See
222
+ [lyric styling](api/styling.md#timed-lyric-component).
223
+
224
+ Custom lyric consumers must handle audio `pause`/`ended` themselves when they need
225
+ to hide: `onLyric()` does not emit a synthetic blank on those events. It also does
226
+ not immediately replay the last value to a newly registered handler.
227
+
228
+ ## Use the shared effects API
229
+
230
+ Load after `dance-moves-effects`, or mount once in response to the document's
231
+ `dance-moves-effects-ready` event. Select the smallest matching primitive:
232
+ `pointer()` for bounded input, `playbackPulse()` for phase-aligned CSS,
233
+ `cueClass()` for a short cue-triggered class, `cueTimeline()` for reconstructable
234
+ playback state, and `quality()` for a reusable quality controller. Stable IDs
235
+ identify instances for `get()`, `snapshot()` and teardown. Each has explicit
236
+ options, callback payloads and disposal semantics in the [shared API](api/effects.md).
237
+ These are APIs, not auto-enabled visual presets. In particular, a cue timeline
238
+ accepts page-owned cue objects; it does not automatically import the Page cue LRC.
239
+
240
+ For paper planes, select **Ambient effect → Paper planes** and provide an existing
241
+ hero with explicit containment. Check full and compact counts, clipping, readable
242
+ controls and reduced motion before publication. See the [paper-plane API](api/paper-planes.md).
243
+
244
+ ## Provide MP3 downloads without breaking playback
245
+
246
+ Use an ordinary same-upload-host MP3 link with an explicit `download` attribute:
247
+
248
+ ```html
249
+ <a href="/wp-content/uploads/2026/09/example.mp3" download>Download MP3</a>
250
+ ```
251
+
252
+ On the main Page content render, DanceMoves rewrites eligible anchors to its
253
+ signed attachment endpoint. It does not rewrite players, `<source>` elements,
254
+ external media or links without `download`. Server-generated signed URLs are
255
+ shareable and do not expire automatically; they are not a private-media service.
256
+ The [download reference](api/downloads.md) covers URL helpers, request methods,
257
+ response headers, path validation and errors.
258
+
259
+ ## Adopt catalogue and orientation motion
260
+
261
+ The catalogue adopter chooses `.ks-epk` first, with specific fallback roots listed
262
+ in the [adapter reference](api/adapters.md#catalogue-timing). It converts owned
263
+ animation/transition durations and delays, preserving zero and special reduced-
264
+ motion/view-timeline sentinels. It also registers the release root for cue resets
265
+ and observes inserted elements/style-attribute changes. It does not change
266
+ artwork, invent choreography, rewrite keyframe geometry, or retime canvas code.
267
+
268
+ Phone orientation is a separate nine-page adapter map. The production wrapper
269
+ checks mobile eligibility and sensor support. Permission-requesting browsers get
270
+ **Use phone motion**; denied/unavailable input leaves the ordinary page usable.
271
+ Hidden pages, reduced motion and teardown stop input work; screen rotation
272
+ recalibrates it. Release-specific motion-off controls remain relevant. CSS
273
+ transitions interpolate targets published at a two-tick cadence; the two-second
274
+ rolling window is input processing, not a musical duration.
275
+
276
+ For Clay/Stars, keep the existing legacy effects plugin active until the approved
277
+ takeover. While `KS_CLAY_STARS_EFFECTS_VERSION` is defined, DanceMoves suppresses
278
+ its Clay CSS/JS and content transform. Deactivating the legacy plugin permits
279
+ takeover on a subsequent request. Do not transplant that release's artwork or
280
+ motion treatment onto other EPKs.
281
+
282
+ ## Diagnostics and deployment
283
+
284
+ Use [development and operations](development.md) for local tests, diagnostics,
285
+ performance tiers, approval gates and rollback. A motion capture is an explicit
286
+ submission of a supplied recording; ordinary plugin playback does not record or
287
+ upload phone samples. No WordPress upload, metadata write or deployment is part
288
+ of a documentation update.