@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.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/clock.cjs +71 -0
- package/dist/clock.d.cts +23 -0
- package/dist/clock.d.ts +23 -0
- package/dist/clock.js +66 -0
- package/dist/collect-reads.cjs +68 -0
- package/dist/collect-reads.d.cts +23 -0
- package/dist/collect-reads.d.ts +23 -0
- package/dist/collect-reads.js +62 -0
- package/dist/component/boundedArray.cjs +74 -0
- package/dist/component/boundedArray.d.cts +25 -0
- package/dist/component/boundedArray.d.ts +25 -0
- package/dist/component/boundedArray.js +68 -0
- package/dist/component/index.cjs +57 -0
- package/dist/component/index.d.cts +12 -0
- package/dist/component/index.d.ts +12 -0
- package/dist/component/index.js +22 -0
- package/dist/component/orchestration.cjs +129 -0
- package/dist/component/orchestration.d.cts +66 -0
- package/dist/component/orchestration.d.ts +66 -0
- package/dist/component/orchestration.js +124 -0
- package/dist/component/resolve.cjs +104 -0
- package/dist/component/resolve.d.cts +11 -0
- package/dist/component/resolve.d.ts +11 -0
- package/dist/component/resolve.js +97 -0
- package/dist/component/transition.cjs +352 -0
- package/dist/component/transition.d.cts +33 -0
- package/dist/component/transition.d.ts +33 -0
- package/dist/component/transition.js +339 -0
- package/dist/component/types.cjs +114 -0
- package/dist/component/types.d.cts +60 -0
- package/dist/component/types.d.ts +60 -0
- package/dist/component/types.js +111 -0
- package/dist/component/validate.cjs +1015 -0
- package/dist/component/validate.d.cts +37 -0
- package/dist/component/validate.d.ts +37 -0
- package/dist/component/validate.js +1002 -0
- package/dist/component/variants.cjs +333 -0
- package/dist/component/variants.d.cts +106 -0
- package/dist/component/variants.d.ts +106 -0
- package/dist/component/variants.js +321 -0
- package/dist/config/constants.cjs +41 -0
- package/dist/config/constants.d.cts +29 -0
- package/dist/config/constants.d.ts +29 -0
- package/dist/config/constants.js +38 -0
- package/dist/delay.cjs +72 -0
- package/dist/delay.d.cts +26 -0
- package/dist/delay.d.ts +26 -0
- package/dist/delay.js +70 -0
- package/dist/derived.cjs +143 -0
- package/dist/derived.d.cts +41 -0
- package/dist/derived.d.ts +41 -0
- package/dist/derived.js +139 -0
- package/dist/driver/index.cjs +22 -0
- package/dist/driver/index.d.cts +7 -0
- package/dist/driver/index.d.ts +7 -0
- package/dist/driver/index.js +14 -0
- package/dist/driver/keyframeTiming.cjs +130 -0
- package/dist/driver/keyframeTiming.d.cts +18 -0
- package/dist/driver/keyframeTiming.d.ts +18 -0
- package/dist/driver/keyframeTiming.js +124 -0
- package/dist/driver/keyframeTimingConfig.cjs +24 -0
- package/dist/driver/keyframeTimingConfig.d.cts +5 -0
- package/dist/driver/keyframeTimingConfig.d.ts +5 -0
- package/dist/driver/keyframeTimingConfig.js +22 -0
- package/dist/driver/prepare.cjs +459 -0
- package/dist/driver/prepare.d.cts +4 -0
- package/dist/driver/prepare.d.ts +4 -0
- package/dist/driver/prepare.js +454 -0
- package/dist/driver/reference.cjs +762 -0
- package/dist/driver/reference.d.cts +53 -0
- package/dist/driver/reference.d.ts +53 -0
- package/dist/driver/reference.js +757 -0
- package/dist/driver/step.cjs +55 -0
- package/dist/driver/step.d.cts +9 -0
- package/dist/driver/step.d.ts +9 -0
- package/dist/driver/step.js +52 -0
- package/dist/driver/tiers.cjs +40 -0
- package/dist/driver/tiers.d.cts +2 -0
- package/dist/driver/tiers.d.ts +2 -0
- package/dist/driver/tiers.js +37 -0
- package/dist/driver/types.cjs +9 -0
- package/dist/driver/types.d.cts +68 -0
- package/dist/driver/types.d.ts +68 -0
- package/dist/driver/types.js +8 -0
- package/dist/external-animation-ledger.cjs +1250 -0
- package/dist/external-animation-ledger.d.cts +416 -0
- package/dist/external-animation-ledger.d.ts +416 -0
- package/dist/external-animation-ledger.js +1243 -0
- package/dist/gesture/directionLock.cjs +25 -0
- package/dist/gesture/directionLock.d.cts +8 -0
- package/dist/gesture/directionLock.d.ts +8 -0
- package/dist/gesture/directionLock.js +21 -0
- package/dist/gesture/dragConfig.cjs +634 -0
- package/dist/gesture/dragConfig.d.cts +298 -0
- package/dist/gesture/dragConfig.d.ts +298 -0
- package/dist/gesture/dragConfig.js +624 -0
- package/dist/gesture/elastic.cjs +44 -0
- package/dist/gesture/elastic.d.cts +4 -0
- package/dist/gesture/elastic.d.ts +4 -0
- package/dist/gesture/elastic.js +39 -0
- package/dist/gesture/handoffSession.cjs +161 -0
- package/dist/gesture/handoffSession.d.cts +35 -0
- package/dist/gesture/handoffSession.d.ts +35 -0
- package/dist/gesture/handoffSession.js +158 -0
- package/dist/gesture/index.cjs +37 -0
- package/dist/gesture/index.d.cts +12 -0
- package/dist/gesture/index.d.ts +12 -0
- package/dist/gesture/index.js +11 -0
- package/dist/gesture/projection.cjs +95 -0
- package/dist/gesture/projection.d.cts +7 -0
- package/dist/gesture/projection.d.ts +7 -0
- package/dist/gesture/projection.js +87 -0
- package/dist/gesture/session.cjs +162 -0
- package/dist/gesture/session.d.cts +29 -0
- package/dist/gesture/session.d.ts +29 -0
- package/dist/gesture/session.js +158 -0
- package/dist/gesture/types.cjs +5 -0
- package/dist/gesture/types.d.cts +13 -0
- package/dist/gesture/types.d.ts +13 -0
- package/dist/gesture/types.js +4 -0
- package/dist/gesture/viewportConstraints.cjs +38 -0
- package/dist/gesture/viewportConstraints.d.cts +6 -0
- package/dist/gesture/viewportConstraints.d.ts +6 -0
- package/dist/gesture/viewportConstraints.js +34 -0
- package/dist/graph.cjs +226 -0
- package/dist/graph.d.cts +2 -0
- package/dist/graph.d.ts +2 -0
- package/dist/graph.js +223 -0
- package/dist/index.cjs +140 -0
- package/dist/index.d.cts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +70 -0
- package/dist/inertia.cjs +214 -0
- package/dist/inertia.d.cts +53 -0
- package/dist/inertia.d.ts +53 -0
- package/dist/inertia.js +212 -0
- package/dist/instant.cjs +66 -0
- package/dist/instant.d.cts +16 -0
- package/dist/instant.d.ts +16 -0
- package/dist/instant.js +63 -0
- package/dist/internal-driver.cjs +81 -0
- package/dist/internal-driver.d.cts +19 -0
- package/dist/internal-driver.d.ts +19 -0
- package/dist/internal-driver.js +35 -0
- package/dist/keyframes.cjs +191 -0
- package/dist/keyframes.d.cts +13 -0
- package/dist/keyframes.d.ts +13 -0
- package/dist/keyframes.js +188 -0
- package/dist/layout/commitDetector.cjs +67 -0
- package/dist/layout/commitDetector.d.cts +21 -0
- package/dist/layout/commitDetector.d.ts +21 -0
- package/dist/layout/commitDetector.js +64 -0
- package/dist/layout/compose.cjs +67 -0
- package/dist/layout/compose.d.cts +30 -0
- package/dist/layout/compose.d.ts +30 -0
- package/dist/layout/compose.js +65 -0
- package/dist/layout/constants.cjs +13 -0
- package/dist/layout/constants.d.cts +6 -0
- package/dist/layout/constants.d.ts +6 -0
- package/dist/layout/constants.js +10 -0
- package/dist/layout/identity.cjs +700 -0
- package/dist/layout/identity.d.cts +67 -0
- package/dist/layout/identity.d.ts +67 -0
- package/dist/layout/identity.js +698 -0
- package/dist/layout/index.cjs +36 -0
- package/dist/layout/index.d.cts +18 -0
- package/dist/layout/index.d.ts +18 -0
- package/dist/layout/index.js +13 -0
- package/dist/layout/measure.cjs +81 -0
- package/dist/layout/measure.d.cts +43 -0
- package/dist/layout/measure.d.ts +43 -0
- package/dist/layout/measure.js +78 -0
- package/dist/layout/projection.cjs +99 -0
- package/dist/layout/projection.d.cts +23 -0
- package/dist/layout/projection.d.ts +23 -0
- package/dist/layout/projection.js +97 -0
- package/dist/layout/scroll.cjs +27 -0
- package/dist/layout/scroll.d.cts +13 -0
- package/dist/layout/scroll.d.ts +13 -0
- package/dist/layout/scroll.js +24 -0
- package/dist/layout/session.cjs +207 -0
- package/dist/layout/session.d.cts +73 -0
- package/dist/layout/session.d.ts +73 -0
- package/dist/layout/session.js +205 -0
- package/dist/layout/tree.cjs +826 -0
- package/dist/layout/tree.d.cts +70 -0
- package/dist/layout/tree.d.ts +70 -0
- package/dist/layout/tree.js +823 -0
- package/dist/layout/types.cjs +36 -0
- package/dist/layout/types.d.cts +31 -0
- package/dist/layout/types.d.ts +31 -0
- package/dist/layout/types.js +35 -0
- package/dist/motion-arc.cjs +184 -0
- package/dist/motion-arc.d.cts +78 -0
- package/dist/motion-arc.d.ts +78 -0
- package/dist/motion-arc.js +183 -0
- package/dist/motion-mix.cjs +205 -0
- package/dist/motion-mix.d.cts +3 -0
- package/dist/motion-mix.d.ts +3 -0
- package/dist/motion-mix.js +202 -0
- package/dist/motion-value-driver-port.cjs +636 -0
- package/dist/motion-value-driver-port.d.cts +406 -0
- package/dist/motion-value-driver-port.d.ts +406 -0
- package/dist/motion-value-driver-port.js +627 -0
- package/dist/motion-value.cjs +189 -0
- package/dist/motion-value.d.cts +51 -0
- package/dist/motion-value.d.ts +51 -0
- package/dist/motion-value.js +185 -0
- package/dist/presence/controller.cjs +657 -0
- package/dist/presence/controller.d.cts +6 -0
- package/dist/presence/controller.d.ts +6 -0
- package/dist/presence/controller.js +652 -0
- package/dist/presence/index.cjs +19 -0
- package/dist/presence/index.d.cts +4 -0
- package/dist/presence/index.d.ts +4 -0
- package/dist/presence/index.js +12 -0
- package/dist/presence/machine.cjs +50 -0
- package/dist/presence/machine.d.cts +10 -0
- package/dist/presence/machine.d.ts +10 -0
- package/dist/presence/machine.js +46 -0
- package/dist/presence/types.cjs +6 -0
- package/dist/presence/types.d.cts +32 -0
- package/dist/presence/types.d.ts +32 -0
- package/dist/presence/types.js +5 -0
- package/dist/repeat.cjs +311 -0
- package/dist/repeat.d.cts +174 -0
- package/dist/repeat.d.ts +174 -0
- package/dist/repeat.js +300 -0
- package/dist/spring.cjs +128 -0
- package/dist/spring.d.cts +18 -0
- package/dist/spring.d.ts +18 -0
- package/dist/spring.js +125 -0
- package/dist/subscriptions.cjs +74 -0
- package/dist/subscriptions.d.cts +19 -0
- package/dist/subscriptions.d.ts +19 -0
- package/dist/subscriptions.js +69 -0
- package/dist/subset/index.cjs +23 -0
- package/dist/subset/index.d.cts +6 -0
- package/dist/subset/index.d.ts +6 -0
- package/dist/subset/index.js +13 -0
- package/dist/subset/normalize.cjs +90 -0
- package/dist/subset/normalize.d.cts +10 -0
- package/dist/subset/normalize.d.ts +10 -0
- package/dist/subset/normalize.js +85 -0
- package/dist/subset/registry.cjs +259 -0
- package/dist/subset/registry.d.cts +25 -0
- package/dist/subset/registry.d.ts +25 -0
- package/dist/subset/registry.js +256 -0
- package/dist/subset/resolve.cjs +98 -0
- package/dist/subset/resolve.d.cts +24 -0
- package/dist/subset/resolve.d.ts +24 -0
- package/dist/subset/resolve.js +90 -0
- package/dist/timing.cjs +206 -0
- package/dist/timing.d.cts +17 -0
- package/dist/timing.d.ts +17 -0
- package/dist/timing.js +201 -0
- package/dist/transformTemplate.cjs +219 -0
- package/dist/transformTemplate.d.cts +29 -0
- package/dist/transformTemplate.d.ts +29 -0
- package/dist/transformTemplate.js +215 -0
- package/dist/transition.cjs +231 -0
- package/dist/transition.d.cts +89 -0
- package/dist/transition.d.ts +89 -0
- package/dist/transition.js +223 -0
- package/dist/types.cjs +4 -0
- package/dist/types.d.cts +175 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.js +3 -0
- package/dist/value-types/color.cjs +220 -0
- package/dist/value-types/color.d.cts +19 -0
- package/dist/value-types/color.d.ts +19 -0
- package/dist/value-types/color.js +218 -0
- package/dist/value-types/complex.cjs +160 -0
- package/dist/value-types/complex.d.cts +19 -0
- package/dist/value-types/complex.d.ts +19 -0
- package/dist/value-types/complex.js +155 -0
- package/dist/value-types/constants.cjs +15 -0
- package/dist/value-types/constants.d.cts +6 -0
- package/dist/value-types/constants.d.ts +6 -0
- package/dist/value-types/constants.js +12 -0
- package/dist/value-types/discrete.cjs +62 -0
- package/dist/value-types/discrete.d.cts +4 -0
- package/dist/value-types/discrete.d.ts +4 -0
- package/dist/value-types/discrete.js +56 -0
- package/dist/value-types/index.cjs +59 -0
- package/dist/value-types/index.d.cts +14 -0
- package/dist/value-types/index.d.ts +14 -0
- package/dist/value-types/index.js +24 -0
- package/dist/value-types/measure-resolve.cjs +325 -0
- package/dist/value-types/measure-resolve.d.cts +91 -0
- package/dist/value-types/measure-resolve.d.ts +91 -0
- package/dist/value-types/measure-resolve.js +313 -0
- package/dist/value-types/mix.cjs +90 -0
- package/dist/value-types/mix.d.cts +27 -0
- package/dist/value-types/mix.d.ts +27 -0
- package/dist/value-types/mix.js +85 -0
- package/dist/value-types/named-colors.cjs +61 -0
- package/dist/value-types/named-colors.d.cts +2 -0
- package/dist/value-types/named-colors.d.ts +2 -0
- package/dist/value-types/named-colors.js +58 -0
- package/dist/value-types/numeric.cjs +86 -0
- package/dist/value-types/numeric.d.cts +16 -0
- package/dist/value-types/numeric.d.ts +16 -0
- package/dist/value-types/numeric.js +79 -0
- package/dist/worklet-layout/config/constants.js +39 -0
- package/dist/worklet-layout/layout/constants.js +11 -0
- package/dist/worklet-layout/layout/identity.js +699 -0
- package/dist/worklet-layout/layout/projection.js +98 -0
- package/dist/worklet-layout/layout/session.js +206 -0
- package/dist/worklet-layout/layout/tree.js +824 -0
- package/dist/worklet-layout/layout/types.js +36 -0
- package/dist/worklet-layout/spring.js +125 -0
- package/dist/worklet-layout/timing.js +201 -0
- package/dist/worklet-layout/transition.js +223 -0
- package/dist/worklet-layout.cjs +47 -0
- package/dist/worklet-layout.d.cts +15 -0
- package/dist/worklet-layout.d.ts +15 -0
- package/dist/worklet-layout.js +28 -0
- package/dist/wrap.cjs +7 -0
- package/dist/wrap.d.cts +1 -0
- package/dist/wrap.d.ts +1 -0
- package/dist/wrap.js +4 -0
- 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
|
+
}
|
package/dist/delay.d.cts
ADDED
|
@@ -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;
|
package/dist/delay.d.ts
ADDED
|
@@ -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;
|