@unrulysystems/native-motion-core 0.1.0-alpha.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.
Files changed (326) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +48 -0
  4. package/dist/clock.cjs +71 -0
  5. package/dist/clock.d.cts +23 -0
  6. package/dist/clock.d.ts +23 -0
  7. package/dist/clock.js +66 -0
  8. package/dist/collect-reads.cjs +68 -0
  9. package/dist/collect-reads.d.cts +23 -0
  10. package/dist/collect-reads.d.ts +23 -0
  11. package/dist/collect-reads.js +62 -0
  12. package/dist/component/boundedArray.cjs +74 -0
  13. package/dist/component/boundedArray.d.cts +25 -0
  14. package/dist/component/boundedArray.d.ts +25 -0
  15. package/dist/component/boundedArray.js +68 -0
  16. package/dist/component/index.cjs +57 -0
  17. package/dist/component/index.d.cts +12 -0
  18. package/dist/component/index.d.ts +12 -0
  19. package/dist/component/index.js +22 -0
  20. package/dist/component/orchestration.cjs +129 -0
  21. package/dist/component/orchestration.d.cts +66 -0
  22. package/dist/component/orchestration.d.ts +66 -0
  23. package/dist/component/orchestration.js +124 -0
  24. package/dist/component/resolve.cjs +104 -0
  25. package/dist/component/resolve.d.cts +11 -0
  26. package/dist/component/resolve.d.ts +11 -0
  27. package/dist/component/resolve.js +97 -0
  28. package/dist/component/transition.cjs +352 -0
  29. package/dist/component/transition.d.cts +33 -0
  30. package/dist/component/transition.d.ts +33 -0
  31. package/dist/component/transition.js +339 -0
  32. package/dist/component/types.cjs +114 -0
  33. package/dist/component/types.d.cts +60 -0
  34. package/dist/component/types.d.ts +60 -0
  35. package/dist/component/types.js +111 -0
  36. package/dist/component/validate.cjs +1015 -0
  37. package/dist/component/validate.d.cts +37 -0
  38. package/dist/component/validate.d.ts +37 -0
  39. package/dist/component/validate.js +1002 -0
  40. package/dist/component/variants.cjs +333 -0
  41. package/dist/component/variants.d.cts +106 -0
  42. package/dist/component/variants.d.ts +106 -0
  43. package/dist/component/variants.js +321 -0
  44. package/dist/config/constants.cjs +41 -0
  45. package/dist/config/constants.d.cts +29 -0
  46. package/dist/config/constants.d.ts +29 -0
  47. package/dist/config/constants.js +38 -0
  48. package/dist/delay.cjs +72 -0
  49. package/dist/delay.d.cts +26 -0
  50. package/dist/delay.d.ts +26 -0
  51. package/dist/delay.js +70 -0
  52. package/dist/derived.cjs +143 -0
  53. package/dist/derived.d.cts +41 -0
  54. package/dist/derived.d.ts +41 -0
  55. package/dist/derived.js +139 -0
  56. package/dist/driver/index.cjs +22 -0
  57. package/dist/driver/index.d.cts +7 -0
  58. package/dist/driver/index.d.ts +7 -0
  59. package/dist/driver/index.js +14 -0
  60. package/dist/driver/keyframeTiming.cjs +130 -0
  61. package/dist/driver/keyframeTiming.d.cts +18 -0
  62. package/dist/driver/keyframeTiming.d.ts +18 -0
  63. package/dist/driver/keyframeTiming.js +124 -0
  64. package/dist/driver/keyframeTimingConfig.cjs +24 -0
  65. package/dist/driver/keyframeTimingConfig.d.cts +5 -0
  66. package/dist/driver/keyframeTimingConfig.d.ts +5 -0
  67. package/dist/driver/keyframeTimingConfig.js +22 -0
  68. package/dist/driver/prepare.cjs +459 -0
  69. package/dist/driver/prepare.d.cts +4 -0
  70. package/dist/driver/prepare.d.ts +4 -0
  71. package/dist/driver/prepare.js +454 -0
  72. package/dist/driver/reference.cjs +762 -0
  73. package/dist/driver/reference.d.cts +53 -0
  74. package/dist/driver/reference.d.ts +53 -0
  75. package/dist/driver/reference.js +757 -0
  76. package/dist/driver/step.cjs +55 -0
  77. package/dist/driver/step.d.cts +9 -0
  78. package/dist/driver/step.d.ts +9 -0
  79. package/dist/driver/step.js +52 -0
  80. package/dist/driver/tiers.cjs +40 -0
  81. package/dist/driver/tiers.d.cts +2 -0
  82. package/dist/driver/tiers.d.ts +2 -0
  83. package/dist/driver/tiers.js +37 -0
  84. package/dist/driver/types.cjs +9 -0
  85. package/dist/driver/types.d.cts +68 -0
  86. package/dist/driver/types.d.ts +68 -0
  87. package/dist/driver/types.js +8 -0
  88. package/dist/external-animation-ledger.cjs +1250 -0
  89. package/dist/external-animation-ledger.d.cts +416 -0
  90. package/dist/external-animation-ledger.d.ts +416 -0
  91. package/dist/external-animation-ledger.js +1243 -0
  92. package/dist/gesture/directionLock.cjs +25 -0
  93. package/dist/gesture/directionLock.d.cts +8 -0
  94. package/dist/gesture/directionLock.d.ts +8 -0
  95. package/dist/gesture/directionLock.js +21 -0
  96. package/dist/gesture/dragConfig.cjs +634 -0
  97. package/dist/gesture/dragConfig.d.cts +298 -0
  98. package/dist/gesture/dragConfig.d.ts +298 -0
  99. package/dist/gesture/dragConfig.js +624 -0
  100. package/dist/gesture/elastic.cjs +44 -0
  101. package/dist/gesture/elastic.d.cts +4 -0
  102. package/dist/gesture/elastic.d.ts +4 -0
  103. package/dist/gesture/elastic.js +39 -0
  104. package/dist/gesture/handoffSession.cjs +161 -0
  105. package/dist/gesture/handoffSession.d.cts +35 -0
  106. package/dist/gesture/handoffSession.d.ts +35 -0
  107. package/dist/gesture/handoffSession.js +158 -0
  108. package/dist/gesture/index.cjs +37 -0
  109. package/dist/gesture/index.d.cts +12 -0
  110. package/dist/gesture/index.d.ts +12 -0
  111. package/dist/gesture/index.js +11 -0
  112. package/dist/gesture/projection.cjs +95 -0
  113. package/dist/gesture/projection.d.cts +7 -0
  114. package/dist/gesture/projection.d.ts +7 -0
  115. package/dist/gesture/projection.js +87 -0
  116. package/dist/gesture/session.cjs +162 -0
  117. package/dist/gesture/session.d.cts +29 -0
  118. package/dist/gesture/session.d.ts +29 -0
  119. package/dist/gesture/session.js +158 -0
  120. package/dist/gesture/types.cjs +5 -0
  121. package/dist/gesture/types.d.cts +13 -0
  122. package/dist/gesture/types.d.ts +13 -0
  123. package/dist/gesture/types.js +4 -0
  124. package/dist/gesture/viewportConstraints.cjs +38 -0
  125. package/dist/gesture/viewportConstraints.d.cts +6 -0
  126. package/dist/gesture/viewportConstraints.d.ts +6 -0
  127. package/dist/gesture/viewportConstraints.js +34 -0
  128. package/dist/graph.cjs +226 -0
  129. package/dist/graph.d.cts +2 -0
  130. package/dist/graph.d.ts +2 -0
  131. package/dist/graph.js +223 -0
  132. package/dist/index.cjs +140 -0
  133. package/dist/index.d.cts +33 -0
  134. package/dist/index.d.ts +33 -0
  135. package/dist/index.js +70 -0
  136. package/dist/inertia.cjs +214 -0
  137. package/dist/inertia.d.cts +53 -0
  138. package/dist/inertia.d.ts +53 -0
  139. package/dist/inertia.js +212 -0
  140. package/dist/instant.cjs +66 -0
  141. package/dist/instant.d.cts +16 -0
  142. package/dist/instant.d.ts +16 -0
  143. package/dist/instant.js +63 -0
  144. package/dist/internal-driver.cjs +81 -0
  145. package/dist/internal-driver.d.cts +19 -0
  146. package/dist/internal-driver.d.ts +19 -0
  147. package/dist/internal-driver.js +35 -0
  148. package/dist/keyframes.cjs +191 -0
  149. package/dist/keyframes.d.cts +13 -0
  150. package/dist/keyframes.d.ts +13 -0
  151. package/dist/keyframes.js +188 -0
  152. package/dist/layout/commitDetector.cjs +67 -0
  153. package/dist/layout/commitDetector.d.cts +21 -0
  154. package/dist/layout/commitDetector.d.ts +21 -0
  155. package/dist/layout/commitDetector.js +64 -0
  156. package/dist/layout/compose.cjs +67 -0
  157. package/dist/layout/compose.d.cts +30 -0
  158. package/dist/layout/compose.d.ts +30 -0
  159. package/dist/layout/compose.js +65 -0
  160. package/dist/layout/constants.cjs +13 -0
  161. package/dist/layout/constants.d.cts +6 -0
  162. package/dist/layout/constants.d.ts +6 -0
  163. package/dist/layout/constants.js +10 -0
  164. package/dist/layout/identity.cjs +700 -0
  165. package/dist/layout/identity.d.cts +67 -0
  166. package/dist/layout/identity.d.ts +67 -0
  167. package/dist/layout/identity.js +698 -0
  168. package/dist/layout/index.cjs +36 -0
  169. package/dist/layout/index.d.cts +18 -0
  170. package/dist/layout/index.d.ts +18 -0
  171. package/dist/layout/index.js +13 -0
  172. package/dist/layout/measure.cjs +81 -0
  173. package/dist/layout/measure.d.cts +43 -0
  174. package/dist/layout/measure.d.ts +43 -0
  175. package/dist/layout/measure.js +78 -0
  176. package/dist/layout/projection.cjs +99 -0
  177. package/dist/layout/projection.d.cts +23 -0
  178. package/dist/layout/projection.d.ts +23 -0
  179. package/dist/layout/projection.js +97 -0
  180. package/dist/layout/scroll.cjs +27 -0
  181. package/dist/layout/scroll.d.cts +13 -0
  182. package/dist/layout/scroll.d.ts +13 -0
  183. package/dist/layout/scroll.js +24 -0
  184. package/dist/layout/session.cjs +207 -0
  185. package/dist/layout/session.d.cts +73 -0
  186. package/dist/layout/session.d.ts +73 -0
  187. package/dist/layout/session.js +205 -0
  188. package/dist/layout/tree.cjs +826 -0
  189. package/dist/layout/tree.d.cts +70 -0
  190. package/dist/layout/tree.d.ts +70 -0
  191. package/dist/layout/tree.js +823 -0
  192. package/dist/layout/types.cjs +36 -0
  193. package/dist/layout/types.d.cts +31 -0
  194. package/dist/layout/types.d.ts +31 -0
  195. package/dist/layout/types.js +35 -0
  196. package/dist/motion-arc.cjs +184 -0
  197. package/dist/motion-arc.d.cts +78 -0
  198. package/dist/motion-arc.d.ts +78 -0
  199. package/dist/motion-arc.js +183 -0
  200. package/dist/motion-mix.cjs +205 -0
  201. package/dist/motion-mix.d.cts +3 -0
  202. package/dist/motion-mix.d.ts +3 -0
  203. package/dist/motion-mix.js +202 -0
  204. package/dist/motion-value-driver-port.cjs +636 -0
  205. package/dist/motion-value-driver-port.d.cts +406 -0
  206. package/dist/motion-value-driver-port.d.ts +406 -0
  207. package/dist/motion-value-driver-port.js +627 -0
  208. package/dist/motion-value.cjs +189 -0
  209. package/dist/motion-value.d.cts +51 -0
  210. package/dist/motion-value.d.ts +51 -0
  211. package/dist/motion-value.js +185 -0
  212. package/dist/presence/controller.cjs +657 -0
  213. package/dist/presence/controller.d.cts +6 -0
  214. package/dist/presence/controller.d.ts +6 -0
  215. package/dist/presence/controller.js +652 -0
  216. package/dist/presence/index.cjs +19 -0
  217. package/dist/presence/index.d.cts +4 -0
  218. package/dist/presence/index.d.ts +4 -0
  219. package/dist/presence/index.js +12 -0
  220. package/dist/presence/machine.cjs +50 -0
  221. package/dist/presence/machine.d.cts +10 -0
  222. package/dist/presence/machine.d.ts +10 -0
  223. package/dist/presence/machine.js +46 -0
  224. package/dist/presence/types.cjs +6 -0
  225. package/dist/presence/types.d.cts +32 -0
  226. package/dist/presence/types.d.ts +32 -0
  227. package/dist/presence/types.js +5 -0
  228. package/dist/repeat.cjs +311 -0
  229. package/dist/repeat.d.cts +174 -0
  230. package/dist/repeat.d.ts +174 -0
  231. package/dist/repeat.js +300 -0
  232. package/dist/spring.cjs +128 -0
  233. package/dist/spring.d.cts +18 -0
  234. package/dist/spring.d.ts +18 -0
  235. package/dist/spring.js +125 -0
  236. package/dist/subscriptions.cjs +74 -0
  237. package/dist/subscriptions.d.cts +19 -0
  238. package/dist/subscriptions.d.ts +19 -0
  239. package/dist/subscriptions.js +69 -0
  240. package/dist/subset/index.cjs +23 -0
  241. package/dist/subset/index.d.cts +6 -0
  242. package/dist/subset/index.d.ts +6 -0
  243. package/dist/subset/index.js +13 -0
  244. package/dist/subset/normalize.cjs +90 -0
  245. package/dist/subset/normalize.d.cts +10 -0
  246. package/dist/subset/normalize.d.ts +10 -0
  247. package/dist/subset/normalize.js +85 -0
  248. package/dist/subset/registry.cjs +259 -0
  249. package/dist/subset/registry.d.cts +25 -0
  250. package/dist/subset/registry.d.ts +25 -0
  251. package/dist/subset/registry.js +256 -0
  252. package/dist/subset/resolve.cjs +98 -0
  253. package/dist/subset/resolve.d.cts +24 -0
  254. package/dist/subset/resolve.d.ts +24 -0
  255. package/dist/subset/resolve.js +90 -0
  256. package/dist/timing.cjs +206 -0
  257. package/dist/timing.d.cts +17 -0
  258. package/dist/timing.d.ts +17 -0
  259. package/dist/timing.js +201 -0
  260. package/dist/transformTemplate.cjs +219 -0
  261. package/dist/transformTemplate.d.cts +29 -0
  262. package/dist/transformTemplate.d.ts +29 -0
  263. package/dist/transformTemplate.js +215 -0
  264. package/dist/transition.cjs +231 -0
  265. package/dist/transition.d.cts +89 -0
  266. package/dist/transition.d.ts +89 -0
  267. package/dist/transition.js +223 -0
  268. package/dist/types.cjs +4 -0
  269. package/dist/types.d.cts +175 -0
  270. package/dist/types.d.ts +175 -0
  271. package/dist/types.js +3 -0
  272. package/dist/value-types/color.cjs +220 -0
  273. package/dist/value-types/color.d.cts +19 -0
  274. package/dist/value-types/color.d.ts +19 -0
  275. package/dist/value-types/color.js +218 -0
  276. package/dist/value-types/complex.cjs +160 -0
  277. package/dist/value-types/complex.d.cts +19 -0
  278. package/dist/value-types/complex.d.ts +19 -0
  279. package/dist/value-types/complex.js +155 -0
  280. package/dist/value-types/constants.cjs +15 -0
  281. package/dist/value-types/constants.d.cts +6 -0
  282. package/dist/value-types/constants.d.ts +6 -0
  283. package/dist/value-types/constants.js +12 -0
  284. package/dist/value-types/discrete.cjs +62 -0
  285. package/dist/value-types/discrete.d.cts +4 -0
  286. package/dist/value-types/discrete.d.ts +4 -0
  287. package/dist/value-types/discrete.js +56 -0
  288. package/dist/value-types/index.cjs +59 -0
  289. package/dist/value-types/index.d.cts +14 -0
  290. package/dist/value-types/index.d.ts +14 -0
  291. package/dist/value-types/index.js +24 -0
  292. package/dist/value-types/measure-resolve.cjs +325 -0
  293. package/dist/value-types/measure-resolve.d.cts +91 -0
  294. package/dist/value-types/measure-resolve.d.ts +91 -0
  295. package/dist/value-types/measure-resolve.js +313 -0
  296. package/dist/value-types/mix.cjs +90 -0
  297. package/dist/value-types/mix.d.cts +27 -0
  298. package/dist/value-types/mix.d.ts +27 -0
  299. package/dist/value-types/mix.js +85 -0
  300. package/dist/value-types/named-colors.cjs +61 -0
  301. package/dist/value-types/named-colors.d.cts +2 -0
  302. package/dist/value-types/named-colors.d.ts +2 -0
  303. package/dist/value-types/named-colors.js +58 -0
  304. package/dist/value-types/numeric.cjs +86 -0
  305. package/dist/value-types/numeric.d.cts +16 -0
  306. package/dist/value-types/numeric.d.ts +16 -0
  307. package/dist/value-types/numeric.js +79 -0
  308. package/dist/worklet-layout/config/constants.js +39 -0
  309. package/dist/worklet-layout/layout/constants.js +11 -0
  310. package/dist/worklet-layout/layout/identity.js +699 -0
  311. package/dist/worklet-layout/layout/projection.js +98 -0
  312. package/dist/worklet-layout/layout/session.js +206 -0
  313. package/dist/worklet-layout/layout/tree.js +824 -0
  314. package/dist/worklet-layout/layout/types.js +36 -0
  315. package/dist/worklet-layout/spring.js +125 -0
  316. package/dist/worklet-layout/timing.js +201 -0
  317. package/dist/worklet-layout/transition.js +223 -0
  318. package/dist/worklet-layout.cjs +47 -0
  319. package/dist/worklet-layout.d.cts +15 -0
  320. package/dist/worklet-layout.d.ts +15 -0
  321. package/dist/worklet-layout.js +28 -0
  322. package/dist/wrap.cjs +7 -0
  323. package/dist/wrap.d.cts +1 -0
  324. package/dist/wrap.d.ts +1 -0
  325. package/dist/wrap.js +4 -0
  326. package/package.json +45 -0
