@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,762 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPEC-NATIVE-DRIVER §Requirements — the reference in-core Driver (REQ-DRIVER-013/020). A concrete,
|
|
3
|
+
// host-agnostic `Driver` the fake host adapter and the deterministic conformance drive; the native worklet
|
|
4
|
+
// and web drivers are the substrate-bound peers of this same interface. It composes the built ladder and
|
|
5
|
+
// forks nothing (REQ-DRIVER-003): the SPRING/TIMING generators (via the COMPONENT seconds→ms converters)
|
|
6
|
+
// supply every trajectory, `retargetSpring` supplies spring continuity, and the pure `stepProp` advances
|
|
7
|
+
// each frame. A command seeds state once (O(1)); `step` reads only seeded state — zero per-frame JS logic
|
|
8
|
+
// beyond the pure advance (REQ-DRIVER-013). An element quiesces when all its animations settle
|
|
9
|
+
// (REQ-DRIVER-020). Host-agnostic (REQ-CORE-003): relative imports only.
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.referenceFoldRefusal = referenceFoldRefusal;
|
|
12
|
+
exports.referenceRetargetFoldRefusal = referenceRetargetFoldRefusal;
|
|
13
|
+
exports.createReferenceDriver = createReferenceDriver;
|
|
14
|
+
const component_1 = require("../component/index.cjs");
|
|
15
|
+
const transition_1 = require("../component/transition.cjs");
|
|
16
|
+
const delay_1 = require("../delay.cjs");
|
|
17
|
+
const inertia_1 = require("../inertia.cjs");
|
|
18
|
+
const instant_1 = require("../instant.cjs");
|
|
19
|
+
const keyframes_1 = require("../keyframes.cjs");
|
|
20
|
+
const repeat_1 = require("../repeat.cjs");
|
|
21
|
+
const timing_1 = require("../timing.cjs");
|
|
22
|
+
const transition_2 = require("../transition.cjs");
|
|
23
|
+
const motion_arc_1 = require("../motion-arc.cjs");
|
|
24
|
+
const prepare_1 = require("./prepare.cjs");
|
|
25
|
+
const step_1 = require("./step.cjs");
|
|
26
|
+
// Clear the gesture hold on ONE prop (the matching release/stop command owns it now). Idempotent —
|
|
27
|
+
// clearing an unheld prop is a no-op, so the heldCount stays exact (review r7 major 23).
|
|
28
|
+
function releaseHold(element, key) {
|
|
29
|
+
if (element.heldVelocity[key] !== undefined) {
|
|
30
|
+
delete element.heldVelocity[key];
|
|
31
|
+
element.heldCount--;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Build a fresh generator for a `start`: from the resolved base to the target, under the transition. Springs
|
|
35
|
+
// and tweens are selected by `transition.type` — with one pin-mandated addition (REQ-TIMING-006): an
|
|
36
|
+
// authored duration-ONLY bag (type omitted) also takes the timing generator, the pin's
|
|
37
|
+
// `type = keyframesGenerator` default for any DEFINED transition. Spring remains the fallback for
|
|
38
|
+
// everything else, reusing the COMPONENT seconds→ms
|
|
39
|
+
// converters + the built generators — no forked math (REQ-DRIVER-003). `velocity` is the REQ-DRIVER-023
|
|
40
|
+
// seed (the gesture release's platform handoff); a tween is position-based and ignores it by construction,
|
|
41
|
+
// kept explicit here so the contract reads at the seam.
|
|
42
|
+
// Normalize a PropTransition to the authored inputs the generators consume (R8 M2, consult
|
|
43
|
+
// agent-2026-07-19-e715fd). A controller-resolved default (`DefaultTransition`) carries shapes the
|
|
44
|
+
// authored `Transition` cannot: a `type:'keyframes'` default normalizes to the equivalent tween — an
|
|
45
|
+
// ABSENT `ease` is preserved so the keyframes generator keeps its intrinsic per-segment easeInOut (the
|
|
46
|
+
// 800ms default); a `type:'spring'` default carries `restSpeed` (Motion's default-transitions
|
|
47
|
+
// override), returned alongside to thread into the spring's settle threshold. Since U7c
|
|
48
|
+
// (REQ-SPRING-014) an AUTHORED spring may also carry restSpeed/restDelta — the extraction below
|
|
49
|
+
// reads the same key either way, and `springConfigWithRest` threads it over `toSpringConfig`'s own
|
|
50
|
+
// passthrough, so authored and default thresholds reach the solver identically.
|
|
51
|
+
function normalizeTransition(transition) {
|
|
52
|
+
if (transition.type === 'keyframes') {
|
|
53
|
+
return {
|
|
54
|
+
authored: {
|
|
55
|
+
type: 'tween',
|
|
56
|
+
duration: transition.duration,
|
|
57
|
+
...(transition.ease !== undefined ? { ease: transition.ease } : {}),
|
|
58
|
+
...(transition.delay !== undefined ? { delay: transition.delay } : {}),
|
|
59
|
+
...(transition.repeat !== undefined ? { repeat: transition.repeat } : {}),
|
|
60
|
+
...(transition.repeatType !== undefined ? { repeatType: transition.repeatType } : {}),
|
|
61
|
+
...(transition.repeatDelay !== undefined ? { repeatDelay: transition.repeatDelay } : {}),
|
|
62
|
+
},
|
|
63
|
+
restSpeed: undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const restSpeed = transition.type === 'spring' && 'restSpeed' in transition ? transition.restSpeed : undefined;
|
|
67
|
+
return { authored: transition, restSpeed };
|
|
68
|
+
}
|
|
69
|
+
// Thread a default spring's `restSpeed` (settle threshold) into the resolved SpringConfig;
|
|
70
|
+
// authored restDelta/restSpeed (U7c) already flow through `toSpringConfig`'s passthrough.
|
|
71
|
+
function springConfigWithRest(transition, restSpeed) {
|
|
72
|
+
return restSpeed !== undefined
|
|
73
|
+
? { ...(0, component_1.toSpringConfig)(transition), restSpeed }
|
|
74
|
+
: (0, component_1.toSpringConfig)(transition);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* T18-a (REQ-API-049 / REQ-DRIVER-031): apply the repeat fold around whatever trajectory the
|
|
78
|
+
* transition resolves to. The fold is generator-agnostic, so this wraps the ONE unrepeated
|
|
79
|
+
* construction below rather than teaching any generator about repetition, and it delegates to
|
|
80
|
+
* core's shared `buildRepeatedGenerator` — the same call the worklet driver makes. Sharing the call
|
|
81
|
+
* is necessary but NOT sufficient for parity: both backends shared it and still skewed, because
|
|
82
|
+
* only the start seam folded. What actually holds the two backends together is the executing floor,
|
|
83
|
+
* `driverParity.differential.test.ts`. (`check:resolution-skew` compares package.json export
|
|
84
|
+
* conditions — module ENTRY-POINT resolution — and has never inspected either driver.)
|
|
85
|
+
*
|
|
86
|
+
* An inertia transition never folds — and is not REFUSED, which an earlier draft of this comment
|
|
87
|
+
* claimed (fix-up review). There is nothing to refuse: `inertia` is absent from the public
|
|
88
|
+
* `TransitionType` (`'spring' | 'tween' | false`), so it is unauthorable, reaching this seam only as the
|
|
89
|
+
* command layer's own gesture-release settle, which carries no authored options. The branch is
|
|
90
|
+
* therefore a defensive skip over a shape that cannot carry a fold, not a severity boundary.
|
|
91
|
+
*/
|
|
92
|
+
function startGenerator(transition, to, from, velocity) {
|
|
93
|
+
const { authored } = normalizeTransition(transition);
|
|
94
|
+
// U7a + transition-default-selection F5: the instant lane — the pin's makeAnimationInstant
|
|
95
|
+
// (motion-dom@12.42.2 motion-value.ts:89-98). The guard is the pin's, type-independent:
|
|
96
|
+
// `type: false` (U7a) OR `duration === 0 && !repeatDelay` (F5). NO trajectory generator, NO
|
|
97
|
+
// fold: the final keyframe commits on the driver's next update tick (never synchronously), and
|
|
98
|
+
// the authored delay is honored through the shared rebase. A repeatDelay-bearing duration-zero
|
|
99
|
+
// bag is exempt and keeps its generator below (the zero-length timing base there takes the same
|
|
100
|
+
// instant SHAPE so the fold's plays stay zero-length). The inertia narrow keeps the union
|
|
101
|
+
// discriminated for the delay crossing.
|
|
102
|
+
if (authored.type !== 'inertia' &&
|
|
103
|
+
(authored.type === false || (0, transition_1.isDurationZeroInstantTransition)(authored))) {
|
|
104
|
+
return (0, delay_1.delayGenerator)((0, instant_1.instantGenerator)((0, instant_1.instantFinalKeyframe)(to))({ from, velocity: 0 }), (0, component_1.toDelayMs)(authored));
|
|
105
|
+
}
|
|
106
|
+
const fold = authored.type === 'inertia' ? null : (0, component_1.toRepeatFoldOptions)(authored);
|
|
107
|
+
// T18-b (REQ-TIMING-004 / REQ-DRIVER-032): the delay rebase wraps AROUND the fold-or-generator —
|
|
108
|
+
// core's shared `delayGenerator`, the ONE rebase seam the worklet driver calls identically at
|
|
109
|
+
// BOTH phases. An inertia release is command-layer-only and carries no authored delay (mirroring
|
|
110
|
+
// the fold's defensive skip, not a severity boundary). `toDelayMs` is the seconds→ms crossing.
|
|
111
|
+
// Sharing the call is not parity on its own — `driverParity.differential.test.ts` executes both
|
|
112
|
+
// backends over delayed commands and compares frame for frame.
|
|
113
|
+
const delayMs = authored.type === 'inertia' ? 0 : (0, component_1.toDelayMs)(authored);
|
|
114
|
+
if (fold === null)
|
|
115
|
+
return (0, delay_1.delayGenerator)(unrepeatedGenerator(transition, to, from, velocity, false), delayMs);
|
|
116
|
+
// Legs are built EAGERLY and passed as values — never a factory the fold would invoke, which on
|
|
117
|
+
// the UI runtime is the wrong-runtime crash class (`check:worklet-closures`). The worklet driver
|
|
118
|
+
// mirrors this shape exactly.
|
|
119
|
+
const leg = fold.repeatType === 'mirror'
|
|
120
|
+
? { type: 'mirror', mirrored: unrepeatedGenerator(transition, to, from, velocity, true) }
|
|
121
|
+
: { type: fold.repeatType };
|
|
122
|
+
const folded = (0, repeat_1.buildRepeatedGenerator)(fold.repeat, leg, fold.repeatDelayMs, unrepeatedGenerator(transition, to, from, velocity, false), knownIterationDurationMs(transition, to));
|
|
123
|
+
if (folded instanceof Error)
|
|
124
|
+
throw repeatRefusal(fold, folded);
|
|
125
|
+
return (0, delay_1.delayGenerator)(folded, delayMs);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The fold's refusal, TYPED (T18-a fix-up, review MAJOR). Whether a trajectory ever settles depends
|
|
129
|
+
* on the DISTANCE travelled and the seed velocity, so it is not decidable from the authored
|
|
130
|
+
* transition and validation cannot own it — this seam, which holds the real generator, does. It
|
|
131
|
+
* arrived here as a bare `Error`, which is what let the failure surface as an anonymous driver-lane
|
|
132
|
+
* fault instead of a refusal naming the offending property.
|
|
133
|
+
*/
|
|
134
|
+
// alloc-ok: lifecycle-edge — built only on the refusal path, once per rejected animate command.
|
|
135
|
+
function repeatRefusal(fold, refusal) {
|
|
136
|
+
return new component_1.InvalidTransitionError(undefined, 'repeat', fold.repeat, refusal.message);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The transition's own resolved iteration length in ms, or null when only a scan can measure it —
|
|
140
|
+
* mirroring the pin's `calculatedDuration` rule (`spring.ts:378`: `isResolvedFromDuration ?
|
|
141
|
+
* duration || null : null`; the keyframes generator always knows its own `duration`).
|
|
142
|
+
*/
|
|
143
|
+
function knownIterationDurationMs(transition, to) {
|
|
144
|
+
const { authored } = normalizeTransition(transition);
|
|
145
|
+
// Narrows `authored` off the inertia arm as well as answering the lane's first question.
|
|
146
|
+
if (authored.type === 'inertia')
|
|
147
|
+
return null;
|
|
148
|
+
// The lane comes from core's ONE rule, never re-derived here (T18-a fix-up review MAJOR: three
|
|
149
|
+
// parallel copies of it drifted across four rounds).
|
|
150
|
+
const lane = (0, repeat_1.iterationMeasurementLane)(typeof to === 'number', authored.type === 'spring',
|
|
151
|
+
// REQ-TIMING-006 + F6: the untyped timing-lane bag (duration-only OR ease-only) measures the
|
|
152
|
+
// timing lane (the authored duration, or the generator's 300ms default), never the
|
|
153
|
+
// duration-spring's resolved settle.
|
|
154
|
+
authored.type === 'tween' || (0, transition_1.isTimingLaneTransition)(authored));
|
|
155
|
+
if (lane === 'keyframes')
|
|
156
|
+
return (0, component_1.toKeyframesConfig)(authored).duration ?? null;
|
|
157
|
+
if (lane === 'timing')
|
|
158
|
+
return (0, component_1.toTimingConfig)(authored).duration ?? null;
|
|
159
|
+
const resolved = (0, transition_2.resolveSpring)((0, component_1.toSpringConfig)(authored));
|
|
160
|
+
// `duration || null`: a zero-length resolution is NOT a known duration — the scan measures it,
|
|
161
|
+
// and the fold's own refusal then names the degenerate iteration (T18-a L3).
|
|
162
|
+
return resolved.calculatedDuration !== null && resolved.calculatedDuration > 0
|
|
163
|
+
? resolved.calculatedDuration
|
|
164
|
+
: null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* One unrepeated trajectory. `reversed` builds the MIRRORED leg (the pin's second generator): the
|
|
168
|
+
* origin and target swap and the seed velocity negates, and a keyframe list is reversed AFTER its
|
|
169
|
+
* nulls resolve — `times`/`ease` are deliberately untouched, exactly as the pin leaves them, so a
|
|
170
|
+
* mirrored leg is a genuinely different trajectory rather than a time-reflection.
|
|
171
|
+
*/
|
|
172
|
+
function unrepeatedGenerator(transition, to, from, velocity, reversed) {
|
|
173
|
+
const { authored, restSpeed } = normalizeTransition(transition);
|
|
174
|
+
if (typeof to !== 'number') {
|
|
175
|
+
if (reversed && authored.type !== 'inertia') {
|
|
176
|
+
// Resolve from-current nulls BEFORE reversing (R8-F2): the pin mirrors the RESOLVED
|
|
177
|
+
// keyframes, and a null that slid to the tail would re-read `from` at the wrong end.
|
|
178
|
+
const resolvedKeyframes = to.map((value) => (value === null ? from : value));
|
|
179
|
+
const mirroredKeyframes = [...resolvedKeyframes].reverse();
|
|
180
|
+
const mirroredFrom = mirroredKeyframes[0] ?? from;
|
|
181
|
+
if (authored.type === 'spring') {
|
|
182
|
+
return springKeyframeGenerator(authored, restSpeed, mirroredKeyframes, mirroredFrom, -velocity);
|
|
183
|
+
}
|
|
184
|
+
return (0, keyframes_1.keyframesGenerator)(mirroredKeyframes, (0, component_1.toKeyframesConfig)(authored))({ from: mirroredFrom, velocity: 0 });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (typeof to !== 'number') {
|
|
188
|
+
if (authored.type === 'inertia') {
|
|
189
|
+
// R16 shape totality (review major 3, G-INV-8/-10): a keyframe array under an inertia
|
|
190
|
+
// transition is a command-shape defect — the worklet driver throws the identical class;
|
|
191
|
+
// never silently run inertia ignoring the array.
|
|
192
|
+
throw new Error('a keyframe array cannot run under an inertia transition (REQ-GESTURE-023, R16).');
|
|
193
|
+
}
|
|
194
|
+
// A keyframe ARRAY HONORS `transition.type` (REQ-API-033, R8-F1). An EXPLICIT spring interpolates
|
|
195
|
+
// exactly two keyframes (Motion's `assertTwoKeyframes`): two → spring physics; a >2 spring FAILS
|
|
196
|
+
// LOUD naming the successor — it never reaches `resolveSpringGenerator` to be silently accepted. A
|
|
197
|
+
// tween or the DEFAULT routes the array THROUGH the keyframes generator (even offsets, per-segment
|
|
198
|
+
// ease); position-based, the seed velocity is dropped and a null FIRST element reads `from` (R8-F2).
|
|
199
|
+
if (authored.type === 'spring')
|
|
200
|
+
return springKeyframeGenerator(authored, restSpeed, to, from, velocity);
|
|
201
|
+
return (0, keyframes_1.keyframesGenerator)(to, (0, component_1.toKeyframesConfig)(authored))({ from, velocity: 0 });
|
|
202
|
+
}
|
|
203
|
+
if (authored.type === 'inertia') {
|
|
204
|
+
// R16 (REQ-GESTURE-023): the gesture free-drag release's two-phase generator. `to` is the
|
|
205
|
+
// mirror terminal (the clamped ideal); the generator recomputes its own ideal from the seed
|
|
206
|
+
// and owns the walls via the boundary spring. The seed velocity is the platform release
|
|
207
|
+
// velocity, momentum-gated upstream (REQ-GESTURE-027).
|
|
208
|
+
return (0, inertia_1.inertiaGenerator)({
|
|
209
|
+
power: authored.power,
|
|
210
|
+
timeConstant: authored.timeConstant,
|
|
211
|
+
bounceStiffness: authored.bounceStiffness,
|
|
212
|
+
bounceDamping: authored.bounceDamping,
|
|
213
|
+
restDelta: authored.restDelta,
|
|
214
|
+
restSpeed: authored.restSpeed,
|
|
215
|
+
...(authored.min !== undefined ? { min: authored.min } : {}),
|
|
216
|
+
...(authored.max !== undefined ? { max: authored.max } : {}),
|
|
217
|
+
})({ from, velocity });
|
|
218
|
+
}
|
|
219
|
+
// The scalar mirrored leg: origin and target swap, and the seed velocity negates (the pin builds
|
|
220
|
+
// its second generator with `velocity: -velocity`).
|
|
221
|
+
const scalarTo = reversed ? from : to;
|
|
222
|
+
const scalarFrom = reversed ? to : from;
|
|
223
|
+
const scalarVelocity = reversed ? -velocity : velocity;
|
|
224
|
+
// REQ-TIMING-006 + transition-default-selection F1/F6: an authored duration-ONLY bag (type
|
|
225
|
+
// omitted) OR a defined ease-only bag takes the pin's keyframes/timing generator — monotone,
|
|
226
|
+
// `easeOut` by default when NO ease spelling is authored, the authored ease verbatim for the
|
|
227
|
+
// ease-only form (the pin's defined-typeless lane at the 300ms default, JSAnimation.ts:106-116) —
|
|
228
|
+
// never the old omitted-type duration-spring (U7a finding A, device peak 1.046) and never the
|
|
229
|
+
// REQ-SPRING-003 generic spring for an ease-only bag. F1 gives the TYPED tween the same easeOut
|
|
230
|
+
// base through the ONE config builder (component/transition.ts `toTimingLaneConfig`);
|
|
231
|
+
// `isTimingLaneTransition` is the single-sourced untyped arm.
|
|
232
|
+
if (authored.type === 'tween' || (0, transition_1.isTimingLaneTransition)(authored)) {
|
|
233
|
+
// F5: a zero-length timing base takes the pin's makeAnimationInstant SHAPE — hold the seed at
|
|
234
|
+
// t ≤ 0, commit the final keyframe past it (motion-value.ts:89-98). Only repeatDelay-bearing
|
|
235
|
+
// bags reach this (a zero duration without one routes to the instant lane above); it keeps
|
|
236
|
+
// the fold's zero-length plays from committing at the command edge.
|
|
237
|
+
if (authored.duration === 0) {
|
|
238
|
+
return (0, instant_1.instantGenerator)(scalarTo)({ from: scalarFrom, velocity: 0 });
|
|
239
|
+
}
|
|
240
|
+
return (0, timing_1.timingGenerator)(scalarTo, (0, transition_1.toTimingLaneConfig)(authored))({ from: scalarFrom, velocity: 0 });
|
|
241
|
+
}
|
|
242
|
+
return (0, transition_2.resolveSpringGenerator)(scalarTo, springConfigWithRest(authored, restSpeed))({ from: scalarFrom, velocity: scalarVelocity });
|
|
243
|
+
}
|
|
244
|
+
// R8-F1: a keyframe ARRAY under an EXPLICIT spring. A spring interpolates EXACTLY two keyframes — the
|
|
245
|
+
// pinned Motion throws `spring-two-frames` for more. Two keyframes run spring physics from keyframes[0]
|
|
246
|
+
// (the explicit origin; a null first element reads `from`, from-current R8-F2) to keyframes[1] (the
|
|
247
|
+
// target); a longer array FAILS LOUD naming the successor so it never reaches `resolveSpringGenerator`.
|
|
248
|
+
function springKeyframeGenerator(transition, restSpeed, keyframes, from, velocity) {
|
|
249
|
+
const countRefusal = (0, transition_2.springKeyframeCountRefusal)(keyframes.length);
|
|
250
|
+
if (countRefusal !== null)
|
|
251
|
+
throw countRefusal;
|
|
252
|
+
const origin = keyframes[0];
|
|
253
|
+
const target = keyframes[1];
|
|
254
|
+
// Validation guarantees a length-2 array whose only legal null is index 0 and whose target parses;
|
|
255
|
+
// the guard keeps this TOTAL under noUncheckedIndexedAccess (never hit for a valid target).
|
|
256
|
+
if (origin === undefined || target === undefined || target === null) {
|
|
257
|
+
throw new Error(`malformed two-keyframe spring array — a non-null numeric target is required (REQ-API-033).`);
|
|
258
|
+
}
|
|
259
|
+
const seedFrom = origin === null ? from : origin;
|
|
260
|
+
return (0, transition_2.resolveSpringGenerator)(target, springConfigWithRest(transition, restSpeed))({
|
|
261
|
+
from: seedFrom,
|
|
262
|
+
velocity,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
// Build a generator that CONTINUES from a live property's current value+velocity to a new target (REQ-API-
|
|
266
|
+
// 003 interruption continuity). Springs use SPRING's own `retargetSpring` (carries the analytic velocity);
|
|
267
|
+
// tweens are position-based, so they reseed from the live value with no carried velocity.
|
|
268
|
+
function unrepeatedRetargetGenerator(transition, live, to) {
|
|
269
|
+
// Normalize first, exactly as `unrepeatedGenerator` does: the authored form is what the config
|
|
270
|
+
// converters accept, and a `type:'keyframes'` default normalizes to its equivalent tween rather
|
|
271
|
+
// than falling through to the spring branch. The disjoint inertia arm runs FIRST so the union
|
|
272
|
+
// narrows to `Transition` for the converter accept below (arms are mutually exclusive; the
|
|
273
|
+
// order swap changes nothing observable).
|
|
274
|
+
const { authored, restSpeed } = normalizeTransition(transition);
|
|
275
|
+
if (authored.type === 'inertia') {
|
|
276
|
+
// R16: a retarget INTO an inertia transition re-seeds the two-phase generator from the LIVE
|
|
277
|
+
// sample — the same continuity law as a spring retarget (C0/C1). The worklet driver has always
|
|
278
|
+
// done this; the reference driver used to fall through to the spring branch and hand an inertia
|
|
279
|
+
// transition to `toSpringConfig`. Pinned as a parity row in driverParity.differential.test.ts.
|
|
280
|
+
const at = live.generator.sample(live.elapsed);
|
|
281
|
+
return unrepeatedGenerator(transition, to, at.value, at.velocity, false);
|
|
282
|
+
}
|
|
283
|
+
if (authored.type === 'tween' || (0, transition_1.isTimingLaneTransition)(authored)) {
|
|
284
|
+
// F5: the zero-length timing base takes the instant SHAPE here too — the same routing as
|
|
285
|
+
// `unrepeatedGenerator`, seeded from the live value (no cross-seam skew).
|
|
286
|
+
if (authored.duration === 0) {
|
|
287
|
+
return (0, instant_1.instantGenerator)(to)({ from: live.value, velocity: 0 });
|
|
288
|
+
}
|
|
289
|
+
return (0, timing_1.timingGenerator)(to, (0, transition_1.toTimingLaneConfig)(authored))({ from: live.value, velocity: 0 });
|
|
290
|
+
}
|
|
291
|
+
return (0, transition_2.retargetSpring)(live.generator, live.elapsed, to, springConfigWithRest(authored, restSpeed));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* T18-a fix-up (review BLOCKER, two independent reviewers): a retarget carries the repeat fold,
|
|
295
|
+
* exactly as `start` does. For a repeating animation this seam is not an edge case, it is the
|
|
296
|
+
* COMMON one — an endless repeat is never `done`, so every changed scalar animate key routes here
|
|
297
|
+
* instead of to `start`. Dropping the fold stopped the loop permanently on the first retarget and
|
|
298
|
+
* then fired the completion the transition says can never come. The internal tell was that the
|
|
299
|
+
* gesture-HELD branch already folds (it builds through `startGenerator`), so the same authoring
|
|
300
|
+
* repeated or not depending on whether a finger happened to be down.
|
|
301
|
+
*
|
|
302
|
+
* The pin rebuilds every retarget as a fresh animation spreading `...valueTransition`
|
|
303
|
+
* (`motion-dom/src/animation/interfaces/motion-value.ts`), so repeat/repeatType/repeatDelay ride
|
|
304
|
+
* through unchanged. The fold's BASE here is the continuity-carrying retarget generator, so
|
|
305
|
+
* iteration 0 keeps the live value and analytic velocity (REQ-API-003) and each later iteration
|
|
306
|
+
* replays from that same seed.
|
|
307
|
+
*/
|
|
308
|
+
function retargetGenerator(transition, live, to) {
|
|
309
|
+
const { authored } = normalizeTransition(transition);
|
|
310
|
+
// U7a + F5: the instant lane at the retarget seam — the pin's guard is type-independent
|
|
311
|
+
// (`type: false` OR `duration === 0 && !repeatDelay`, motion-value.ts:89-98). Commit the new
|
|
312
|
+
// target on the next update tick from the live value, honoring the retarget's OWN authored
|
|
313
|
+
// delay (the pin starts a fresh animation per retarget). No fold, exactly as `startGenerator`.
|
|
314
|
+
// The inertia narrow keeps the union discriminated for the delay crossing.
|
|
315
|
+
if (authored.type !== 'inertia' &&
|
|
316
|
+
(authored.type === false || (0, transition_1.isDurationZeroInstantTransition)(authored))) {
|
|
317
|
+
return (0, delay_1.delayGenerator)((0, instant_1.instantGenerator)(to)({ from: live.value, velocity: 0 }), (0, component_1.toDelayMs)(authored));
|
|
318
|
+
}
|
|
319
|
+
const base = unrepeatedRetargetGenerator(transition, live, to);
|
|
320
|
+
const fold = authored.type === 'inertia' ? null : (0, component_1.toRepeatFoldOptions)(authored);
|
|
321
|
+
// T18-b (REQ-DRIVER-032): a retarget applies its OWN delay, as the pin starts a fresh animation
|
|
322
|
+
// per retarget. The rebase wraps the (possibly folded) retarget trajectory — AROUND the fold,
|
|
323
|
+
// the same core seam as `startGenerator`. A mid-delay retarget reseeds from the held first
|
|
324
|
+
// keyframe at velocity 0, because the outgoing delay wrapper reports exactly that while held
|
|
325
|
+
// (packet L2: no motion to be continuous WITH).
|
|
326
|
+
const delayMs = authored.type === 'inertia' ? 0 : (0, component_1.toDelayMs)(authored);
|
|
327
|
+
if (fold === null)
|
|
328
|
+
return (0, delay_1.delayGenerator)(base, delayMs);
|
|
329
|
+
// Legs eager, never a factory the fold would invoke — the worklet driver mirrors this shape
|
|
330
|
+
// exactly (`check:worklet-closures`). The mirrored leg swaps origin/target around the LIVE value.
|
|
331
|
+
const leg = fold.repeatType === 'mirror'
|
|
332
|
+
? { type: 'mirror', mirrored: unrepeatedGenerator(transition, to, live.value, 0, true) }
|
|
333
|
+
: { type: fold.repeatType };
|
|
334
|
+
const folded = (0, repeat_1.buildRepeatedGenerator)(fold.repeat, leg, fold.repeatDelayMs, base, knownIterationDurationMs(transition, to));
|
|
335
|
+
if (folded instanceof Error)
|
|
336
|
+
throw repeatRefusal(fold, folded);
|
|
337
|
+
return (0, delay_1.delayGenerator)(folded, delayMs);
|
|
338
|
+
}
|
|
339
|
+
// A CONTENDING target drifts FROM the committed finger value — never a backward jump off the finger
|
|
340
|
+
// (REQ-DRIVER-026 / G-INV-2, review major 25). A keyframe array's non-null FIRST element would make the
|
|
341
|
+
// generator restart near keyframes[0], rewinding the drift; re-seed the first keyframe from-current
|
|
342
|
+
// (null-first, R8-F2) so the trajectory runs the live value → remaining keyframes. A scalar (springs/
|
|
343
|
+
// tweens already seed from `from`) and an already-null-first array are unchanged. `to` is a captured
|
|
344
|
+
// snapshot, so this reads it once more into a fresh frozen array only at a command/gesture edge.
|
|
345
|
+
function anchorContentionToLive(to) {
|
|
346
|
+
if (typeof to === 'number' || to[0] === null)
|
|
347
|
+
return to;
|
|
348
|
+
return Object.freeze([null, ...to.slice(1)]);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* This backend's OWN verdict on a fold, for one transition and one target, with the boundary
|
|
352
|
+
* validation `command()` runs first deliberately NOT in the path.
|
|
353
|
+
*
|
|
354
|
+
* It exists because the parity floor that guards this rung was structurally half-blind without it
|
|
355
|
+
* (fix-up review MAJOR): `prepareDriverCommand` calls `validateTransitionRefusal` before reaching
|
|
356
|
+
* any generator, so a floor that reads `command()`'s throw sees validation's own refusal echoed back
|
|
357
|
+
* as "the driver refused". Every over-refusal therefore passed — a mutation that made validation
|
|
358
|
+
* reject 36 executable configs left the floor green. Only a verdict taken from BELOW validation can
|
|
359
|
+
* decide whether validation is measuring the fold the way this backend does.
|
|
360
|
+
*
|
|
361
|
+
* Returns the fold's refusal, or null when this backend would construct and run the generator.
|
|
362
|
+
*
|
|
363
|
+
* `from` is a real parameter, not a convenience: a null-first keyframe array (`[null, 100]`, the
|
|
364
|
+
* from-current form) resolves its first keyframe FROM the live value, so with `from` pinned at 0 it
|
|
365
|
+
* is indistinguishable from `[0, 100]` and the target axis loses a shape it claims to sweep (round-5
|
|
366
|
+
* review MINOR).
|
|
367
|
+
*
|
|
368
|
+
* Test seam for this package's own parity floor — NOT part of any published entry: exporting it from
|
|
369
|
+
* `internal-driver` would pull this whole backend into the seam the worklet driver imports.
|
|
370
|
+
*/
|
|
371
|
+
function referenceFoldRefusal(transition, to, from = 0) {
|
|
372
|
+
try {
|
|
373
|
+
startGenerator(transition, to, from, 0);
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
catch (error) {
|
|
377
|
+
// Only the fold's own refusal answers this question. Anything else is a different fault and must
|
|
378
|
+
// not be laundered into a verdict — it propagates.
|
|
379
|
+
if (error instanceof component_1.InvalidTransitionError && error.key === 'repeat')
|
|
380
|
+
return error;
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* The same verdict at the RETARGET seam — the second half of the parity floor's oracle.
|
|
386
|
+
*
|
|
387
|
+
* Rounds 4-6 each fixed one axis pinned to a constant (`repeat`, then `repeatDelay`), and round 7
|
|
388
|
+
* found the pattern one level up: the floor's ORACLE was itself pinned to a constant — the `start`
|
|
389
|
+
* seam of the reference backend — while `buildRepeatedGenerator` has four seams (two backends x two
|
|
390
|
+
* phases). The retarget seam is not a duplicate of `start`:
|
|
391
|
+
*
|
|
392
|
+
* - it reseeds the scan from the live VALUE, so the distance it measures is the distance from
|
|
393
|
+
* wherever the animation currently IS — a different trajectory than `start` measured, which is
|
|
394
|
+
* why it can refuse where `start` ran (round-7 review MAJOR). It also carries the live velocity
|
|
395
|
+
* into the reseed; that is structurally present but NOT the demonstrated variable — sweeping the
|
|
396
|
+
* dwell from 0 to 480ms at a fixed distance changes no verdict, and removing the dwell entirely
|
|
397
|
+
* leaves the floor green (round-8 review MINOR). Distance is what moves it;
|
|
398
|
+
* - it cannot reach the keyframes lane at all — `DriverCommand`'s retarget targets are numbers, so
|
|
399
|
+
* `targetIsNumeric` is constantly true here. The floor's target axis is structurally
|
|
400
|
+
* inexpressible at this seam, and its axis is the LIVE STATE instead.
|
|
401
|
+
*
|
|
402
|
+
* Taken from BELOW validation for the same reason as `referenceFoldRefusal`: `command()` validates
|
|
403
|
+
* first, so reading its throw would make the driver echo the boundary and the floor could only ever
|
|
404
|
+
* catch over-acceptance.
|
|
405
|
+
*
|
|
406
|
+
* A fold that cannot even START is reported as refused — "would this backend run it at a retarget"
|
|
407
|
+
* is answered `no` either way, and conflating them here would make the phase axis lie about which
|
|
408
|
+
* seam refused.
|
|
409
|
+
*
|
|
410
|
+
* Test seam for this package's own parity floor — NOT part of any published entry.
|
|
411
|
+
*/
|
|
412
|
+
function referenceRetargetFoldRefusal(transition, startTo, from, retargetTo, dwellMs) {
|
|
413
|
+
let generator;
|
|
414
|
+
try {
|
|
415
|
+
generator = startGenerator(transition, startTo, from, 0);
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
if (error instanceof component_1.InvalidTransitionError && error.key === 'repeat')
|
|
419
|
+
return error;
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
// Reach a genuinely live state the way the driver does, so the retarget carries a real velocity.
|
|
423
|
+
const live = { generator, elapsed: 0, value: from, done: false };
|
|
424
|
+
(0, step_1.stepProp)(live, dwellMs);
|
|
425
|
+
try {
|
|
426
|
+
retargetGenerator(transition, live, retargetTo);
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
if (error instanceof component_1.InvalidTransitionError && error.key === 'repeat')
|
|
431
|
+
return error;
|
|
432
|
+
throw error;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function createReferenceDriver() {
|
|
436
|
+
// Indexed by handle (a plain number, worklet-friendly). register() appends; the index is the handle.
|
|
437
|
+
const elements = [];
|
|
438
|
+
function elementAt(handle) {
|
|
439
|
+
const element = elements[handle];
|
|
440
|
+
if (element === undefined) {
|
|
441
|
+
throw new Error(`unknown element handle ${String(handle)}: it was never registered on this driver.`);
|
|
442
|
+
}
|
|
443
|
+
return element;
|
|
444
|
+
}
|
|
445
|
+
const backend = {
|
|
446
|
+
register(initial) {
|
|
447
|
+
const handle = elements.length;
|
|
448
|
+
elements.push({
|
|
449
|
+
active: false,
|
|
450
|
+
heldCount: 0,
|
|
451
|
+
committed: { ...initial },
|
|
452
|
+
heldVelocity: {},
|
|
453
|
+
props: new Map(),
|
|
454
|
+
contending: {},
|
|
455
|
+
path: null,
|
|
456
|
+
});
|
|
457
|
+
return handle;
|
|
458
|
+
},
|
|
459
|
+
command(handle, command) {
|
|
460
|
+
const element = elementAt(handle);
|
|
461
|
+
switch (command.kind) {
|
|
462
|
+
case 'start': {
|
|
463
|
+
// Only a gesture RELEASE (`releasesGesture`) or a `stop` ends a hold. A declarative start on
|
|
464
|
+
// a gesture-held prop CONTENDS instead of being skipped (REQ-DRIVER-026, Motion's shared-
|
|
465
|
+
// value model): it seeds a generator that drifts the live value while the finger still owns
|
|
466
|
+
// the prop, so a mid-drag `animate` change moves the element and the release reads the
|
|
467
|
+
// drifted origin (the snap-selection parity fix). The finger's release velocity is preserved
|
|
468
|
+
// (liveFor held-velocity precedence, REQ-DRIVER-025); the hold clears only at release/stop.
|
|
469
|
+
const releasesGesture = command.releasesGesture;
|
|
470
|
+
// PHASE 1 — build every prop's generator WITHOUT mutating element state. A construction that
|
|
471
|
+
// throws (an explicit spring on a >2-keyframe array, R8-F1) aborts the WHOLE command here, so
|
|
472
|
+
// a rejected multi-prop start applies NOTHING (fail-closed atomicity, review major 19).
|
|
473
|
+
const plans = [];
|
|
474
|
+
for (const key of Object.keys(command.targets)) {
|
|
475
|
+
const target = command.targets[key]; // key came from Object.keys
|
|
476
|
+
// A gesture-RELEASE start takes over the prop (its hold clears in phase 2), so it is treated
|
|
477
|
+
// as NOT still-held and uses the command's nominal `from`. A start CONTENDING on a prop the
|
|
478
|
+
// finger still holds drifts from the CURRENT live value (never `from`) so committed does not
|
|
479
|
+
// jump off the finger. An ordinary non-held start uses `from`.
|
|
480
|
+
const stillHeld = !releasesGesture && element.heldVelocity[key] !== undefined;
|
|
481
|
+
const from = stillHeld ? element.committed[key] : target.from;
|
|
482
|
+
// `target` is already the complete immutable REQ-DRIVER-030 snapshot. No caller-owned
|
|
483
|
+
// PropTarget or fallback semantics reach this backend.
|
|
484
|
+
const to = target.to;
|
|
485
|
+
const transition = target.transition;
|
|
486
|
+
// A still-held (contending) start drifts from the finger value: seed the first keyframe
|
|
487
|
+
// from-current so it never rewinds to keyframes[0] (major 25). A non-held start keeps the
|
|
488
|
+
// array's own origin (a plain keyframe start plays [k0 … kN] verbatim).
|
|
489
|
+
const generator = startGenerator(transition, stillHeld ? anchorContentionToLive(to) : to, from, target.velocity);
|
|
490
|
+
// Seed committed/value from the generator's TICK-0, not the raw `from`: a keyframe array's
|
|
491
|
+
// origin is keyframes[0] (or the null-first seed), so committed() matches liveFor()'s
|
|
492
|
+
// zero-sample and never shows a one-frame `from` jump (review major dfeaa4bf4bcf). A scalar
|
|
493
|
+
// generator samples `from` at t=0 (no-op). A still-held start keeps the finger-authoritative
|
|
494
|
+
// committed. sample(0) is a pure read — no mutation, so phase 1 stays side-effect-free.
|
|
495
|
+
const seededValue = stillHeld ? from : generator.sample(0).value;
|
|
496
|
+
plans.push({ key, stillHeld, seededValue, generator, to, transition });
|
|
497
|
+
}
|
|
498
|
+
// PHASE 2 — commit every plan. No throw path here, so element state mutates atomically.
|
|
499
|
+
for (const plan of plans) {
|
|
500
|
+
if (releasesGesture)
|
|
501
|
+
releaseHold(element, plan.key);
|
|
502
|
+
element.props.set(plan.key, {
|
|
503
|
+
generator: plan.generator,
|
|
504
|
+
elapsed: 0,
|
|
505
|
+
value: plan.seededValue,
|
|
506
|
+
done: false,
|
|
507
|
+
});
|
|
508
|
+
element.committed[plan.key] = plan.seededValue;
|
|
509
|
+
// Track the contention target so a later finger write re-anchors this generator (major 29).
|
|
510
|
+
// `plan.to` is ALREADY the phase-1 snapshot the generator was built from (captured once,
|
|
511
|
+
// review major 20 + 21), so this stores the SAME frozen array — no second read, no skew; a
|
|
512
|
+
// released/non-held start owns the prop outright, so clear any prior contention.
|
|
513
|
+
if (plan.stillHeld)
|
|
514
|
+
element.contending[plan.key] = {
|
|
515
|
+
to: plan.to,
|
|
516
|
+
transition: plan.transition,
|
|
517
|
+
};
|
|
518
|
+
else
|
|
519
|
+
delete element.contending[plan.key];
|
|
520
|
+
}
|
|
521
|
+
if (command.path !== undefined) {
|
|
522
|
+
const geometry = command.path;
|
|
523
|
+
const generator = startGenerator(geometry.transition, 1000, 0, 0);
|
|
524
|
+
const seeded = generator.sample(0).value;
|
|
525
|
+
element.path = {
|
|
526
|
+
progress: { generator, elapsed: 0, value: seeded, done: false },
|
|
527
|
+
geometry,
|
|
528
|
+
};
|
|
529
|
+
element.props.delete('x');
|
|
530
|
+
element.props.delete('y');
|
|
531
|
+
element.props.delete('pathRotation');
|
|
532
|
+
const sample = (0, motion_arc_1.applyPathProgress)(seeded, geometry, false);
|
|
533
|
+
if ('x' in element.committed)
|
|
534
|
+
element.committed.x = sample.x;
|
|
535
|
+
if ('y' in element.committed)
|
|
536
|
+
element.committed.y = sample.y;
|
|
537
|
+
if (geometry.rotationScale && 'pathRotation' in element.committed)
|
|
538
|
+
element.committed.pathRotation = sample.pathRotation;
|
|
539
|
+
}
|
|
540
|
+
else if (element.path !== null) {
|
|
541
|
+
if (element.path.geometry.rotationScale && 'pathRotation' in element.committed)
|
|
542
|
+
element.committed.pathRotation = 0;
|
|
543
|
+
element.path = null;
|
|
544
|
+
}
|
|
545
|
+
element.active = element.props.size > 0 || element.heldCount > 0 || element.path !== null;
|
|
546
|
+
break;
|
|
547
|
+
}
|
|
548
|
+
case 'retarget': {
|
|
549
|
+
// BUILD every key first, COMMIT only once all of them succeeded — the same atomicity law
|
|
550
|
+
// `start` already carries (review major 36). Building can REFUSE (the fold re-measures from
|
|
551
|
+
// the live value, so a `repeat` executable at start can be refused here), and a per-key
|
|
552
|
+
// commit left the earlier keys already retargeted when a later one threw. A refused command
|
|
553
|
+
// must mutate nothing; the controller's severity lane depends on it, because it reports the
|
|
554
|
+
// refusal and lets the remaining keys proceed.
|
|
555
|
+
const staged = [];
|
|
556
|
+
for (const key of Object.keys(command.targets)) {
|
|
557
|
+
const to = command.targets[key]; // key came from Object.keys
|
|
558
|
+
const transition = command.targetTransitions?.[key] ?? command.transition;
|
|
559
|
+
// A retarget is NEVER the gesture release (the release is a seeded `start`). A retarget on
|
|
560
|
+
// a gesture-HELD prop CONTENDS (REQ-DRIVER-026): it seeds a fresh generator from the
|
|
561
|
+
// finger-authoritative COMMITTED value (not the possibly-stale generator `live.value` — a
|
|
562
|
+
// finger write may have advanced committed past it, review r10 major 29) toward the new
|
|
563
|
+
// target, and records the contention so a later write re-anchors it. A non-held prop
|
|
564
|
+
// retargets normally with velocity continuity.
|
|
565
|
+
const held = element.heldVelocity[key] !== undefined;
|
|
566
|
+
let from;
|
|
567
|
+
let generator;
|
|
568
|
+
if (held) {
|
|
569
|
+
from = element.committed[key]; // held ⇒ written ⇒ committed exists
|
|
570
|
+
generator = startGenerator(transition, to, from, 0);
|
|
571
|
+
staged.push({ key, from, generator, contendTo: to });
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
// Retarget carries no base — it derives `from` from the in-flight value (continuity), or
|
|
576
|
+
// for a registered-but-idle prop, its last committed value. A key that is neither
|
|
577
|
+
// in-flight nor committed is a malformed retarget: fail loud, never silently seed 0.
|
|
578
|
+
const live = element.props.get(key);
|
|
579
|
+
if (live !== undefined) {
|
|
580
|
+
from = live.value;
|
|
581
|
+
generator = retargetGenerator(transition, live, to);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
const base = element.committed[key];
|
|
585
|
+
if (base === undefined) {
|
|
586
|
+
throw new Error(`cannot retarget '${key}': it was never registered or started on this element.`);
|
|
587
|
+
}
|
|
588
|
+
from = base;
|
|
589
|
+
generator = startGenerator(transition, to, from, 0);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
staged.push({ key, from, generator });
|
|
593
|
+
}
|
|
594
|
+
// Past this line nothing can refuse, so the commit is all-or-nothing.
|
|
595
|
+
if (element.path !== null &&
|
|
596
|
+
staged.some(({ key }) => key === 'x' || key === 'y' || key === 'pathRotation')) {
|
|
597
|
+
if (element.path.geometry.rotationScale && 'pathRotation' in element.committed)
|
|
598
|
+
element.committed.pathRotation = 0;
|
|
599
|
+
element.path = null;
|
|
600
|
+
}
|
|
601
|
+
for (const { key, from, generator, contendTo } of staged) {
|
|
602
|
+
if (contendTo === undefined)
|
|
603
|
+
delete element.contending[key];
|
|
604
|
+
else
|
|
605
|
+
element.contending[key] = {
|
|
606
|
+
to: contendTo,
|
|
607
|
+
transition: command.targetTransitions?.[key] ?? command.transition,
|
|
608
|
+
};
|
|
609
|
+
element.props.set(key, { generator, elapsed: 0, value: from, done: false });
|
|
610
|
+
element.committed[key] = from;
|
|
611
|
+
}
|
|
612
|
+
// Recompute from what remains in flight: a held retarget seeds a contending generator
|
|
613
|
+
// (props.size grows) and a held element is active regardless (heldCount > 0).
|
|
614
|
+
element.active = element.props.size > 0 || element.heldCount > 0 || element.path !== null;
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
case 'stop': {
|
|
618
|
+
// Halt every animation AND release every gesture hold (stop = halt everything); the
|
|
619
|
+
// committed values are held as-is (REQ-DRIVER-013). Pin onStop zeroes pathRotation.
|
|
620
|
+
element.props.clear();
|
|
621
|
+
for (const key of Object.keys(element.heldVelocity))
|
|
622
|
+
delete element.heldVelocity[key];
|
|
623
|
+
for (const key of Object.keys(element.contending))
|
|
624
|
+
delete element.contending[key];
|
|
625
|
+
if (element.path !== null) {
|
|
626
|
+
if (element.path.geometry.rotationScale && 'pathRotation' in element.committed)
|
|
627
|
+
element.committed.pathRotation = 0;
|
|
628
|
+
element.path = null;
|
|
629
|
+
}
|
|
630
|
+
element.heldCount = 0;
|
|
631
|
+
element.active = false;
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
step(elapsedMs) {
|
|
637
|
+
for (const element of elements) {
|
|
638
|
+
if (!element.active)
|
|
639
|
+
continue;
|
|
640
|
+
let anyActive = false;
|
|
641
|
+
for (const [key, prop] of element.props) {
|
|
642
|
+
(0, step_1.stepProp)(prop, elapsedMs);
|
|
643
|
+
element.committed[key] = prop.value;
|
|
644
|
+
if (!prop.done)
|
|
645
|
+
anyActive = true;
|
|
646
|
+
}
|
|
647
|
+
if (element.path !== null) {
|
|
648
|
+
const path = element.path;
|
|
649
|
+
(0, step_1.stepProp)(path.progress, elapsedMs);
|
|
650
|
+
const sample = (0, motion_arc_1.applyPathProgress)(path.progress.value, path.geometry, path.progress.done);
|
|
651
|
+
if ('x' in element.committed)
|
|
652
|
+
element.committed.x = sample.x;
|
|
653
|
+
if ('y' in element.committed)
|
|
654
|
+
element.committed.y = sample.y;
|
|
655
|
+
if (path.geometry.rotationScale && 'pathRotation' in element.committed)
|
|
656
|
+
element.committed.pathRotation = sample.pathRotation;
|
|
657
|
+
if (path.progress.done)
|
|
658
|
+
element.path = null;
|
|
659
|
+
else
|
|
660
|
+
anyActive = true;
|
|
661
|
+
}
|
|
662
|
+
// Quiesce once every animation settles (REQ-DRIVER-020) — UNLESS a gesture still holds a
|
|
663
|
+
// prop (a finger is down, no animation but unsettled, G-INV-7). heldCount is O(1), so this
|
|
664
|
+
// stays allocation-free. A held element stays active until the matching release clears it.
|
|
665
|
+
if (!anyActive && element.heldCount === 0)
|
|
666
|
+
element.active = false;
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
committed(handle) {
|
|
670
|
+
return { ...elementAt(handle).committed };
|
|
671
|
+
},
|
|
672
|
+
setActive(handle, active) {
|
|
673
|
+
elementAt(handle).active = active;
|
|
674
|
+
},
|
|
675
|
+
isActive(handle) {
|
|
676
|
+
return elementAt(handle).active;
|
|
677
|
+
},
|
|
678
|
+
// The gesture write lane (REQ-DRIVER-024): commit event-driven values and interrupt any
|
|
679
|
+
// in-flight animation on the written props through ONE entry point — committed state and
|
|
680
|
+
// animation state can never skew. Never emits a settle edge for a prop that was not
|
|
681
|
+
// animating (the active flag recomputes from what actually remains in flight).
|
|
682
|
+
write(handle, values, velocities) {
|
|
683
|
+
const element = elementAt(handle);
|
|
684
|
+
for (const key of Object.keys(values)) {
|
|
685
|
+
if (!(key in element.committed)) {
|
|
686
|
+
throw new Error(`cannot write '${key}': it was never registered on this element.`);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// Validate ALL keys before mutating ANY (fail-closed: a malformed write never half-applies).
|
|
690
|
+
for (const key of Object.keys(values)) {
|
|
691
|
+
const finger = values[key];
|
|
692
|
+
if (element.heldVelocity[key] === undefined)
|
|
693
|
+
element.heldCount++; // count a NEW hold once
|
|
694
|
+
element.committed[key] = finger;
|
|
695
|
+
// Refresh the per-prop held platform velocity so liveFor reports it while held (G-INV-3 C1
|
|
696
|
+
// seam, held-velocity precedence over any contending generator); omitted ⇒ 0.
|
|
697
|
+
element.heldVelocity[key] = velocities?.[key] ?? 0;
|
|
698
|
+
// Reconcile the prop's generator with the finger write (REQ-DRIVER-026). A LIVE declarative
|
|
699
|
+
// contention is RE-ANCHORED to the freshly-committed finger value so it drifts FROM here —
|
|
700
|
+
// never a backward jump to the generator's stale trajectory (review r10 major 29, G-INV-2).
|
|
701
|
+
// Otherwise the finger owns the value outright: a plain grab interrupts the pre-existing
|
|
702
|
+
// animation (REQ-GESTURE-012), and a SETTLED contention is finished, so its generator is
|
|
703
|
+
// dropped (else `step` would keep forcing its value and the finger could never move it).
|
|
704
|
+
const contention = element.contending[key];
|
|
705
|
+
const prop = element.props.get(key);
|
|
706
|
+
if (contention !== undefined && prop !== undefined && !prop.done) {
|
|
707
|
+
element.props.set(key, {
|
|
708
|
+
// Re-anchor FROM the finger: seed a keyframe array's first element from-current so the
|
|
709
|
+
// drift continues from `finger`, never rewinding to keyframes[0] (major 25).
|
|
710
|
+
generator: startGenerator(contention.transition, anchorContentionToLive(contention.to), finger, 0),
|
|
711
|
+
elapsed: 0,
|
|
712
|
+
value: finger,
|
|
713
|
+
done: false,
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
if (prop !== undefined)
|
|
718
|
+
element.props.delete(key);
|
|
719
|
+
delete element.contending[key];
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
// A gesture write holds the element unsettled (G-INV-7): a finger is down driving it, so it
|
|
723
|
+
// stays active until the matching release/stop clears the hold — never a spurious settle edge
|
|
724
|
+
// mid-drag (the reviewer-reproduced re-grab defect), even after a contending animation settles.
|
|
725
|
+
element.active = true;
|
|
726
|
+
},
|
|
727
|
+
// The grab live-read (REQ-DRIVER-025). An in-flight prop re-samples its generator at the
|
|
728
|
+
// current elapsed — pure by elapsed time (REQ-CORE-001), scalars copied out immediately (the
|
|
729
|
+
// sample record is generator-owned and reused). Settled/never-animated ⇒ velocity 0.
|
|
730
|
+
liveFor(handle, key) {
|
|
731
|
+
const element = elementAt(handle);
|
|
732
|
+
// HELD-VELOCITY PRECEDENCE (REQ-DRIVER-025): a held (finger-down) prop reports the platform
|
|
733
|
+
// finger velocity its write carried EVEN when a contending declarative generator is in flight
|
|
734
|
+
// (REQ-DRIVER-026) — the release seed is the finger's number, never the generator's. The value
|
|
735
|
+
// is the live committed number (the finger position, or the contending animation's drift). This
|
|
736
|
+
// read comes BEFORE the generator branch so contention can't leak the generator velocity into
|
|
737
|
+
// the release seam (the two-sided G-INV-3 C1 seam; per-prop since review r7 major 23).
|
|
738
|
+
const heldV = element.heldVelocity[key];
|
|
739
|
+
if (heldV !== undefined) {
|
|
740
|
+
const base = element.committed[key];
|
|
741
|
+
if (base === undefined) {
|
|
742
|
+
throw new Error(`cannot read '${key}': it was never registered on this element.`);
|
|
743
|
+
}
|
|
744
|
+
return { value: base, velocity: heldV };
|
|
745
|
+
}
|
|
746
|
+
const live = element.props.get(key);
|
|
747
|
+
if (live !== undefined && !live.done) {
|
|
748
|
+
const sample = live.generator.sample(live.elapsed);
|
|
749
|
+
return { value: sample.value, velocity: sample.velocity };
|
|
750
|
+
}
|
|
751
|
+
const base = element.committed[key];
|
|
752
|
+
if (base === undefined) {
|
|
753
|
+
throw new Error(`cannot read '${key}': it was never registered on this element.`);
|
|
754
|
+
}
|
|
755
|
+
// A settled or never-animated non-held prop has velocity 0 (REQ-DRIVER-025).
|
|
756
|
+
return { value: base, velocity: 0 };
|
|
757
|
+
},
|
|
758
|
+
};
|
|
759
|
+
return (0, prepare_1.adaptPreparedDriver)(backend, (handle) => {
|
|
760
|
+
elementAt(handle);
|
|
761
|
+
});
|
|
762
|
+
}
|