@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.
- package/LICENSE +338 -0
- package/README.md +893 -0
- package/RUDIMENTS-API.md +394 -0
- package/docs/README.md +73 -0
- package/docs/api/adapters.md +400 -0
- package/docs/api/downloads.md +158 -0
- package/docs/api/effects.md +463 -0
- package/docs/api/javascript.md +500 -0
- package/docs/api/paper-planes.md +167 -0
- package/docs/api/styling.md +292 -0
- package/docs/api/surface.json +446 -0
- package/docs/api/wordpress.md +365 -0
- package/docs/clay-transform-validation.md +84 -0
- package/docs/development.md +254 -0
- package/docs/guide.md +288 -0
- package/docs/javascript-api.md +292 -0
- package/docs/javascript-server.md +150 -0
- package/docs/react-next.md +185 -0
- package/docs/releasing-shared.md +162 -0
- package/docs/rudiments-source-integrity.md +80 -0
- package/docs/shared-feature-coverage.md +34 -0
- package/docs/shared-runtime-migration.md +111 -0
- package/docs/source-audit.md +120 -0
- package/docs/validation-setup.md +102 -0
- package/docs/wordpress-examples.md +206 -0
- package/docs/wordpress-shared-runtime.md +133 -0
- package/lib/admin.min.js +1 -0
- package/lib/assets/DanceRudiments-LICENSE +21 -0
- package/lib/assets/DanceRudiments-build-manifest.json +21 -0
- package/lib/assets/paper-dreams-plane-atlas.png +0 -0
- package/lib/build-manifest.json +117 -0
- package/lib/dancemoves.css +9 -0
- package/lib/dancemoves.min.js +5 -0
- package/lib/index.cjs +4802 -0
- package/lib/index.d.ts +71 -0
- package/lib/index.mjs +4780 -0
- package/lib/react.cjs +154 -0
- package/lib/react.d.ts +12 -0
- package/lib/react.mjs +135 -0
- package/lib/rudiments.d.ts +124 -0
- package/lib/server.cjs +411 -0
- package/lib/server.d.ts +11 -0
- package/lib/server.mjs +367 -0
- package/lib/styles/clay-stars-effects.css +1 -0
- package/lib/styles/clay-stars-rudiments.css +1 -0
- package/lib/styles/dance-moves-core.css +1 -0
- package/lib/styles/ks-epk-device-orientation.css +1 -0
- package/lib/styles/paper-dreams-flight.css +1 -0
- package/lib/wordpress.js +5 -0
- package/package.json +101 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# WordPress, PHP and REST API reference
|
|
2
|
+
|
|
3
|
+
[Documentation index](../README.md) · [JavaScript API](javascript.md)
|
|
4
|
+
|
|
5
|
+
Source: [kieran-epk-device-orientation.php](../../kieran-epk-device-orientation.php).
|
|
6
|
+
Baseline: **2.8.0 / `4cb6a71f60459b5579be87d7e55ac8b1426c578e`**.
|
|
7
|
+
All PHP calls below run inside a loaded WordPress environment. Callback functions
|
|
8
|
+
are globally visible PHP symbols, not a promise of a separately versioned SDK.
|
|
9
|
+
Prefer the explicit configuration, sanitisation and validation helpers to invoking
|
|
10
|
+
registration, rendering or save callbacks manually.
|
|
11
|
+
|
|
12
|
+
## Constants
|
|
13
|
+
|
|
14
|
+
| Constant | Value / purpose |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `DANCE_MOVES_VERSION` | `2.8.0` |
|
|
17
|
+
| `KS_EPK_ORIENTATION_VERSION` | Alias of `DANCE_MOVES_VERSION`. |
|
|
18
|
+
| `KS_EPK_MOTION_CAPTURE_TOKEN` | Existing fixed capture submission token; deliberately not reproduced here. It is in public source and is **not a deployment secret**. See the capture security section. |
|
|
19
|
+
| `DANCE_MOVES_META_BPM` | `_dance_moves_bpm` |
|
|
20
|
+
| `DANCE_MOVES_META_LYRIC_TIMING` | `_dance_moves_lyric_timing_id` |
|
|
21
|
+
| `DANCE_MOVES_META_CUE_TIMING` | `_dance_moves_cue_timing_id` |
|
|
22
|
+
| `DANCE_MOVES_META_LYRIC_POPUPS` | `_dance_moves_lyric_popups_enabled` |
|
|
23
|
+
| `DANCE_MOVES_META_MASTER_DURATION` | `_dance_moves_effect` | `string` / `""` | `dance_moves_sanitize_effect`: sanitised key restricted to `""` / `"paper-planes"`. | Yes |
|
|
24
|
+
| `_dance_moves_master_duration_ms` |
|
|
25
|
+
| `DANCE_MOVES_CLAY_STARS_PAGE_ID` | `252` |
|
|
26
|
+
| `DANCE_MOVES_META_EFFECT` | `_dance_moves_effect` |
|
|
27
|
+
| `DANCE_MOVES_DOWNLOAD_QUERY_VAR` | `dance_moves_download` |
|
|
28
|
+
| `DANCE_MOVES_DOWNLOAD_SIGNATURE_QUERY_VAR` | `dance_moves_download_signature` |
|
|
29
|
+
|
|
30
|
+
`KS_CLAY_STARS_EFFECTS_VERSION` is an **external legacy-plugin marker**, not a
|
|
31
|
+
constant defined here. Its presence suppresses DanceMoves' Clay effects assets
|
|
32
|
+
and content transformation. The plugin's own constants are defined unconditionally;
|
|
33
|
+
predefining them is not a supported configuration override mechanism.
|
|
34
|
+
|
|
35
|
+
## Page metadata
|
|
36
|
+
|
|
37
|
+
All keys are registered for post type `page`, as single values, with
|
|
38
|
+
`revisions_enabled: true`. `dance_moves_meta_auth()` requires
|
|
39
|
+
`current_user_can('edit_post', $post_id)`. The plugin also adds the six keys to
|
|
40
|
+
`wp_post_revision_meta_keys`. Revision support still depends on the site's
|
|
41
|
+
WordPress version and revision configuration.
|
|
42
|
+
|
|
43
|
+
| Key | Registered type / default | Sanitiser | Standard REST exposure |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `_dance_moves_bpm` | `number` / 0 | Finite 20–400, rounded to 3 decimals; invalid/blank becomes `''`. | Yes |
|
|
46
|
+
| `_dance_moves_lyric_timing_id` | `integer` / 0 | `absint()` only. | Yes |
|
|
47
|
+
| `_dance_moves_cue_timing_id` | `integer` / 0 | `absint()` only. | Yes |
|
|
48
|
+
| `_dance_moves_lyric_popups_enabled` | `boolean` / false | `rest_sanitize_boolean`. | Yes |
|
|
49
|
+
| `_dance_moves_effect` | `string` / `""` | `dance_moves_sanitize_effect`: sanitised key restricted to `""` / `"paper-planes"`. | Yes |
|
|
50
|
+
| `_dance_moves_master_duration_ms` | `number` / 0 | Positive finite milliseconds, at most 86,400,000, rounded to 3 decimals; otherwise 0. | **No** |
|
|
51
|
+
|
|
52
|
+
These are metadata on the ordinary WordPress Page REST resource, not a separate
|
|
53
|
+
`/dance-moves` endpoint. The usual resource is `/wp-json/wp/v2/pages/<id>`; use the
|
|
54
|
+
site's actual REST root, including a subdirectory or `?rest_route=` form where
|
|
55
|
+
applicable. Normal WordPress authentication and edit permissions apply to writes.
|
|
56
|
+
|
|
57
|
+
Illustrative **authenticated** page update body:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"meta": {
|
|
62
|
+
"_dance_moves_bpm": 120,
|
|
63
|
+
"_dance_moves_lyric_timing_id": 1234,
|
|
64
|
+
"_dance_moves_cue_timing_id": 1235,
|
|
65
|
+
"_dance_moves_lyric_popups_enabled": false,
|
|
66
|
+
"_dance_moves_effect": ""
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The attachment IDs above are examples, not existing media. Use IDs validated for
|
|
72
|
+
this site. The editor's invalid-value preservation and full attachment-content
|
|
73
|
+
validation are **not** implemented as REST pre-update validation. A REST write
|
|
74
|
+
only uses registered type/schema checks and sanitisation; `absint()` does not
|
|
75
|
+
prove attachment type, readability, file extension, UTF-8 or timing order.
|
|
76
|
+
Do not send an empty string as though it were a valid REST number: use a validated
|
|
77
|
+
BPM or clear metadata through an appropriate trusted WordPress path. Defaults
|
|
78
|
+
such as zero mean unknown, not a valid musical BPM.
|
|
79
|
+
|
|
80
|
+
### Trusted PHP integration
|
|
81
|
+
|
|
82
|
+
Validate before calling `update_post_meta()`, and retain the caller's own nonce
|
|
83
|
+
and capability checks for any custom admin endpoint. Example inside an authorised
|
|
84
|
+
save operation, with `$page_id` and `$attachment_id` already resolved:
|
|
85
|
+
|
|
86
|
+
```php
|
|
87
|
+
if (!current_user_can('edit_post', $page_id)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
$valid = dance_moves_validate_timing_attachment($attachment_id, 'lyric');
|
|
91
|
+
if (is_wp_error($valid)) {
|
|
92
|
+
// Return/display this error through the calling integration's error path.
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
update_post_meta($page_id, DANCE_MOVES_META_LYRIC_TIMING, absint($attachment_id));
|
|
96
|
+
|
|
97
|
+
$duration = dance_moves_sanitize_duration(183420.125);
|
|
98
|
+
if ($duration > 0) {
|
|
99
|
+
update_post_meta($page_id, DANCE_MOVES_META_MASTER_DURATION, $duration);
|
|
100
|
+
}
|
|
101
|
+
$config = dance_moves_get_page_config($page_id);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This does not authorise an unauthenticated caller or implement a complete custom
|
|
105
|
+
save route. `update_post_meta()` is not a substitute for the integration's access
|
|
106
|
+
control, and individual field updates are not an atomic multi-field transaction.
|
|
107
|
+
|
|
108
|
+
## Configuration and sanitisation helpers
|
|
109
|
+
|
|
110
|
+
| Function | Return and behaviour |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `dance_moves_orientation_adapters()` | `array<int,string>` mapping the nine configured Page IDs to adapter names; see [adapters](adapters.md#orientation-page-map). |
|
|
113
|
+
| `dance_moves_shared_control_pages()` | Array of Page IDs receiving 8-tick shared-control transitions: `250, 254, 260, 262, 264, 266, 272, 274, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 300, 302, 304, 306, 308, 312, 314, 316, 318, 320, 322`. |
|
|
114
|
+
| `dance_moves_lyric_disclosure_ticks($page_id)` | `5` for 130, `7` for 243, otherwise `6`. |
|
|
115
|
+
| `dance_moves_attachment_url($attachment_id)` | Absolute integer ID lookup with `wp_get_attachment_url()` and `esc_url_raw()`; empty string for no ID/unusable URL. Does not run timing validation. |
|
|
116
|
+
| `dance_moves_get_page_config($page_id)` | Configuration array described below. Reads page meta, resolves URLs and assigns fallback BPM/provenance. No writes. |
|
|
117
|
+
| `dance_moves_sanitize_bpm($value)` | Number rounded to 3 decimals for finite numeric 20–400; `''` for blank/null/invalid input. |
|
|
118
|
+
| `dance_moves_sanitize_attachment_id($value)` | `absint($value)`; no existence or content check. |
|
|
119
|
+
| `dance_moves_sanitize_duration($value)` | Positive finite milliseconds up to one day, rounded to 3 decimals; otherwise 0. |
|
|
120
|
+
| `dance_moves_sanitize_effect($value)` | Runs `sanitize_key((string) $value)`, accepts only empty string or `paper-planes`, otherwise returns empty string. |
|
|
121
|
+
| `dance_moves_meta_auth($allowed, $meta_key, $post_id)` | Boolean from `current_user_can('edit_post', $post_id)`; the first two arguments do not alter the decision. |
|
|
122
|
+
| `ks_epk_motion_finite_number($value, $minimum, $maximum)` | Float for numeric, finite, inclusive-range input, otherwise `null`. Numeric strings are accepted. |
|
|
123
|
+
|
|
124
|
+
`dance_moves_get_page_config()` returns all of:
|
|
125
|
+
`pageId`, `version`, `bpm`, `bpmSource`, `fallbackBpm`, `lyricTimingUrl`,
|
|
126
|
+
`lyricPopupsEnabled`, `cueTimingUrl`, `masterDurationMilliseconds`,
|
|
127
|
+
`tickDefinition`, `ticksPerBeat`, `longDurationQuantumTicks`, `sharedControlTicks`,
|
|
128
|
+
`lyricDisclosureTicks`, `effect`. See the [boot table](javascript.md#boot-object-windowdancemovesconfig)
|
|
129
|
+
for their values. This helper does not emit `diagnostics` or a capture credential.
|
|
130
|
+
Its read-time duration check accepts a positive numeric value; use the duration
|
|
131
|
+
sanitiser on writes rather than relying on this reader to enforce the one-day cap.
|
|
132
|
+
|
|
133
|
+
## Timing attachment validation
|
|
134
|
+
|
|
135
|
+
### `dance_moves_validate_timing_attachment($attachment_id, $kind)`
|
|
136
|
+
|
|
137
|
+
Returns `true` or `WP_Error`. Zero/empty ID is a valid cleared selection. `$kind`
|
|
138
|
+
equal to `'lyric'` permits only `.lrc`; every other kind uses the cue extension
|
|
139
|
+
set `.lrc`/`.cue`. This is not an enum-validating argument.
|
|
140
|
+
|
|
141
|
+
| Error code | Validation failure |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `dance_moves_attachment` | ID is not a WordPress attachment. |
|
|
144
|
+
| `dance_moves_file` | Missing/unreadable path, or file larger than 1 MiB. |
|
|
145
|
+
| `dance_moves_extension` | Extension invalid for the selected field. |
|
|
146
|
+
| `dance_moves_utf8` | Unreadable contents, invalid UTF-8, null or U+FFFD replacement character. |
|
|
147
|
+
| `dance_moves_timestamps` | No recognised bracketed timestamp token. |
|
|
148
|
+
| `dance_moves_order` | Timestamp tokens decrease in physical file order. |
|
|
149
|
+
|
|
150
|
+
The validator does not check media ownership, attachment-level read permission,
|
|
151
|
+
lyric accuracy, master identity, a seconds-field range of 00–59, or whether the
|
|
152
|
+
file contains a nonblank displayable lyric. It reads `get_attached_file()` locally;
|
|
153
|
+
remote-only offloaded media may need an accessible local copy for editor validation.
|
|
154
|
+
|
|
155
|
+
### Upload hooks versus selection validation
|
|
156
|
+
|
|
157
|
+
`dance_moves_timing_upload_mimes($mimes)` returns the array with `lrc` and `cue`
|
|
158
|
+
set to `text/plain`.
|
|
159
|
+
|
|
160
|
+
`dance_moves_timing_filetype($data, $file, $filename, $mimes)` is the four-argument
|
|
161
|
+
`wp_check_filetype_and_ext` filter. For recognised extensions with readable
|
|
162
|
+
contents no larger than 1 MiB, no nulls and valid UTF-8, it sets `ext`, `type` and
|
|
163
|
+
`proper_filename`. Otherwise it returns the incoming data unchanged. It does
|
|
164
|
+
**not** perform the selection validator's timestamp-order or replacement-character
|
|
165
|
+
checks, and returning unchanged data is not itself a guaranteed upload rejection.
|
|
166
|
+
The full validator runs when the Page editor saves the selected attachment.
|
|
167
|
+
|
|
168
|
+
## Motion-capture REST API
|
|
169
|
+
|
|
170
|
+
### Endpoint and permission contract
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
POST <WordPress REST root>/ks-epk-motion/v1/capture
|
|
174
|
+
Content-Type: application/json
|
|
175
|
+
X-KS-Motion-Token: <operator-supplied value; not reproduced here>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Implemented by `ks_epk_motion_register_rest_route()` using
|
|
179
|
+
`WP_REST_Server::CREATABLE`, permission callback
|
|
180
|
+
`ks_epk_motion_capture_permission(WP_REST_Request $request)` and handler
|
|
181
|
+
`ks_epk_motion_store_capture(WP_REST_Request $request)`.
|
|
182
|
+
|
|
183
|
+
Permission processing, in order:
|
|
184
|
+
|
|
185
|
+
1. Compare the supplied header with the fixed token using `hash_equals()`.
|
|
186
|
+
2. When `get_http_origin()` returns an origin, require it to equal `home_url()`
|
|
187
|
+
after trailing-slash removal. A missing Origin is **not rejected**.
|
|
188
|
+
3. Rate-limit by a transient keyed from MD5 of `REMOTE_ADDR` (or `'unknown'`).
|
|
189
|
+
Eight accepted permission checks are allowed before a 429. Each allowed check
|
|
190
|
+
writes a new ten-minute expiry; this is not a rigorously sliding-window quota.
|
|
191
|
+
A later-invalid payload still consumes a permission-check attempt.
|
|
192
|
+
|
|
193
|
+
**Security limitation:** the token is embedded in this public repository. The
|
|
194
|
+
endpoint does not require a logged-in user, a WordPress capability or a WordPress
|
|
195
|
+
nonce. Origin checking and a shared IP transient do not turn a published constant
|
|
196
|
+
into authentication. Do not document this as a secure secret-protected upload
|
|
197
|
+
service. Restrict/disable access or implement genuine authenticated capture
|
|
198
|
+
submission before relying on it in a new deployment. This documentation patch
|
|
199
|
+
does not change the endpoint's security model or rotate its constant.
|
|
200
|
+
|
|
201
|
+
### Request shape
|
|
202
|
+
|
|
203
|
+
Required: `schema` exactly `"ks-epk-motion-recording/v1"`, and `samples`, an array
|
|
204
|
+
of **1–500** sample objects. The entire request is treated as untrusted data.
|
|
205
|
+
Unknown fields are discarded when the clean payload is built.
|
|
206
|
+
|
|
207
|
+
| Top-level field | Accepted / stored behaviour |
|
|
208
|
+
| --- | --- |
|
|
209
|
+
| `schema` | Required exact schema string. |
|
|
210
|
+
| `capturedAt` | Sanitised text, default `""`; not parsed as a date. |
|
|
211
|
+
| `userAgent` | Sanitised text, default `""`. |
|
|
212
|
+
| `screenAngle` | Finite numeric -360–360, default 0; invalid becomes `null`. |
|
|
213
|
+
| `targetDurationMilliseconds` | Finite numeric 0–120000, default 0; invalid becomes `null`. |
|
|
214
|
+
| `captureDurationMilliseconds` | Same range/default. |
|
|
215
|
+
| `sampledDurationMilliseconds` | Same range/default. |
|
|
216
|
+
| `processedPairCount` | `absint()`, capped at 100000; defaults to validated sample count. |
|
|
217
|
+
| `storedSampleCount` | Recomputed from samples; a supplied value is ignored. |
|
|
218
|
+
| `storageIntervalMilliseconds` | Finite numeric 0–120000, default 0; invalid becomes `null`. |
|
|
219
|
+
| `sampleStrategy` | `sanitize_key()`, default `"legacy"`. |
|
|
220
|
+
| `fullWindowObserved` | Boolean derived with `!empty()`. |
|
|
221
|
+
| `expectedDifference` | Sanitised text, default `""`. |
|
|
222
|
+
| `passed` | Boolean derived with `!empty()`; this is a caller claim, not server-verified conformance. |
|
|
223
|
+
| `failureCount` | `absint()`, capped at 100000; defaults to cleaned failure count. |
|
|
224
|
+
| `failures` | Optional array; only first 100 input entries considered, nonobjects skipped. |
|
|
225
|
+
| `samples` | Required 1–500 valid sample objects. |
|
|
226
|
+
|
|
227
|
+
Each sample:
|
|
228
|
+
|
|
229
|
+
| Field | Validation / output |
|
|
230
|
+
| --- | --- |
|
|
231
|
+
| `milliseconds` | Required numeric finite 0–120000. |
|
|
232
|
+
| `beta` | Required numeric finite -180–180. |
|
|
233
|
+
| `gamma` | Required numeric finite -90–90. |
|
|
234
|
+
| `alpha` | Optional/null; otherwise numeric finite 0–360; invalid becomes `null`. |
|
|
235
|
+
| `screenAngle` | Optional numeric finite -360–360, default 0; invalid becomes `null`. |
|
|
236
|
+
| `absolute` | Boolean from `!empty()`. |
|
|
237
|
+
| `nativeTrusted` | Boolean from `!empty()`; not independently authenticated. |
|
|
238
|
+
| `simulatedTrusted` | Boolean from `!empty()`. |
|
|
239
|
+
| `fieldParity` | Boolean from `!empty()`. |
|
|
240
|
+
| `dispatchParity` | Boolean from `!empty()`. |
|
|
241
|
+
| `mapperParity` | Boolean from `!empty()`. |
|
|
242
|
+
|
|
243
|
+
A nonobject sample or invalid `milliseconds`/`beta`/`gamma` invalidates the whole
|
|
244
|
+
capture; samples are not silently removed on a successful submission. Numeric
|
|
245
|
+
strings pass `is_numeric()`. Sample ordering, actual observation duration, event
|
|
246
|
+
trust and parity are not verified by this endpoint. Use JSON booleans, not strings
|
|
247
|
+
such as `"false"`, since PHP `!empty()` treats nonempty strings as true.
|
|
248
|
+
|
|
249
|
+
Each retained failure becomes:
|
|
250
|
+
`{type: sanitize_key(string or "unknown"), sample: absint or null,
|
|
251
|
+
validPairs: absint or null}`. The supplied counts do not have to agree with the
|
|
252
|
+
booleans or retained arrays.
|
|
253
|
+
|
|
254
|
+
Minimal illustrative request (not a physical-device acceptance record):
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"schema": "ks-epk-motion-recording/v1",
|
|
259
|
+
"capturedAt": "2026-09-29T00:00:00Z",
|
|
260
|
+
"passed": false,
|
|
261
|
+
"sampleStrategy": "manual-example",
|
|
262
|
+
"samples": [
|
|
263
|
+
{"milliseconds": 0, "alpha": null, "beta": 0, "gamma": 0, "screenAngle": 0}
|
|
264
|
+
]
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Response, errors and storage
|
|
269
|
+
|
|
270
|
+
Success returns a normal REST response (no explicit 201 status is set):
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{"captureId": 123, "sampleCount": 1, "storedPrivately": true}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
| HTTP status | Error code | Meaning |
|
|
277
|
+
| --- | --- | --- |
|
|
278
|
+
| 403 | `ks_motion_forbidden` | Missing/wrong token. |
|
|
279
|
+
| 403 | `ks_motion_origin` | Supplied origin does not match the site. |
|
|
280
|
+
| 429 | `ks_motion_rate` | Permission-check quota exhausted. |
|
|
281
|
+
| 400 | `ks_motion_schema` | Missing/wrong schema or nonarray JSON payload. |
|
|
282
|
+
| 400 | `ks_motion_samples` | Missing/nonarray samples or input count outside 1–500. |
|
|
283
|
+
| 400 | `ks_motion_invalid_samples` | At least one required sample field is invalid. |
|
|
284
|
+
| 413 | `ks_motion_size` | Clean JSON encoding fails or exceeds 262144 bytes. |
|
|
285
|
+
| WordPress-defined | WordPress insertion error | A `WP_Error` from `wp_insert_post()` is passed through. |
|
|
286
|
+
|
|
287
|
+
The size limit is on the **sanitised, pretty-printed encoded payload**, not an
|
|
288
|
+
up-front raw request-body limiter. Normal WordPress/server request parsing and
|
|
289
|
+
limits remain separate.
|
|
290
|
+
|
|
291
|
+
A successful record is a `private` post of type `ks_motion_capture`, titled
|
|
292
|
+
`Phone motion capture <site-local date/time>`, with the cleaned JSON in
|
|
293
|
+
`post_content`. Extra metadata: `_ks_motion_passed` (`'1'`/`'0'`),
|
|
294
|
+
`_ks_motion_sample_count`, and `_ks_motion_sha256` (hash of stored encoded JSON).
|
|
295
|
+
The post type has a Tools-menu UI, title/editor support, `public: false`,
|
|
296
|
+
`show_in_rest: false`, and default mapped post capabilities; no custom
|
|
297
|
+
administrator-only capability scheme is defined.
|
|
298
|
+
|
|
299
|
+
There is **no plugin GET/list/delete capture REST route, retention job, automatic
|
|
300
|
+
capture upload, or cryptographic proof of native sensor provenance**. Private
|
|
301
|
+
storage does not mean anonymous data or verified evidence. Review data retention
|
|
302
|
+
and access through normal authorised WordPress operations.
|
|
303
|
+
|
|
304
|
+
## Enqueued asset contract
|
|
305
|
+
|
|
306
|
+
| Handle | Type | Dependencies | Scope |
|
|
307
|
+
| --- | --- | --- | --- |
|
|
308
|
+
| `dance-moves-core` | CSS and JS | None | Singular Pages; JS in footer; localises `danceMovesConfig`. |
|
|
309
|
+
| `dance-moves-effects` | JS | `dance-moves-core` | Singular Pages; footer; installs `DanceMovesEffects`. |
|
|
310
|
+
| `dance-moves-paper-dreams` | CSS and JS | `dance-moves-core` for both | Only when `effect === "paper-planes"`; JS localises `danceMovesPaperDreamsConfig`; footer. |
|
|
311
|
+
| `dance-moves-catalogue-timing` | JS | `dance-moves-core`, `dance-moves-effects` | Same Page gate; footer. |
|
|
312
|
+
| `dance-moves-clay-stars` | CSS and JS | JS: `dance-moves-core` | Page 252, only without the legacy marker. |
|
|
313
|
+
| `ks-epk-device-orientation` | CSS | None | Configured orientation pages. |
|
|
314
|
+
| `ks-epk-device-orientation-core` | JS | None | Configured orientation pages. |
|
|
315
|
+
| `ks-epk-device-orientation` | JS | Orientation core and `dance-moves-core`; also Clay JS when applicable | Localises `ksEpkOrientationConfig`; footer. |
|
|
316
|
+
| `dance-moves-admin` | JS | `jquery` | Page editing on `post.php` / `post-new.php`; loads the Media Library picker. |
|
|
317
|
+
|
|
318
|
+
Runtime asset versions use the plugin version. To load a page integration, enqueue
|
|
319
|
+
it with `array('dance-moves-core')` for core-only consumers or
|
|
320
|
+
`array('dance-moves-effects')` for shared primitives; add `dance-moves-catalogue-timing` or
|
|
321
|
+
`dance-moves-clay-stars` when those optional surfaces are actually required and
|
|
322
|
+
available. Do not assume a root exists merely because the shared script loaded.
|
|
323
|
+
|
|
324
|
+
## Registered hooks and callback reference
|
|
325
|
+
|
|
326
|
+
These are WordPress hooks **consumed** by the plugin, not plugin-defined extension
|
|
327
|
+
hooks. Default priority is 10 unless shown. No `apply_filters('dance_moves_...')`
|
|
328
|
+
or `do_action('dance_moves_...')` extension contract is exposed in this baseline.
|
|
329
|
+
|
|
330
|
+
| Hook | Callback | Role |
|
|
331
|
+
| --- | --- | --- |
|
|
332
|
+
| `wp_enqueue_scripts` (20) | `ks_epk_orientation_enqueue_runtime()` | Enqueues assets/localises configuration after Page gating; returns no value. |
|
|
333
|
+
| `init` | `ks_epk_motion_register_capture_type()` | Registers private capture post type; no value. |
|
|
334
|
+
| `init` | `dance_moves_register_page_meta()` | Registers the six Page-meta schemas; no value. |
|
|
335
|
+
| `rest_api_init` | `ks_epk_motion_register_rest_route()` | Registers capture POST route; no value. |
|
|
336
|
+
| `wp_post_revision_meta_keys` | `dance_moves_revision_meta_keys($keys)` | Returns unique merge of incoming keys and the six DanceMoves keys. |
|
|
337
|
+
| `add_meta_boxes_page` | `dance_moves_add_meta_box()` | Registers side/default `dance-moves-epk-timing` meta box; no value. |
|
|
338
|
+
| `admin_enqueue_scripts` | `dance_moves_admin_assets($hook)` | Loads Page-editor media/admin JS when the screen matches; no value. |
|
|
339
|
+
| `upload_mimes` | `dance_moves_timing_upload_mimes($mimes)` | Adds the two text MIME extensions. |
|
|
340
|
+
| `wp_check_filetype_and_ext` (10; 4 arguments) | `dance_moves_timing_filetype($data, $file, $filename, $mimes)` | See upload validation above. |
|
|
341
|
+
| `admin_notices` | `dance_moves_admin_notice()` | Reads/deletes the current user's queued transient and prints escaped error HTML, or returns without output. |
|
|
342
|
+
| `save_post_page` | `dance_moves_save_page_meta($post_id)` | Nonce/capability/autosave checks, per-field preservation/clear/update, popup checkbox and ambient-effect persistence; no value. Blank/invalid/missing effect clears its metadata. |
|
|
343
|
+
| `query_vars` | `dance_moves_epk_download_query_vars($query_vars)` | Adds the two signed-download query vars; unique array returned. |
|
|
344
|
+
| `the_content` (30) | `dance_moves_epk_download_filter_content($content)` | Rewrites eligible MP3 download anchors on main Page content; see [downloads](downloads.md). |
|
|
345
|
+
| `template_redirect` (0) | `dance_moves_epk_download_serve()` | Validates/serves signed MP3 GET/HEAD requests; terminates handled requests. |
|
|
346
|
+
| `the_content` (20) | `dance_moves_clay_stars_filter_content($content)` | Conditionally returns transformed Clay markup. |
|
|
347
|
+
|
|
348
|
+
The eight `dance_moves_epk_download_*` functions have complete signatures and
|
|
349
|
+
contracts in the [download API](downloads.md#php-functions). Together with that
|
|
350
|
+
reference and `dance_moves_sanitize_effect()`, the tables cover all **38** global
|
|
351
|
+
PHP functions in 2.8.0.
|
|
352
|
+
|
|
353
|
+
Additional callbacks/helpers:
|
|
354
|
+
|
|
355
|
+
| Function | Contract |
|
|
356
|
+
| --- | --- |
|
|
357
|
+
| `dance_moves_file_field($post_id, $label, $field_name, $meta_key, $allowed_extensions)` | Prints escaped file-picker markup, hidden attachment ID, status text, view/choose/clear controls; no return value. |
|
|
358
|
+
| `dance_moves_render_meta_box($post)` | Prints the nonce, BPM/file inputs and opt-in checkbox plus Ambient effect selector for `$post->ID`; no return value. |
|
|
359
|
+
| `dance_moves_queue_admin_error($message)` | Stores sanitised text at `dance_moves_admin_error_<user-id>` for 60 seconds; subsequent errors overwrite the same transient. |
|
|
360
|
+
| `dance_moves_clay_stars_is_target()` | Boolean `is_page(252)`. |
|
|
361
|
+
| `dance_moves_clay_stars_filter_content($content)` | Returns input unchanged in admin, off-target, outside the main loop/query, while the legacy constant exists, or without `ks-clay-stars-v2`. Otherwise conditionally inserts warm-bloom/lens/specular and cloud spans, removes the old `ks-clay-stars-v2-script`, and returns the string (empty on a nonstring replacement result). It transforms output, not stored Page content. |
|
|
362
|
+
|
|
363
|
+
`ks_epk_motion_capture_permission()` and `ks_epk_motion_store_capture()` are fully
|
|
364
|
+
specified in the capture section; all remaining global functions appear in the
|
|
365
|
+
configuration, upload, validation or hook tables, and the download reference. No PHP classes are defined.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Clay/Stars transform validation on a clean checkout
|
|
2
|
+
|
|
3
|
+
## Offline Unit checks
|
|
4
|
+
|
|
5
|
+
From any normal DanceMoves clone, run:
|
|
6
|
+
|
|
7
|
+
```powershell
|
|
8
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\validate.ps1 -Mode Unit
|
|
9
|
+
if ($LASTEXITCODE -ne 0) { throw "Unit validation failed; do not release" }
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`tests/validate-clay-transform.php` and `tests/validate-clay-legacy-collision.php`
|
|
13
|
+
now read [checked-in fixtures](../tests/fixtures/clay-transform/README.md), rather
|
|
14
|
+
than climbing three directories above the repository to infer a private
|
|
15
|
+
`Made from the clay and the stars` release folder. Both scripts load the actual
|
|
16
|
+
`kieran-epk-device-orientation.php` entrypoint and use mock WordPress context
|
|
17
|
+
functions. No production code or site data is changed.
|
|
18
|
+
|
|
19
|
+
The transform contract compares against a separately authored expected HTML file,
|
|
20
|
+
checks exact content preservation and idempotence, and exercises page, admin,
|
|
21
|
+
loop and query guards. The collision contract runs in its own PHP process with
|
|
22
|
+
the legacy plugin marker defined and checks that it blocks both insertions and
|
|
23
|
+
legacy-script removal. Missing or changed fixture files fail explicitly.
|
|
24
|
+
|
|
25
|
+
Both scripts are already called by the existing Unit coordinator.
|
|
26
|
+
`tests/clay-transform-fixtures.test.cjs` is automatically discovered with the
|
|
27
|
+
other `.test.cjs` tests. It relocates the minimal test inputs into a temporary
|
|
28
|
+
checkout, runs from an unrelated current directory, tests CRLF and disabled PHP
|
|
29
|
+
assertions, and deliberately breaks fixtures and production behavior to check
|
|
30
|
+
that failures are still detected. Temporary mutations never touch the checkout.
|
|
31
|
+
|
|
32
|
+
Focused commands:
|
|
33
|
+
|
|
34
|
+
```powershell
|
|
35
|
+
php .\tests\validate-clay-transform.php
|
|
36
|
+
if ($LASTEXITCODE -ne 0) { throw "Clay content transform failed" }
|
|
37
|
+
php .\tests\validate-clay-legacy-collision.php
|
|
38
|
+
if ($LASTEXITCODE -ne 0) { throw "Clay legacy coexistence failed" }
|
|
39
|
+
node .\tests\clay-transform-fixtures.test.cjs
|
|
40
|
+
if ($LASTEXITCODE -ne 0) { throw "PHP fixture regression checks failed" }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Separate approved release-payload comparison
|
|
44
|
+
|
|
45
|
+
The old comparison against an approved full-page payload is retained as an
|
|
46
|
+
explicit additional mode, not silently skipped or claimed by synthetic tests:
|
|
47
|
+
|
|
48
|
+
```powershell
|
|
49
|
+
php .\tests\validate-clay-transform.php --base "C:\release-evidence\clay-base.html" --candidate "C:\release-evidence\clay-approved.html"
|
|
50
|
+
if ($LASTEXITCODE -ne 0) { throw "Supplied approved-payload comparison failed" }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Replace the two paths with your actual reviewed local files. Both options are
|
|
54
|
+
required. A missing file, unreadable file, unknown option, invalid UTF-8, or a
|
|
55
|
+
network URL fails. The checked-in synthetic unit fixtures are rejected in this
|
|
56
|
+
mode. The script does not establish who approved a supplied file; provenance and
|
|
57
|
+
approval remain the release owner's responsibility.
|
|
58
|
+
|
|
59
|
+
This mode first runs the offline contracts, then transforms the supplied base and
|
|
60
|
+
compares its bytes against the supplied candidate after removing only the former
|
|
61
|
+
`ks-clay-stars-warm-light-style` block (and its immediate line ending) and the
|
|
62
|
+
superseded `ks-clay-stars-v2-script` block. It also checks idempotence. Unlike the
|
|
63
|
+
checked-in fixture loader, this comparison does not normalize release-file line
|
|
64
|
+
endings; use a matching source/candidate pair. No expected output is generated or
|
|
65
|
+
rewritten. Exit 0 means all requested checks passed, 1 means a contract mismatch,
|
|
66
|
+
and 2 means invalid input or an execution/setup error.
|
|
67
|
+
|
|
68
|
+
## What a pass does not establish
|
|
69
|
+
|
|
70
|
+
Offline transform checks are not a browser render, real WordPress hook execution,
|
|
71
|
+
media playback, physical-device performance test or publication receipt. Keep the
|
|
72
|
+
existing pre-live harness and signed-out post-deployment checks. Package mode's
|
|
73
|
+
release-evidence requirements are separate and are not changed by this fix.
|
|
74
|
+
|
|
75
|
+
## California scaffold parameter groups
|
|
76
|
+
|
|
77
|
+
The later California scaffold check also requires `master`, `timing` and `effect`
|
|
78
|
+
parameter groups. Its manifest previously contained only the first two. It now
|
|
79
|
+
includes a read-only **Orientation target cadence** reference in the `effect`
|
|
80
|
+
group, matching the production `ksEpkOrientationConfig.transitionTargetTicks`
|
|
81
|
+
value (two ticks). This does not introduce an adjustable motion parameter or
|
|
82
|
+
change the runtime. A focused Node contract checks the reference against the PHP
|
|
83
|
+
configuration. Production asset hashes and the full-page acceptance rules remain
|
|
84
|
+
unchanged.
|