@@ -0,0 +1,321 @@
1
+ // SPEC-COMPONENT §2 — REQ-API-032: the variants resolution core (R7). Pure, host-agnostic,
2
+ // deterministic over (definition, dictionary, live state) — the pinned `resolveVariantFromProps`
3
+ // chain including its runtime-only direct function form. Law (a): a local dictionary miss is the pinned
4
+ // NO-OP (the propagation-source shape), never an error. Law (b): animation-time arrays
5
+ // resolve to ORDERED per-label applications, each preserving its own embedded transition.
6
+ // Law (c): initial labels overlay synchronously into one first-paint state, transitions
7
+ // discarded. Law (f): the eager shape + entry validation — outer shapes typed as a unit,
8
+ // per-entry validation through the SAME target/transition boundaries the animate lane
9
+ // rides. The FUNCTION form (T24 B2, dynamic variants) is accepted at the boundary by
10
+ // identity and validated at RESOLUTION, where its result exists.
11
+ import { InvalidTransitionError, validateTargetRefusal, validateTransitionRefusal, } from "./validate.js";
12
+ import { keyframeTransitionRefusal } from "../driver/keyframeTiming.js";
13
+ import { captureTransition } from "../driver/prepare.js";
14
+ import { captureBoundedArray, capturedArrayDescription } from "./boundedArray.js";
15
+ import { normalizeTransitionEaseAlias, resolveTransitionForKey } from "./transition.js";
16
+ // Thrown for malformed variants SHAPES (REQ-API-014's structured pattern): the key names the
17
+ // offending unit ('(variants)' for the outer shape, the label for an entry).
18
+ export class InvalidVariantError extends Error {
19
+ key;
20
+ value;
21
+ constructor(key, value, reason, cause) {
22
+ super(`invalid variants ${key === '(variants)' ? 'prop' : `entry '${key}'`} — ${reason}`, cause !== undefined ? { cause } : undefined);
23
+ this.name = 'InvalidVariantError';
24
+ this.key = key;
25
+ this.value = value;
26
+ }
27
+ }
28
+ function isPlainObject(value) {
29
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
30
+ return false;
31
+ const proto = Object.getPrototypeOf(value);
32
+ return proto === Object.prototype || proto === null;
33
+ }
34
+ // Hostile-input architecture (M3 r3 majors 1b53e9337aec/13af48a64530): severity gates never
35
+ // CATCH around code that can run foreign traps/getters — any durable "ownership" mark on an
36
+ // error object is forgeable or replayable, and trusting exported classes launders authentic
37
+ // sentinels. Instead every boundary primitive is RETURN-shaped with PHASE-SEPARATED reads:
38
+ // foreign code (prototype probes, getters, enumeration traps) runs UNGUARDED first — its
39
+ // faults propagate untouched by construction — and validation then operates on plain
40
+ // snapshots, so a returned refusal is boundary-made by construction and nothing else is
41
+ // ever classified.
42
+ /**
43
+ * Law (f), outer shape, RETURN-shaped: the typed refusal, or null when `variants` is a
44
+ * plain object. The probe itself may throw on hostile values (a getPrototypeOf trap, a
45
+ * revoked proxy) — those faults propagate untouched; only the RETURNED refusal is input
46
+ * refusal.
47
+ */
48
+ export function variantsShapeRefusal(value) {
49
+ if (isPlainObject(value))
50
+ return null;
51
+ return new InvalidVariantError('(variants)', value, 'the dictionary must be a plain object of label → target entries (REQ-API-032 law f; ' +
52
+ 'a malformed shape fails loud, never coerces to the empty dictionary)');
53
+ }
54
+ /**
55
+ * Law (f), outer shape: `variants` must be a plain object — null, arrays, and
56
+ * prototype-carrying objects refuse AS A UNIT (typed), never coerce to an empty dictionary.
57
+ */
58
+ export function assertVariantsShape(value) {
59
+ const refusal = variantsShapeRefusal(value);
60
+ if (refusal !== null)
61
+ throw refusal;
62
+ }
63
+ /**
64
+ * Law (f), per entry: an entry must be a plain object whose members validate through the
65
+ * SAME boundaries the animate lane rides — core validateTarget for the target members and
66
+ * the REQ-API-031 transition law for the embedded transition — or a RESOLVER (T24 B2),
67
+ * accepted uninvoked and validated at resolution.
68
+ */
69
+ export function validateVariantEntry(label, entry, host, opts) {
70
+ const { refusal } = validateVariantEntrySnapshot(label, entry, host, opts);
71
+ if (refusal !== null)
72
+ throw refusal;
73
+ }
74
+ /**
75
+ * Law (f), per entry, RETURN-shaped + SNAPSHOT-accepting (M3 r3 majors 13af48a64530 +
76
+ * 5cb2381e272c; hardened r4 majors 4db96de50131 + 93bab4ecf757): the READ phase runs first
77
+ * and UNGUARDED — the entry's getters and every level of a transition's enumeration traps
78
+ * fire here, so their faults (including authentic same-class sentinels) propagate
79
+ * untouched. Validation then runs on DEEP-plain snapshots, and the SNAPSHOT is what the
80
+ * caller accepts: a stateful proxy cannot show the validators one value and the engine
81
+ * another (one read, one truth). Residual bound, stated honestly: hostile LEAF objects
82
+ * (non-array, non-plain) stay by reference and are refused by the validators' trap-free
83
+ * type checks — they are never enumerated inside the trusted region.
84
+ */
85
+ export function validateVariantEntrySnapshot(label, entry, host, opts) {
86
+ if (typeof entry === 'function') {
87
+ // T24 B2: the dynamic form is ACCEPTED at the boundary, by identity and UNINVOKED — its
88
+ // keys do not exist until resolution, so entry validation applies to its RESULT at the
89
+ // resolution seam (resolveVariantDefinition), never here.
90
+ return { refusal: null, entry: entry };
91
+ }
92
+ if (!isPlainObject(entry)) {
93
+ return {
94
+ refusal: new InvalidVariantError(label, entry, `variants.${label} must be a plain target entry (REQ-API-032 law f)`),
95
+ entry: null,
96
+ };
97
+ }
98
+ // READ phase — every getter and enumeration trap fires HERE, outside any try.
99
+ const { transition: rawTransition, ...rawTarget } = entry;
100
+ // Materialize each ARRAY member ONCE, before validation (R8, review major 18): a shallow snapshot let
101
+ // the validators read a member's elements and the accepted clone read them AGAIN, so a hostile
102
+ // accessor-backed array (100 then null) could pass validation yet land the unvalidated null in the
103
+ // snapshot. The bounded capture reads each own index exactly once; the frozen copy is the SINGLE truth both the
104
+ // validators and the accepted entry see. Non-array members pass through unchanged. The accumulator is
105
+ // NULL-PROTOTYPE (review major 24): a SCALAR own '__proto__' member assigned onto an ordinary object
106
+ // is a silent no-op setter (the key vanishes yet the snapshot stays plain and passes the shape gate) —
107
+ // a null-prototype object makes it an own data property so the capability gate refuses it, loudly.
108
+ const targetSnapshot = Object.create(null);
109
+ for (const [key, member] of Object.entries(rawTarget)) {
110
+ if (!Array.isArray(member)) {
111
+ targetSnapshot[key] = member;
112
+ continue;
113
+ }
114
+ const captured = captureBoundedArray(member);
115
+ if (captured.kind !== 'captured') {
116
+ return {
117
+ refusal: new InvalidVariantError(label, capturedArrayDescription(captured), `variants.${label} keyframe arrays must have a safe length between 0 and 100000 (REQ-API-033)`),
118
+ entry: null,
119
+ };
120
+ }
121
+ targetSnapshot[key] = captured.values;
122
+ }
123
+ let transitionSnapshot;
124
+ if (rawTransition === undefined) {
125
+ transitionSnapshot = undefined;
126
+ }
127
+ else if (isPlainObject(rawTransition)) {
128
+ // Reuse the value-preserving transition capture used by every raw/supplying boundary. It keeps
129
+ // symbols, unknown strings, and non-enumerable known fields for validateTransitionRefusal while
130
+ // deeply snapshotting only legal timing arrays.
131
+ transitionSnapshot = captureTransition(rawTransition);
132
+ }
133
+ else {
134
+ // A non-plain transition cannot be faithfully snapshotted — spreading a Date/Map/array
135
+ // yields the EMPTY object, silently laundering the malformed shape into a valid empty
136
+ // transition (M3 r4 major 4db96de50131). The refusal is constructed HERE, return-shaped,
137
+ // mirroring validateTransition's own shape law verbatim (message + category parity);
138
+ // the value is never probed again.
139
+ const shapeCause = new InvalidTransitionError(opts?.componentId, '(transition)', rawTransition, 'a transition must be a plain object of transition options (G-INV-8 — a malformed config ' +
140
+ 'fails loud, never coerces to the default transition)');
141
+ return {
142
+ refusal: new InvalidVariantError(label, entry, `variants.${label}: ${shapeCause.message}`, shapeCause),
143
+ entry: null,
144
+ };
145
+ }
146
+ // RETURN-shaped validators, NO catch (M3 r6 major 30a9c21bf960): a returned refusal is
147
+ // validator-made by construction; anything THROWN — including an authentic same-class
148
+ // sentinel from a polluted dependency (Set.prototype.has) — propagates untouched because
149
+ // nothing here catches it.
150
+ const transitionRefusal = validateTransitionRefusal(transitionSnapshot, opts);
151
+ if (transitionRefusal === null && transitionSnapshot !== undefined) {
152
+ // Family-2: web pin consumes `ease`; rewrite catalog `easings` on the accepted snapshot so
153
+ // every supplier (variant embed, element, MotionConfig) hands the same normalized shape.
154
+ transitionSnapshot = normalizeTransitionEaseAlias(transitionSnapshot);
155
+ }
156
+ if (transitionRefusal !== null) {
157
+ return {
158
+ refusal: new InvalidVariantError(label, entry, `variants.${label}: ${transitionRefusal.message}`, transitionRefusal),
159
+ entry: null,
160
+ };
161
+ }
162
+ const targetRefusal = validateTargetRefusal(targetSnapshot, host, opts);
163
+ if (targetRefusal !== null) {
164
+ return {
165
+ refusal: new InvalidVariantError(label, entry, `variants.${label}: ${targetRefusal.message}`, targetRefusal),
166
+ entry: null,
167
+ };
168
+ }
169
+ for (const [key, value] of Object.entries(targetSnapshot)) {
170
+ const effectiveTransition = transitionSnapshot === undefined
171
+ ? undefined
172
+ : resolveTransitionForKey(transitionSnapshot, key);
173
+ const timingRefusal = keyframeTransitionRefusal(opts?.componentId, key, value, effectiveTransition);
174
+ if (timingRefusal !== null) {
175
+ return {
176
+ refusal: new InvalidVariantError(label, entry, `variants.${label}: ${timingRefusal.message}`, timingRefusal),
177
+ entry: null,
178
+ };
179
+ }
180
+ }
181
+ // The accepted ENTRY is null-prototype too (M3 r6 major 5d48ad691b96): absent must MEAN
182
+ // absent — a consumer reading `.transition` off an Object.prototype-backed entry would
183
+ // see a polluted inherited value when none is own.
184
+ const acceptedEntry = Object.create(null);
185
+ for (const [key, member] of Object.entries(targetSnapshot)) {
186
+ // `targetSnapshot` array members are ALREADY the read-once frozen copies the validators saw, so the
187
+ // accepted entry references that single truth directly — no second read of the caller's array
188
+ // (reviews major 91f7a2c43bd0 immutability + major 18 one-read). Keyframe elements are scalars.
189
+ acceptedEntry[key] = member;
190
+ }
191
+ if (transitionSnapshot !== undefined) {
192
+ acceptedEntry['transition'] = transitionSnapshot;
193
+ }
194
+ return { refusal: null, entry: acceptedEntry };
195
+ }
196
+ /** Split one entry into its application (the bare target + its own transition). */
197
+ function applicationOf(entry) {
198
+ const { transition, ...target } = entry;
199
+ return { target: target, transition };
200
+ }
201
+ /**
202
+ * Laws (a)/(b): resolve a label or label array to the ORDERED application list. A local
203
+ * miss contributes nothing (the pinned no-op); each hit preserves its own transition.
204
+ */
205
+ export function resolveVariantDefinition(definition, dictionary, context) {
206
+ const result = resolveVariantDefinitionResult(definition, dictionary, context);
207
+ if (result.refusal !== null)
208
+ throw result.refusal;
209
+ return result.applications;
210
+ }
211
+ /**
212
+ * Internal severity seam: boundary-made validation failures are returned, while value-state reads
213
+ * and user resolver invocations remain outside every catch and preserve their exact thrown value.
214
+ */
215
+ export function resolveVariantDefinitionResult(definition, dictionary, context) {
216
+ if (typeof definition === 'function') {
217
+ const invocation = invokeResolver('(definition)', definition, context);
218
+ if (invocation.refusal !== null)
219
+ return { applications: [], refusal: invocation.refusal };
220
+ const produced = invocation.value;
221
+ if (typeof produced !== 'string') {
222
+ const resolution = resolveProducedTarget('(definition)', produced, context);
223
+ return resolution.refusal === null
224
+ ? { applications: [resolution.application], refusal: null }
225
+ : { applications: [], refusal: resolution.refusal };
226
+ }
227
+ return resolveSingleLabel(produced, dictionary, context);
228
+ }
229
+ const labels = typeof definition === 'string' ? [definition] : definition;
230
+ const applications = [];
231
+ for (const label of labels) {
232
+ const resolution = resolveSingleLabel(label, dictionary, context);
233
+ if (resolution.refusal !== null)
234
+ return { applications: [], refusal: resolution.refusal };
235
+ applications.push(...resolution.applications);
236
+ }
237
+ return { applications, refusal: null };
238
+ }
239
+ function resolutionContextRefusal(label, context) {
240
+ return context === undefined
241
+ ? new InvalidVariantError(label, undefined, `variants.${label} is a RESOLVER but the resolution site supplied no ` +
242
+ 'resolution context — the site is not wired for dynamic variants (T24 B2)')
243
+ : null;
244
+ }
245
+ // Each call performs its own pin-shaped `getValueState` read. The invocation is deliberately
246
+ // unguarded: user faults preserve identity and host severity routes only our typed refusals.
247
+ function invokeResolver(label, entry, context) {
248
+ const refusal = resolutionContextRefusal(label, context);
249
+ if (refusal !== null)
250
+ return { refusal };
251
+ const wired = context;
252
+ const { current, velocity } = wired.readValueState();
253
+ return { value: entry(wired.custom, current, velocity), refusal: null };
254
+ }
255
+ function resolveProducedTarget(label, produced, context) {
256
+ const contextRefusal = resolutionContextRefusal(label, context);
257
+ if (contextRefusal !== null)
258
+ return { refusal: contextRefusal };
259
+ const wired = context;
260
+ if (typeof produced === 'function') {
261
+ return {
262
+ refusal: new InvalidVariantError(label, produced, `variants.${label}: the resolver returned another resolver — a dictionary resolver ` +
263
+ 'must return a target object exactly once (the pin two-step bound)'),
264
+ };
265
+ }
266
+ const { refusal, entry: accepted } = validateVariantEntrySnapshot(label, produced, wired.host, wired.componentId === undefined ? undefined : { componentId: wired.componentId });
267
+ if (refusal !== null)
268
+ return { refusal };
269
+ return { application: applicationOf(accepted), refusal: null };
270
+ }
271
+ function resolveSingleLabel(label, dictionary, context) {
272
+ // OWN properties only (M1 review major 1): prototype-chain names are local misses.
273
+ if (dictionary === undefined || !Object.hasOwn(dictionary, label)) {
274
+ return { applications: [], refusal: null };
275
+ }
276
+ const entry = dictionary[label];
277
+ if (typeof entry !== 'function') {
278
+ return { applications: [applicationOf(entry)], refusal: null };
279
+ }
280
+ const invocation = invokeResolver(label, entry, context);
281
+ if (invocation.refusal !== null)
282
+ return { applications: [], refusal: invocation.refusal };
283
+ // This is the bounded second function arm. Its result is final and cannot name another label.
284
+ const resolution = resolveProducedTarget(label, invocation.value, context);
285
+ return resolution.refusal === null
286
+ ? { applications: [resolution.application], refusal: null }
287
+ : { applications: [], refusal: resolution.refusal };
288
+ }
289
+ export function flattenVariantApplications(applications) {
290
+ const target = {};
291
+ const transitions = {};
292
+ for (const application of applications) {
293
+ for (const key of Object.keys(application.target)) {
294
+ target[key] = application.target[key];
295
+ if (application.transition === undefined)
296
+ delete transitions[key];
297
+ else
298
+ transitions[key] = application.transition;
299
+ }
300
+ }
301
+ return { target: target, transitions };
302
+ }
303
+ /**
304
+ * Law (c): the synchronous initial overlay — all labels merge in order into ONE first-paint
305
+ * state, transitions DISCARDED (REQ-API-010's no-entrance law is untouched).
306
+ */
307
+ export function resolveInitialOverlay(definition, dictionary, context) {
308
+ const overlay = {};
309
+ for (const application of resolveVariantDefinition(definition, dictionary, context)) {
310
+ // T23 B3c: an initial application applies its transitionEnd INSTANTLY (the pin's
311
+ // nothing-animates arm) — the carrier's sub-values fold into the first-paint state,
312
+ // winning over the same application's target key; the carrier member itself never
313
+ // rides the overlay.
314
+ const { transitionEnd: carrier, ...plain } = application.target;
315
+ Object.assign(overlay, plain);
316
+ if (typeof carrier === 'object' && carrier !== null && !Array.isArray(carrier)) {
317
+ Object.assign(overlay, carrier);
318
+ }
319
+ }
320
+ return overlay;
321
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ // @frame-path — executes inside the UI-runtime frame step; allocation-gated (REQ-DRIVER-021).
3
+ // Pinned motion-graph constants. Adopted from `motion@12.42.2` (see
4
+ // `specs/OPEN-DECISIONS.md` §D resolutions log) and PROVEN equal to that pinned oracle by the M1b
5
+ // conformance suite — these literals are a starting seed, not hand-authored ground truth. Never
6
+ // widen an epsilon here to make a test pass (test-integrity); fix the code or ratify the constant.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.SETTLE_HORIZON_MS = exports.EPS_SETTLE_FRAME = exports.EPS_TRAJ = exports.EPS_VELOCITY = exports.GRANULAR_THRESHOLD = exports.REST_SPEED = exports.REST_DELTA = exports.DT_CLAMP_MS = exports.MAX_VELOCITY_DELTA_MS = void 0;
9
+ /**
10
+ * CORE-only velocity staleness window (ms). Governs `MotionValue.getVelocity` and the animation
11
+ * cold-start velocity seed. It does NOT govern the gesture path — that consumes platform release
12
+ * velocity (§D/§G). A value sample older than this reads velocity `0`.
13
+ */
14
+ exports.MAX_VELOCITY_DELTA_MS = 30;
15
+ /**
16
+ * Per-frame elapsed-time ceiling (ms). Guards the graph against a large jump after backgrounding
17
+ * (REQ-CLOCK-003). Flagged for human confirmation. ~2.4 frames at 60Hz.
18
+ */
19
+ exports.DT_CLAMP_MS = 40;
20
+ // Rest thresholds — adopted from Motion; the exact numerics and their conformance pin are owned by
21
+ // SPEC-SPRING. Present here only so CORE has one source; SPRING tightens them.
22
+ exports.REST_DELTA = 0.01;
23
+ exports.REST_SPEED = 2;
24
+ /** Granular rest-threshold discontinuity at `|target − origin| < 5` (Motion). */
25
+ exports.GRANULAR_THRESHOLD = 5;
26
+ // Named epsilons — config, not literals in assertions. Nominal seeds from SPEC-CORE §5; final
27
+ // values ratified with SPEC-SPRING and tightened against the pinned oracle in M1b.
28
+ /** Velocity equality tolerance (units/sec). */
29
+ exports.EPS_VELOCITY = 1;
30
+ /** Trajectory / dt-robustness tolerance (value units). */
31
+ exports.EPS_TRAJ = 0.5;
32
+ /** Settle is exact to the frame. */
33
+ exports.EPS_SETTLE_FRAME = 0;
34
+ /**
35
+ * The settle law's shared horizon (r12 4f6e2d1b8a70 / r13 minor 1d6f4b8a2e90 — ONE
36
+ * authority): validateTransition requires every accepted trajectory to be DONE by this
37
+ * instant (~285 millennia), and stepProp's precision-freeze termination samples the settled
38
+ * state at max(elapsed, this horizon). The pairing is what guarantees an accepted config
39
+ * reaches its settled value on every stepping cadence; the two consumers must never diverge.
40
+ */
41
+ exports.SETTLE_HORIZON_MS = 2 ** 53;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * CORE-only velocity staleness window (ms). Governs `MotionValue.getVelocity` and the animation
3
+ * cold-start velocity seed. It does NOT govern the gesture path — that consumes platform release
4
+ * velocity (§D/§G). A value sample older than this reads velocity `0`.
5
+ */
6
+ export declare const MAX_VELOCITY_DELTA_MS = 30;
7
+ /**
8
+ * Per-frame elapsed-time ceiling (ms). Guards the graph against a large jump after backgrounding
9
+ * (REQ-CLOCK-003). Flagged for human confirmation. ~2.4 frames at 60Hz.
10
+ */
11
+ export declare const DT_CLAMP_MS = 40;
12
+ export declare const REST_DELTA = 0.01;
13
+ export declare const REST_SPEED = 2;
14
+ /** Granular rest-threshold discontinuity at `|target − origin| < 5` (Motion). */
15
+ export declare const GRANULAR_THRESHOLD = 5;
16
+ /** Velocity equality tolerance (units/sec). */
17
+ export declare const EPS_VELOCITY = 1;
18
+ /** Trajectory / dt-robustness tolerance (value units). */
19
+ export declare const EPS_TRAJ = 0.5;
20
+ /** Settle is exact to the frame. */
21
+ export declare const EPS_SETTLE_FRAME = 0;
22
+ /**
23
+ * The settle law's shared horizon (r12 4f6e2d1b8a70 / r13 minor 1d6f4b8a2e90 — ONE
24
+ * authority): validateTransition requires every accepted trajectory to be DONE by this
25
+ * instant (~285 millennia), and stepProp's precision-freeze termination samples the settled
26
+ * state at max(elapsed, this horizon). The pairing is what guarantees an accepted config
27
+ * reaches its settled value on every stepping cadence; the two consumers must never diverge.
28
+ */
29
+ export declare const SETTLE_HORIZON_MS: number;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * CORE-only velocity staleness window (ms). Governs `MotionValue.getVelocity` and the animation
3
+ * cold-start velocity seed. It does NOT govern the gesture path — that consumes platform release
4
+ * velocity (§D/§G). A value sample older than this reads velocity `0`.
5
+ */
6
+ export declare const MAX_VELOCITY_DELTA_MS = 30;
7
+ /**
8
+ * Per-frame elapsed-time ceiling (ms). Guards the graph against a large jump after backgrounding
9
+ * (REQ-CLOCK-003). Flagged for human confirmation. ~2.4 frames at 60Hz.
10
+ */
11
+ export declare const DT_CLAMP_MS = 40;
12
+ export declare const REST_DELTA = 0.01;
13
+ export declare const REST_SPEED = 2;
14
+ /** Granular rest-threshold discontinuity at `|target − origin| < 5` (Motion). */
15
+ export declare const GRANULAR_THRESHOLD = 5;
16
+ /** Velocity equality tolerance (units/sec). */
17
+ export declare const EPS_VELOCITY = 1;
18
+ /** Trajectory / dt-robustness tolerance (value units). */
19
+ export declare const EPS_TRAJ = 0.5;
20
+ /** Settle is exact to the frame. */
21
+ export declare const EPS_SETTLE_FRAME = 0;
22
+ /**
23
+ * The settle law's shared horizon (r12 4f6e2d1b8a70 / r13 minor 1d6f4b8a2e90 — ONE
24
+ * authority): validateTransition requires every accepted trajectory to be DONE by this
25
+ * instant (~285 millennia), and stepProp's precision-freeze termination samples the settled
26
+ * state at max(elapsed, this horizon). The pairing is what guarantees an accepted config
27
+ * reaches its settled value on every stepping cadence; the two consumers must never diverge.
28
+ */
29
+ export declare const SETTLE_HORIZON_MS: number;
@@ -0,0 +1,38 @@
1
+ // @frame-path — executes inside the UI-runtime frame step; allocation-gated (REQ-DRIVER-021).
2
+ // Pinned motion-graph constants. Adopted from `motion@12.42.2` (see
3
+ // `specs/OPEN-DECISIONS.md` §D resolutions log) and PROVEN equal to that pinned oracle by the M1b
4
+ // conformance suite — these literals are a starting seed, not hand-authored ground truth. Never
5
+ // widen an epsilon here to make a test pass (test-integrity); fix the code or ratify the constant.
6
+ /**
7
+ * CORE-only velocity staleness window (ms). Governs `MotionValue.getVelocity` and the animation
8
+ * cold-start velocity seed. It does NOT govern the gesture path — that consumes platform release
9
+ * velocity (§D/§G). A value sample older than this reads velocity `0`.
10
+ */
11
+ export const MAX_VELOCITY_DELTA_MS = 30;
12
+ /**
13
+ * Per-frame elapsed-time ceiling (ms). Guards the graph against a large jump after backgrounding
14
+ * (REQ-CLOCK-003). Flagged for human confirmation. ~2.4 frames at 60Hz.
15
+ */
16
+ export const DT_CLAMP_MS = 40;
17
+ // Rest thresholds — adopted from Motion; the exact numerics and their conformance pin are owned by
18
+ // SPEC-SPRING. Present here only so CORE has one source; SPRING tightens them.
19
+ export const REST_DELTA = 0.01;
20
+ export const REST_SPEED = 2;
21
+ /** Granular rest-threshold discontinuity at `|target − origin| < 5` (Motion). */
22
+ export const GRANULAR_THRESHOLD = 5;
23
+ // Named epsilons — config, not literals in assertions. Nominal seeds from SPEC-CORE §5; final
24
+ // values ratified with SPEC-SPRING and tightened against the pinned oracle in M1b.
25
+ /** Velocity equality tolerance (units/sec). */
26
+ export const EPS_VELOCITY = 1;
27
+ /** Trajectory / dt-robustness tolerance (value units). */
28
+ export const EPS_TRAJ = 0.5;
29
+ /** Settle is exact to the frame. */
30
+ export const EPS_SETTLE_FRAME = 0;
31
+ /**
32
+ * The settle law's shared horizon (r12 4f6e2d1b8a70 / r13 minor 1d6f4b8a2e90 — ONE
33
+ * authority): validateTransition requires every accepted trajectory to be DONE by this
34
+ * instant (~285 millennia), and stepProp's precision-freeze termination samples the settled
35
+ * state at max(elapsed, this horizon). The pairing is what guarantees an accepted config
36
+ * reaches its settled value on every stepping cadence; the two consumers must never diverge.
37
+ */
38
+ export const SETTLE_HORIZON_MS = 2 ** 53;
package/dist/delay.cjs ADDED
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // @frame-path — executes inside the UI-runtime frame step; allocation-gated (REQ-DRIVER-021).
3
+ // T18-b / REQ-TIMING-004 — the delay elapsed-time REBASE. `delay` is not a generator feature in
4
+ // the pinned Motion: it is a pure `t → t − delay` shift applied AROUND the repeat fold
5
+ // (motion-dom@12.42.2 `JSAnimation.tick`: `timeWithoutDelay = currentTime − delay`, clamped at 0,
6
+ // computed BEFORE the fold arithmetic). This module is that shift, so every trajectory — bare
7
+ // generator or fold — delays identically and none of them learns about delay. Host-agnostic
8
+ // (REQ-CORE-003): relative imports only. Numerics are pinned by per-sample goldens in
9
+ // delay.test.ts.
10
+ //
11
+ // The hold is never done, which is what keeps `delay` + `duration: 0` from finishing instantly
12
+ // (the pin's `delayState` law). A NEGATIVE delay is an elapsed-time seed, not an error: the
13
+ // rebase formula is the whole law, so the first sample lands mid-trajectory — including
14
+ // mid-iteration when the magnitude exceeds whole iterations of a fold. There is no sign floor
15
+ // (pinned behavior; validate.ts bounds only a POSITIVE delay to the settle horizon and refuses
16
+ // the non-finite ones).
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.delayGenerator = delayGenerator;
19
+ /**
20
+ * Wrap `base` in the delay rebase (REQ-TIMING-004). The returned generator is a `Generator` like
21
+ * any other — the driver steps it without knowing it delays. Both driver backends call this at
22
+ * BOTH seams (start and retarget), around whatever the transition resolved to — the fold when the
23
+ * transition repeats, the bare generator otherwise — and parity between them is held by the
24
+ * executing floor, `driverParity.differential.test.ts`, not by this call being shared.
25
+ *
26
+ * While `t − delayMs < 0` the sample is the FIRST keyframe with velocity 0 and `done: false`
27
+ * (packet L2): the pin's `delayState` holds `keyframes[0]` and never completes, and our
28
+ * analytic-velocity contract (REQ-SPRING-009) reads 0 during the hold — so a mid-delay retarget
29
+ * reseeds from the held value at rest, there being no motion to be continuous WITH. The first
30
+ * keyframe is captured from `base.sample(0)` at CONSTRUCTION: every core generator is a pure
31
+ * function of elapsed time, so the zero-sample is the held value by definition.
32
+ *
33
+ * After the hold, `done` is the wrapped trajectory's own at `t − delayMs` — the fold reports done
34
+ * against its `totalDuration` (which excludes delay), so a finite animation settles at
35
+ * `delay + totalDuration` exactly (packet L4).
36
+ *
37
+ * `delayMs === 0` is elided to `base` unchanged: the identity rebase adds no behavior, and the
38
+ * drivers never produce a negative elapsed where elision would differ (`stepProp` accumulates
39
+ * non-negative deltas). A NaN elapsed is NOT laundered into the hold: `NaN < delayMs` is false,
40
+ * so the wrapped generator receives NaN and answers NaN — a broken clock stays loud (the repeat
41
+ * fold's `Math.max` law, applied here).
42
+ */
43
+ // alloc-ok: lifecycle-edge — construction captures the first keyframe and builds the ONE reused
44
+ // sample record; sample() below mutates it and allocates nothing (REQ-DRIVER-021).
45
+ function delayGenerator(base, delayMs) {
46
+ if (delayMs === 0)
47
+ return base;
48
+ const firstKeyframe = base.sample(0).value;
49
+ const out = { value: firstKeyframe, velocity: 0, done: false };
50
+ return {
51
+ // A delay is a pure time SHIFT: it moves WHEN a trajectory ends, never WHERE it rests. So the
52
+ // wrapped trajectory's finish-time commit passes straight through. Dropping it here silently
53
+ // returned `delay` + a fractional `repeat` to the mid-play landing REQ-TIMING-003 exists to
54
+ // fix — on both drivers and at both seams, through a combination validation accepts (H2
55
+ // round-1 review MAJOR 1). Every wrapper of a `Generator` owes this forward.
56
+ finalValue: base.finalValue,
57
+ sample(elapsedMs) {
58
+ const rebasedMs = elapsedMs - delayMs;
59
+ if (rebasedMs < 0) {
60
+ out.value = firstKeyframe;
61
+ out.velocity = 0;
62
+ out.done = false;
63
+ return out;
64
+ }
65
+ const sample = base.sample(rebasedMs);
66
+ out.value = sample.value;
67
+ out.velocity = sample.velocity;
68
+ out.done = sample.done;
69
+ return out;
70
+ },
71
+ };
72
+ }
@@ -0,0 +1,26 @@
1
+ import type { Generator } from "./types.cjs";
2
+ /**
3
+ * Wrap `base` in the delay rebase (REQ-TIMING-004). The returned generator is a `Generator` like
4
+ * any other — the driver steps it without knowing it delays. Both driver backends call this at
5
+ * BOTH seams (start and retarget), around whatever the transition resolved to — the fold when the
6
+ * transition repeats, the bare generator otherwise — and parity between them is held by the
7
+ * executing floor, `driverParity.differential.test.ts`, not by this call being shared.
8
+ *
9
+ * While `t − delayMs < 0` the sample is the FIRST keyframe with velocity 0 and `done: false`
10
+ * (packet L2): the pin's `delayState` holds `keyframes[0]` and never completes, and our
11
+ * analytic-velocity contract (REQ-SPRING-009) reads 0 during the hold — so a mid-delay retarget
12
+ * reseeds from the held value at rest, there being no motion to be continuous WITH. The first
13
+ * keyframe is captured from `base.sample(0)` at CONSTRUCTION: every core generator is a pure
14
+ * function of elapsed time, so the zero-sample is the held value by definition.
15
+ *
16
+ * After the hold, `done` is the wrapped trajectory's own at `t − delayMs` — the fold reports done
17
+ * against its `totalDuration` (which excludes delay), so a finite animation settles at
18
+ * `delay + totalDuration` exactly (packet L4).
19
+ *
20
+ * `delayMs === 0` is elided to `base` unchanged: the identity rebase adds no behavior, and the
21
+ * drivers never produce a negative elapsed where elision would differ (`stepProp` accumulates
22
+ * non-negative deltas). A NaN elapsed is NOT laundered into the hold: `NaN < delayMs` is false,
23
+ * so the wrapped generator receives NaN and answers NaN — a broken clock stays loud (the repeat
24
+ * fold's `Math.max` law, applied here).
25
+ */
26
+ export declare function delayGenerator(base: Generator, delayMs: number): Generator;
@@ -0,0 +1,26 @@
1
+ import type { Generator } from "./types.js";
2
+ /**
3
+ * Wrap `base` in the delay rebase (REQ-TIMING-004). The returned generator is a `Generator` like
4
+ * any other — the driver steps it without knowing it delays. Both driver backends call this at
5
+ * BOTH seams (start and retarget), around whatever the transition resolved to — the fold when the
6
+ * transition repeats, the bare generator otherwise — and parity between them is held by the
7
+ * executing floor, `driverParity.differential.test.ts`, not by this call being shared.
8
+ *
9
+ * While `t − delayMs < 0` the sample is the FIRST keyframe with velocity 0 and `done: false`
10
+ * (packet L2): the pin's `delayState` holds `keyframes[0]` and never completes, and our
11
+ * analytic-velocity contract (REQ-SPRING-009) reads 0 during the hold — so a mid-delay retarget
12
+ * reseeds from the held value at rest, there being no motion to be continuous WITH. The first
13
+ * keyframe is captured from `base.sample(0)` at CONSTRUCTION: every core generator is a pure
14
+ * function of elapsed time, so the zero-sample is the held value by definition.
15
+ *
16
+ * After the hold, `done` is the wrapped trajectory's own at `t − delayMs` — the fold reports done
17
+ * against its `totalDuration` (which excludes delay), so a finite animation settles at
18
+ * `delay + totalDuration` exactly (packet L4).
19
+ *
20
+ * `delayMs === 0` is elided to `base` unchanged: the identity rebase adds no behavior, and the
21
+ * drivers never produce a negative elapsed where elision would differ (`stepProp` accumulates
22
+ * non-negative deltas). A NaN elapsed is NOT laundered into the hold: `NaN < delayMs` is false,
23
+ * so the wrapped generator receives NaN and answers NaN — a broken clock stays loud (the repeat
24
+ * fold's `Math.max` law, applied here).
25
+ */
26
+ export declare function delayGenerator(base: Generator, delayMs: number): Generator;