@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,215 @@
|
|
|
1
|
+
'worklet';
|
|
2
|
+
// @frame-path — executes inside the UI-runtime frame step; allocation-gated (REQ-DRIVER-021).
|
|
3
|
+
// Bounded transform-template support (T17 packet, specs/T17-TRANSFORM-TEMPLATE-BUILD-PACKET.md):
|
|
4
|
+
// the canonical generated-string builder (pin `motion-dom buildTransform` format and value
|
|
5
|
+
// typing) and the bounded parser that turns a template's RETURN string into the RN transform
|
|
6
|
+
// array. Grammar is exactly the canonical builder's function set; anything off-grammar fails
|
|
7
|
+
// loud naming the offending token — never a silent partial parse (the R13 law). Host-agnostic
|
|
8
|
+
// (REQ-CORE-003): no host imports.
|
|
9
|
+
//
|
|
10
|
+
// alloc-ok: frame — template composition is string-valued by pin design (motion-dom
|
|
11
|
+
// buildTransform allocates the composed string per frame); the parser allocates only the small
|
|
12
|
+
// output entry list, proportional to the entry count.
|
|
13
|
+
// Canonical key order (pin `transformPropOrder` restricted to the shipped transform keys — the
|
|
14
|
+
// same list composeTransform commits, so template and non-template composition agree).
|
|
15
|
+
const TEMPLATE_KEY_ORDER = [
|
|
16
|
+
'perspective',
|
|
17
|
+
'x',
|
|
18
|
+
'y',
|
|
19
|
+
'scale',
|
|
20
|
+
'scaleX',
|
|
21
|
+
'scaleY',
|
|
22
|
+
'rotate',
|
|
23
|
+
'rotateX',
|
|
24
|
+
'rotateY',
|
|
25
|
+
'skewX',
|
|
26
|
+
'skewY',
|
|
27
|
+
];
|
|
28
|
+
// Function name in the generated string per key (pin: translateAlias x→translateX, y→translateY).
|
|
29
|
+
const KEY_FUNCTION = {
|
|
30
|
+
perspective: 'perspective',
|
|
31
|
+
x: 'translateX',
|
|
32
|
+
y: 'translateY',
|
|
33
|
+
scale: 'scale',
|
|
34
|
+
scaleX: 'scaleX',
|
|
35
|
+
scaleY: 'scaleY',
|
|
36
|
+
rotate: 'rotate',
|
|
37
|
+
rotateX: 'rotateX',
|
|
38
|
+
rotateY: 'rotateY',
|
|
39
|
+
skewX: 'skewX',
|
|
40
|
+
skewY: 'skewY',
|
|
41
|
+
};
|
|
42
|
+
// Plain-object lookups, never Sets: worklet captures stay in the most conservative shareable
|
|
43
|
+
// shape — records of primitives (the composeTransform.ts law) — so serialization can never be
|
|
44
|
+
// the failure mode on the UI runtime.
|
|
45
|
+
const DEGREE_KEYS = Object.freeze({
|
|
46
|
+
rotate: 1,
|
|
47
|
+
rotateX: 1,
|
|
48
|
+
rotateY: 1,
|
|
49
|
+
skewX: 1,
|
|
50
|
+
skewY: 1,
|
|
51
|
+
});
|
|
52
|
+
const LENGTH_KEYS = Object.freeze({ perspective: 1, x: 1, y: 1 });
|
|
53
|
+
// Pin build-transform's default law: `value === (key.startsWith("scale") ? 1 : 0)`.
|
|
54
|
+
const SCALE_KEYS = Object.freeze({ scale: 1, scaleX: 1, scaleY: 1 });
|
|
55
|
+
// The values-map key name per canonical key (pin latestValues naming: transformPerspective).
|
|
56
|
+
const VALUES_MAP_KEY = {
|
|
57
|
+
perspective: 'transformPerspective',
|
|
58
|
+
x: 'x',
|
|
59
|
+
y: 'y',
|
|
60
|
+
scale: 'scale',
|
|
61
|
+
scaleX: 'scaleX',
|
|
62
|
+
scaleY: 'scaleY',
|
|
63
|
+
rotate: 'rotate',
|
|
64
|
+
rotateX: 'rotateX',
|
|
65
|
+
rotateY: 'rotateY',
|
|
66
|
+
skewX: 'skewX',
|
|
67
|
+
skewY: 'skewY',
|
|
68
|
+
};
|
|
69
|
+
function typedValueFor(key, value) {
|
|
70
|
+
const unit = DEGREE_KEYS[key] === 1 ? 'deg' : LENGTH_KEYS[key] === 1 ? 'px' : '';
|
|
71
|
+
return `${value}${unit}`;
|
|
72
|
+
}
|
|
73
|
+
function assertFiniteTemplateValue(key, value) {
|
|
74
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
75
|
+
throw new Error(`transformTemplate values: key '${key}' must be a finite number, got ${String(value)} (T17).`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The canonical generated string (pin `buildTransform`): `${fn}(${valueWithUnit})` joined by
|
|
80
|
+
* spaces in canonical order. A non-finite value fails loud naming the key.
|
|
81
|
+
*/
|
|
82
|
+
export function buildTransformString(values) {
|
|
83
|
+
let out = '';
|
|
84
|
+
for (const key of TEMPLATE_KEY_ORDER) {
|
|
85
|
+
const value = values[key];
|
|
86
|
+
if (value === undefined)
|
|
87
|
+
continue;
|
|
88
|
+
assertFiniteTemplateValue(key, value);
|
|
89
|
+
out += `${out === '' ? '' : ' '}${KEY_FUNCTION[key]}(${typedValueFor(key, value)})`;
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The pin's template call args (motion-dom build-transform, verbatim loop): the values map
|
|
95
|
+
* carries every PRESENT key typed (defaults INCLUDED — `!valueIsDefault || transformTemplate`);
|
|
96
|
+
* the generated string carries only NON-DEFAULT values in canonical order, so an all-default
|
|
97
|
+
* transform hands the template '' (pin `transformIsDefault ? "" : transformString`).
|
|
98
|
+
*/
|
|
99
|
+
export function buildTransformTemplateArgs(values) {
|
|
100
|
+
const typed = {};
|
|
101
|
+
let generated = '';
|
|
102
|
+
for (const key of TEMPLATE_KEY_ORDER) {
|
|
103
|
+
const value = values[key];
|
|
104
|
+
if (value === undefined)
|
|
105
|
+
continue;
|
|
106
|
+
assertFiniteTemplateValue(key, value);
|
|
107
|
+
const typedValue = typedValueFor(key, value);
|
|
108
|
+
typed[VALUES_MAP_KEY[key]] = typedValue;
|
|
109
|
+
const isDefault = SCALE_KEYS[key] === 1 ? value === 1 : value === 0;
|
|
110
|
+
if (!isDefault) {
|
|
111
|
+
generated += `${generated === '' ? '' : ' '}${KEY_FUNCTION[key]}(${typedValue})`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { values: typed, generated };
|
|
115
|
+
}
|
|
116
|
+
// Per-function unit law: translate* take px|%; scale* are unitless; rotate*/skew* take
|
|
117
|
+
// deg|unitless; perspective takes px|unitless. Anything else is a named refusal.
|
|
118
|
+
const FUNCTION_UNITS = {
|
|
119
|
+
perspective: ['px', ''],
|
|
120
|
+
translate: ['px', '%'],
|
|
121
|
+
translateX: ['px', '%'],
|
|
122
|
+
translateY: ['px', '%'],
|
|
123
|
+
scale: [''],
|
|
124
|
+
scaleX: [''],
|
|
125
|
+
scaleY: [''],
|
|
126
|
+
rotate: ['deg', ''],
|
|
127
|
+
rotateX: ['deg', ''],
|
|
128
|
+
rotateY: ['deg', ''],
|
|
129
|
+
skewX: ['deg', ''],
|
|
130
|
+
skewY: ['deg', ''],
|
|
131
|
+
};
|
|
132
|
+
const ENTRY_NAME = {
|
|
133
|
+
perspective: 'perspective',
|
|
134
|
+
translateX: 'translateX',
|
|
135
|
+
translateY: 'translateY',
|
|
136
|
+
scale: 'scale',
|
|
137
|
+
scaleX: 'scaleX',
|
|
138
|
+
scaleY: 'scaleY',
|
|
139
|
+
rotate: 'rotate',
|
|
140
|
+
rotateX: 'rotateX',
|
|
141
|
+
rotateY: 'rotateY',
|
|
142
|
+
skewX: 'skewX',
|
|
143
|
+
skewY: 'skewY',
|
|
144
|
+
};
|
|
145
|
+
const VALUE_RE = /^(-?(?:\d+(?:\.\d+)?|\.\d+))(px|%|deg)?$/;
|
|
146
|
+
function fail(templateOutput, reason) {
|
|
147
|
+
throw new Error(`transformTemplate output '${templateOutput}': ${reason} (T17 bounded grammar).`);
|
|
148
|
+
}
|
|
149
|
+
function parseValue(templateOutput, fn, raw) {
|
|
150
|
+
const m = VALUE_RE.exec(raw.trim());
|
|
151
|
+
if (m === null) {
|
|
152
|
+
fail(templateOutput, `unparseable value '${raw}' for ${fn}`);
|
|
153
|
+
}
|
|
154
|
+
const [, numeral, rawUnit] = m;
|
|
155
|
+
const unit = (rawUnit ?? '');
|
|
156
|
+
const allowed = FUNCTION_UNITS[fn];
|
|
157
|
+
if (!allowed.includes(unit)) {
|
|
158
|
+
fail(templateOutput, `unit '${unit || '(none)'}' is not valid for ${fn}`);
|
|
159
|
+
}
|
|
160
|
+
// Percent translate entries ride RN's percent-string form. Angle entries commit as RN degree
|
|
161
|
+
// STRINGS — the shipped composeTransform output shape (RN types the rotate/skew family
|
|
162
|
+
// string-typed; a bare number is not a valid entry). A unitless angle is degrees by the pin's
|
|
163
|
+
// getValueAsType law. Everything else commits numeric.
|
|
164
|
+
if (unit === '%')
|
|
165
|
+
return `${numeral}%`;
|
|
166
|
+
if (allowed.includes('deg'))
|
|
167
|
+
return `${numeral}deg`;
|
|
168
|
+
return Number(numeral);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parse a template's RETURN string into the ordered RN transform array. The grammar is the
|
|
172
|
+
* canonical builder's function set with px/%/deg/unitless values; `translate` takes 1-2 args
|
|
173
|
+
* (comma or space separated). Anything else throws naming the offending token.
|
|
174
|
+
*/
|
|
175
|
+
export function parseTransformTemplateOutput(templateOutput) {
|
|
176
|
+
const out = [];
|
|
177
|
+
let rest = templateOutput.trim();
|
|
178
|
+
while (rest.length > 0) {
|
|
179
|
+
const open = rest.indexOf('(');
|
|
180
|
+
const fn = open === -1 ? rest.trim() : rest.slice(0, open).trim();
|
|
181
|
+
if (open === -1 || fn === '' || /\s/.test(fn)) {
|
|
182
|
+
fail(templateOutput, `malformed token '${fn}' — expected fn(args)`);
|
|
183
|
+
}
|
|
184
|
+
if (!(fn in FUNCTION_UNITS) && fn !== 'translate') {
|
|
185
|
+
fail(templateOutput, `transform function '${fn}' is outside the bounded grammar`);
|
|
186
|
+
}
|
|
187
|
+
const close = rest.indexOf(')', open);
|
|
188
|
+
if (close === -1) {
|
|
189
|
+
fail(templateOutput, `unbalanced parens near '${fn}('`);
|
|
190
|
+
}
|
|
191
|
+
const argsRaw = rest.slice(open + 1, close);
|
|
192
|
+
const args = argsRaw.includes(',')
|
|
193
|
+
? argsRaw.split(',').map((a) => a.trim())
|
|
194
|
+
: argsRaw.trim() === ''
|
|
195
|
+
? []
|
|
196
|
+
: argsRaw.trim().split(/\s+/);
|
|
197
|
+
if (fn === 'translate') {
|
|
198
|
+
if (args.length === 0 || args.length > 2) {
|
|
199
|
+
fail(templateOutput, `translate takes 1 or 2 args, got ${args.length}`);
|
|
200
|
+
}
|
|
201
|
+
out.push({ translateX: parseValue(templateOutput, 'translate', args[0]) });
|
|
202
|
+
if (args.length === 2) {
|
|
203
|
+
out.push({ translateY: parseValue(templateOutput, 'translate', args[1]) });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
if (args.length !== 1) {
|
|
208
|
+
fail(templateOutput, `${fn} takes exactly 1 arg, got ${args.length}`);
|
|
209
|
+
}
|
|
210
|
+
out.push({ [ENTRY_NAME[fn]]: parseValue(templateOutput, fn, args[0]) });
|
|
211
|
+
}
|
|
212
|
+
rest = rest.slice(close + 1).trim();
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @frame-path — executes inside the UI-runtime frame step; allocation-gated (REQ-DRIVER-021).
|
|
3
|
+
// Transition-config resolution (SPEC-SPRING REQ-SPRING-004/005/006/007/012). Turns a user transition
|
|
4
|
+
// config into concrete spring physics + the flags the generator/settle layers need. Host-agnostic
|
|
5
|
+
// (REQ-CORE-003): imports nothing from motion/react. Numerics are pinned to motion@12.42.2 and proven
|
|
6
|
+
// by resolution parity in transition.test.ts.
|
|
7
|
+
//
|
|
8
|
+
// findSpring (REQ-SPRING-004) uses the DETERMINISTIC closed form, not motion's 12-iteration
|
|
9
|
+
// Newton-Raphson: for velocity-free duration springs the closed form is the exact analytic root of
|
|
10
|
+
// motion's envelope, so it reproduces motion's resolution (proven to ~5e-5 relative in the tests) with
|
|
11
|
+
// no iteration.
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.DRAG_INERTIA_DEFAULTS = void 0;
|
|
14
|
+
exports.resolveSpring = resolveSpring;
|
|
15
|
+
exports.resolveSpringGenerator = resolveSpringGenerator;
|
|
16
|
+
exports.retargetSpring = retargetSpring;
|
|
17
|
+
exports.springKeyframeCountRefusal = springKeyframeCountRefusal;
|
|
18
|
+
exports.getDefaultTransition = getDefaultTransition;
|
|
19
|
+
exports.dragInertiaBounce = dragInertiaBounce;
|
|
20
|
+
const spring_1 = require("./spring.cjs");
|
|
21
|
+
// Pinned defaults (REQ-SPRING-003 springDefaults).
|
|
22
|
+
const DEFAULT_PHYSICS = { stiffness: 100, damping: 10, mass: 1 };
|
|
23
|
+
const DEFAULT_DURATION_MS = 800;
|
|
24
|
+
const DEFAULT_BOUNCE = 0.3;
|
|
25
|
+
const SAFE_MIN = 0.001;
|
|
26
|
+
const clamp = (lo, hi, v) => Math.max(lo, Math.min(hi, v));
|
|
27
|
+
// REQ-SPRING-004 critical-root constant: the u solving e^(−u)·(u+1) = SAFE_MIN. Derived from SAFE_MIN
|
|
28
|
+
// by Newton (NOT hard-copied 9.2334…) so it stays consistent if SAFE_MIN changes.
|
|
29
|
+
const CRITICAL_ROOT = (() => {
|
|
30
|
+
let u = 9;
|
|
31
|
+
for (let i = 0; i < 40; i++)
|
|
32
|
+
u -= (Math.exp(-u) * (u + 1) - SAFE_MIN) / (-u * Math.exp(-u));
|
|
33
|
+
return u;
|
|
34
|
+
})();
|
|
35
|
+
// REQ-SPRING-004: duration+bounce → physics via the closed-form undamped frequency (velocity = 0).
|
|
36
|
+
// alloc-ok: lifecycle-edge — duration→physics resolution at command time.
|
|
37
|
+
function findSpring(durationMs, bounce, mass) {
|
|
38
|
+
const z = clamp(0.05, 1, 1 - bounce);
|
|
39
|
+
const tSec = clamp(0.01, 10, durationMs / 1000);
|
|
40
|
+
const omega = z < 1 ? Math.log(z / (SAFE_MIN * Math.sqrt(1 - z * z))) / (z * tSec) : CRITICAL_ROOT / tSec;
|
|
41
|
+
if (Number.isNaN(omega)) {
|
|
42
|
+
return { ...DEFAULT_PHYSICS, mass, durationMs: tSec * 1000 };
|
|
43
|
+
}
|
|
44
|
+
const stiffness = omega * omega * mass;
|
|
45
|
+
return { stiffness, damping: z * 2 * Math.sqrt(mass * stiffness), mass, durationMs: tSec * 1000 };
|
|
46
|
+
}
|
|
47
|
+
// REQ-SPRING-005: visualDuration+bounce → the DISTINCT path (no findSpring). bounce defaults to 0 here
|
|
48
|
+
// (intentional asymmetry with REQ-SPRING-004's 0.3). The 1.2 factor is load-bearing.
|
|
49
|
+
// alloc-ok: lifecycle-edge — visualDuration→physics resolution at command time.
|
|
50
|
+
function visualDurationSpring(visualDuration, bounce, mass) {
|
|
51
|
+
const root = (2 * Math.PI) / (visualDuration * 1.2);
|
|
52
|
+
const stiffness = root * root;
|
|
53
|
+
const damping = 2 * clamp(0.05, 1, 1 - (bounce ?? 0)) * Math.sqrt(stiffness);
|
|
54
|
+
return { stiffness, damping, mass };
|
|
55
|
+
}
|
|
56
|
+
const hasPhysicsKey = (c) => c.stiffness !== undefined || c.damping !== undefined || c.mass !== undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a spring transition config to concrete physics + carry/settle flags (REQ-SPRING-006
|
|
59
|
+
* precedence). Presence is tested on `!== undefined`.
|
|
60
|
+
*/
|
|
61
|
+
// alloc-ok: lifecycle-edge — config resolution at command time (REQ-SPRING-006 precedence).
|
|
62
|
+
function resolveSpring(config) {
|
|
63
|
+
const mass = config.mass ?? DEFAULT_PHYSICS.mass;
|
|
64
|
+
// Any physics key ⇒ physics used directly; the entire duration family is ignored; velocity carries.
|
|
65
|
+
if (hasPhysicsKey(config)) {
|
|
66
|
+
return {
|
|
67
|
+
physics: {
|
|
68
|
+
stiffness: config.stiffness ?? DEFAULT_PHYSICS.stiffness,
|
|
69
|
+
damping: config.damping ?? DEFAULT_PHYSICS.damping,
|
|
70
|
+
mass,
|
|
71
|
+
},
|
|
72
|
+
carryVelocity: true,
|
|
73
|
+
isResolvedFromDuration: false,
|
|
74
|
+
calculatedDuration: null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Duration family — velocity is ZEROED (REQ-SPRING-007). visualDuration wins over duration, and a
|
|
78
|
+
// visualDuration-only config still takes the vd path (REQ-SPRING-006, post-plan-030); it MUST NOT
|
|
79
|
+
// fall back to default physics.
|
|
80
|
+
if (config.visualDuration !== undefined) {
|
|
81
|
+
return {
|
|
82
|
+
physics: visualDurationSpring(config.visualDuration, config.bounce, mass),
|
|
83
|
+
carryVelocity: false,
|
|
84
|
+
isResolvedFromDuration: false, // vd does NOT set the duration flag (REQ-SPRING-011)
|
|
85
|
+
calculatedDuration: null,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (config.duration !== undefined || config.bounce !== undefined) {
|
|
89
|
+
const fs = findSpring(config.duration ?? DEFAULT_DURATION_MS, config.bounce ?? DEFAULT_BOUNCE, mass);
|
|
90
|
+
return {
|
|
91
|
+
physics: { stiffness: fs.stiffness, damping: fs.damping, mass: fs.mass },
|
|
92
|
+
carryVelocity: false,
|
|
93
|
+
isResolvedFromDuration: true,
|
|
94
|
+
calculatedDuration: fs.durationMs,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Bare `{type:'spring'}` / empty ⇒ REQ-SPRING-003 defaults (100/10/1); a physics spring (carries).
|
|
98
|
+
return {
|
|
99
|
+
physics: { ...DEFAULT_PHYSICS },
|
|
100
|
+
carryVelocity: true,
|
|
101
|
+
isResolvedFromDuration: false,
|
|
102
|
+
calculatedDuration: null,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Build a `GeneratorFactory` from a target + config, honoring velocity carry/zero (REQ-SPRING-007).
|
|
107
|
+
* Duration/visualDuration springs drop the seed's incoming velocity; physics springs keep it —
|
|
108
|
+
* unless the config carries an AUTHORED `velocity`, which replaces it (REQ-API-053, T21): the pin's
|
|
109
|
+
* animateMotionValue spreads the authored transition over the live-velocity default
|
|
110
|
+
* (motion-dom@12.42.2 motion-value.ts:45-50), so the authored number wins on every start.
|
|
111
|
+
*/
|
|
112
|
+
// alloc-ok: lifecycle-edge — factory construction at command time; sampling stays allocation-free.
|
|
113
|
+
function resolveSpringGenerator(target, config) {
|
|
114
|
+
const resolved = resolveSpring(config);
|
|
115
|
+
// findSpring (duration) springs settle at t ≥ calculatedDuration; physics/visualDuration settle by
|
|
116
|
+
// threshold (settleDuration null). (REQ-SPRING-011)
|
|
117
|
+
const factory = (0, spring_1.springGenerator)(target, resolved.physics, {
|
|
118
|
+
settleDuration: resolved.calculatedDuration,
|
|
119
|
+
...(config.restSpeed !== undefined ? { restSpeed: config.restSpeed } : {}),
|
|
120
|
+
...(config.restDelta !== undefined ? { restDelta: config.restDelta } : {}),
|
|
121
|
+
});
|
|
122
|
+
if (resolved.carryVelocity) {
|
|
123
|
+
const authoredVelocity = config.velocity;
|
|
124
|
+
if (authoredVelocity === undefined)
|
|
125
|
+
return factory;
|
|
126
|
+
// alloc-ok: lifecycle-edge — the authored-velocity reseed wrapper runs at generator construction.
|
|
127
|
+
return (seed) => factory({ from: seed.from, velocity: authoredVelocity });
|
|
128
|
+
}
|
|
129
|
+
// alloc-ok: lifecycle-edge — the zero-velocity reseed wrapper runs at generator construction.
|
|
130
|
+
return (seed) => factory({ from: seed.from, velocity: 0 });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Interrupt/retarget (REQ-SPRING-009): build a new generator for `newTarget` from the OUTGOING
|
|
134
|
+
* generator's analytic state at `atMs` — its exact value and analytic velocity (preferred over any
|
|
135
|
+
* finite-diff, which avoids systematic velocity loss at high frame rates). Whether that incoming
|
|
136
|
+
* velocity carries (physics), is replaced by an authored config `velocity` (REQ-API-053), or is
|
|
137
|
+
* zeroed (duration/visualDuration) is decided by
|
|
138
|
+
* `resolveSpringGenerator` (REQ-SPRING-007). The result's `value(0)` equals the outgoing `value(atMs)`
|
|
139
|
+
* exactly — no teleport, no velocity reset. The graph's own interruption seam does the equivalent via
|
|
140
|
+
* `motionValue.getVelocity()`; this is the explicit spring-layer helper for consumers driving
|
|
141
|
+
* generators directly (e.g. the Reanimated driver).
|
|
142
|
+
*/
|
|
143
|
+
// alloc-ok: lifecycle-edge — interruption/retarget construction; samples the outgoing generator
|
|
144
|
+
// once, then builds the successor.
|
|
145
|
+
function retargetSpring(outgoing, atMs, newTarget, config) {
|
|
146
|
+
const at = outgoing.sample(atMs);
|
|
147
|
+
return resolveSpringGenerator(newTarget, config)({ from: at.value, velocity: at.velocity });
|
|
148
|
+
}
|
|
149
|
+
// REQ-SPRING-012 getDefaultTransition selection table. transformProps mirrors motion's set.
|
|
150
|
+
const TRANSFORM_PROPS = new Set([
|
|
151
|
+
'transformPerspective',
|
|
152
|
+
'x',
|
|
153
|
+
'y',
|
|
154
|
+
'z',
|
|
155
|
+
'translateX',
|
|
156
|
+
'translateY',
|
|
157
|
+
'translateZ',
|
|
158
|
+
'scale',
|
|
159
|
+
'scaleX',
|
|
160
|
+
'scaleY',
|
|
161
|
+
'rotate',
|
|
162
|
+
'rotateX',
|
|
163
|
+
'rotateY',
|
|
164
|
+
'rotateZ',
|
|
165
|
+
'skew',
|
|
166
|
+
'skewX',
|
|
167
|
+
'skewY',
|
|
168
|
+
'pathRotation',
|
|
169
|
+
]);
|
|
170
|
+
// R8-F1: a spring interpolates EXACTLY two keyframes (origin → target); the pinned Motion throws
|
|
171
|
+
// `spring-two-frames` for any other count. The ONE predicate the reference driver's
|
|
172
|
+
// springKeyframeGenerator throws from AND the native controller PRE-VALIDATES with before issuing any
|
|
173
|
+
// driver command (so a rejected multi-command mount/update mutates nothing — atomicity, review major
|
|
174
|
+
// 36). The worklet driver mirrors the SAME message inline on its 'worklet' path. Returns the loud
|
|
175
|
+
// refusal for a non-two count, else null.
|
|
176
|
+
// alloc-ok: lifecycle-edge — a refusal built at command/pre-validation time, never per frame.
|
|
177
|
+
function springKeyframeCountRefusal(count) {
|
|
178
|
+
if (count === 2)
|
|
179
|
+
return null;
|
|
180
|
+
return new Error(`a spring transition cannot interpolate through ${count} keyframes — a spring animates exactly ` +
|
|
181
|
+
'two (origin → target). Keyframe index 2 (the successor) is unreachable; use a tween for a ' +
|
|
182
|
+
'multi-keyframe array (REQ-API-033, R8-F1).');
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Default transition per property when none is specified (REQ-SPRING-012), keyframe-count-aware to
|
|
186
|
+
* match the pinned `motion-dom` `getDefaultTransition(valueKey, { keyframes })`
|
|
187
|
+
* (default-transitions.ts): MORE than two keyframes → an 800ms keyframes transition (regardless of
|
|
188
|
+
* property); otherwise a transform prop gets an underdamped spring (scale: critically-damped 550,
|
|
189
|
+
* damping 30 for a non-zero target and 2√550 at exactly 0; other transforms: 500/25), and every
|
|
190
|
+
* other property gets the 300ms shallow-browser tween. A scalar animation is the two-keyframe case
|
|
191
|
+
* (`[from, target]`); the last keyframe drives the scale-at-zero branch (Motion reads `keyframes[1]`).
|
|
192
|
+
*/
|
|
193
|
+
// alloc-ok: lifecycle-edge — per-property default selection at command time.
|
|
194
|
+
function getDefaultTransition(valueKey, keyframes) {
|
|
195
|
+
if (keyframes.length > 2) {
|
|
196
|
+
return { type: 'keyframes', duration: 0.8 };
|
|
197
|
+
}
|
|
198
|
+
if (TRANSFORM_PROPS.has(valueKey)) {
|
|
199
|
+
if (valueKey.startsWith('scale')) {
|
|
200
|
+
const last = keyframes[keyframes.length - 1];
|
|
201
|
+
const target = typeof last === 'number' ? last : 0;
|
|
202
|
+
return {
|
|
203
|
+
type: 'spring',
|
|
204
|
+
stiffness: 550,
|
|
205
|
+
damping: target === 0 ? 2 * Math.sqrt(550) : 30,
|
|
206
|
+
restSpeed: 10,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return { type: 'spring', stiffness: 500, damping: 25, restSpeed: 10 };
|
|
210
|
+
}
|
|
211
|
+
return { type: 'keyframes', ease: [0.25, 0.1, 0.35, 1], duration: 0.3 };
|
|
212
|
+
}
|
|
213
|
+
// Pinned drag-layer physics (startAnimation spread: timeConstant 750, restDelta 1, restSpeed 10;
|
|
214
|
+
// motion-dom inertia `power` default 0.8 — single-sourced with PROJECTION_POWER's pin note).
|
|
215
|
+
exports.DRAG_INERTIA_DEFAULTS = {
|
|
216
|
+
power: 0.8,
|
|
217
|
+
timeConstant: 750,
|
|
218
|
+
restDelta: 1,
|
|
219
|
+
restSpeed: 10,
|
|
220
|
+
};
|
|
221
|
+
// The pin's elastic-conditional boundary-spring pairs (VisualElementDragControls: dragElastic
|
|
222
|
+
// truthy → 200/40, falsy → 1e6/1e7 "overdamp the boundary spring"). dragTransition overrides.
|
|
223
|
+
// Shared frozen constants (never a per-call literal — the frame-path allocation law, REQ-DRIVER-021).
|
|
224
|
+
const ELASTIC_BOUNDARY_BOUNCE = Object.freeze({ bounceStiffness: 200, bounceDamping: 40 });
|
|
225
|
+
const RIGID_BOUNDARY_BOUNCE = Object.freeze({
|
|
226
|
+
bounceStiffness: 1000000,
|
|
227
|
+
bounceDamping: 10000000,
|
|
228
|
+
});
|
|
229
|
+
function dragInertiaBounce(elastic) {
|
|
230
|
+
return elastic !== undefined && elastic > 0 ? ELASTIC_BOUNDARY_BOUNCE : RIGID_BOUNDARY_BOUNCE;
|
|
231
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { SpringPhysics } from "./spring.cjs";
|
|
2
|
+
import type { Generator, GeneratorFactory } from "./types.cjs";
|
|
3
|
+
import type { Transition } from "./component/types.cjs";
|
|
4
|
+
export interface SpringConfig {
|
|
5
|
+
stiffness?: number;
|
|
6
|
+
damping?: number;
|
|
7
|
+
mass?: number;
|
|
8
|
+
duration?: number;
|
|
9
|
+
bounce?: number;
|
|
10
|
+
visualDuration?: number;
|
|
11
|
+
velocity?: number;
|
|
12
|
+
restSpeed?: number;
|
|
13
|
+
restDelta?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedSpring {
|
|
16
|
+
physics: SpringPhysics;
|
|
17
|
+
carryVelocity: boolean;
|
|
18
|
+
isResolvedFromDuration: boolean;
|
|
19
|
+
calculatedDuration: number | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a spring transition config to concrete physics + carry/settle flags (REQ-SPRING-006
|
|
23
|
+
* precedence). Presence is tested on `!== undefined`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveSpring(config: SpringConfig): ResolvedSpring;
|
|
26
|
+
/**
|
|
27
|
+
* Build a `GeneratorFactory` from a target + config, honoring velocity carry/zero (REQ-SPRING-007).
|
|
28
|
+
* Duration/visualDuration springs drop the seed's incoming velocity; physics springs keep it —
|
|
29
|
+
* unless the config carries an AUTHORED `velocity`, which replaces it (REQ-API-053, T21): the pin's
|
|
30
|
+
* animateMotionValue spreads the authored transition over the live-velocity default
|
|
31
|
+
* (motion-dom@12.42.2 motion-value.ts:45-50), so the authored number wins on every start.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveSpringGenerator(target: number, config: SpringConfig): GeneratorFactory;
|
|
34
|
+
/**
|
|
35
|
+
* Interrupt/retarget (REQ-SPRING-009): build a new generator for `newTarget` from the OUTGOING
|
|
36
|
+
* generator's analytic state at `atMs` — its exact value and analytic velocity (preferred over any
|
|
37
|
+
* finite-diff, which avoids systematic velocity loss at high frame rates). Whether that incoming
|
|
38
|
+
* velocity carries (physics), is replaced by an authored config `velocity` (REQ-API-053), or is
|
|
39
|
+
* zeroed (duration/visualDuration) is decided by
|
|
40
|
+
* `resolveSpringGenerator` (REQ-SPRING-007). The result's `value(0)` equals the outgoing `value(atMs)`
|
|
41
|
+
* exactly — no teleport, no velocity reset. The graph's own interruption seam does the equivalent via
|
|
42
|
+
* `motionValue.getVelocity()`; this is the explicit spring-layer helper for consumers driving
|
|
43
|
+
* generators directly (e.g. the Reanimated driver).
|
|
44
|
+
*/
|
|
45
|
+
export declare function retargetSpring(outgoing: Generator, atMs: number, newTarget: number, config: SpringConfig): Generator;
|
|
46
|
+
export declare function springKeyframeCountRefusal(count: number): Error | null;
|
|
47
|
+
export type DefaultTransition = ({
|
|
48
|
+
type: 'spring';
|
|
49
|
+
stiffness: number;
|
|
50
|
+
damping: number;
|
|
51
|
+
restSpeed: number;
|
|
52
|
+
} & Pick<Transition, 'delay' | 'repeat' | 'repeatType' | 'repeatDelay'>) | ({
|
|
53
|
+
type: 'keyframes';
|
|
54
|
+
ease?: readonly [number, number, number, number];
|
|
55
|
+
duration: number;
|
|
56
|
+
} & Pick<Transition, 'delay' | 'repeat' | 'repeatType' | 'repeatDelay'>);
|
|
57
|
+
/**
|
|
58
|
+
* Default transition per property when none is specified (REQ-SPRING-012), keyframe-count-aware to
|
|
59
|
+
* match the pinned `motion-dom` `getDefaultTransition(valueKey, { keyframes })`
|
|
60
|
+
* (default-transitions.ts): MORE than two keyframes → an 800ms keyframes transition (regardless of
|
|
61
|
+
* property); otherwise a transform prop gets an underdamped spring (scale: critically-damped 550,
|
|
62
|
+
* damping 30 for a non-zero target and 2√550 at exactly 0; other transforms: 500/25), and every
|
|
63
|
+
* other property gets the 300ms shallow-browser tween. A scalar animation is the two-keyframe case
|
|
64
|
+
* (`[from, target]`); the last keyframe drives the scale-at-zero branch (Motion reads `keyframes[1]`).
|
|
65
|
+
*/
|
|
66
|
+
export declare function getDefaultTransition(valueKey: string, keyframes: readonly (number | null)[]): DefaultTransition;
|
|
67
|
+
export interface InertiaTransition {
|
|
68
|
+
readonly type: 'inertia';
|
|
69
|
+
/** Pinned drag-layer defaults (VisualElementDragControls.startAnimation); all fields resolved */
|
|
70
|
+
readonly power: number;
|
|
71
|
+
readonly timeConstant: number;
|
|
72
|
+
readonly bounceStiffness: number;
|
|
73
|
+
readonly bounceDamping: number;
|
|
74
|
+
readonly restDelta: number;
|
|
75
|
+
readonly restSpeed: number;
|
|
76
|
+
/** Constraint bounds for the boundary spring; ±Infinity sentinels are legal (open sides). */
|
|
77
|
+
readonly min?: number;
|
|
78
|
+
readonly max?: number;
|
|
79
|
+
}
|
|
80
|
+
export declare const DRAG_INERTIA_DEFAULTS: {
|
|
81
|
+
readonly power: 0.8;
|
|
82
|
+
readonly timeConstant: 750;
|
|
83
|
+
readonly restDelta: 1;
|
|
84
|
+
readonly restSpeed: 10;
|
|
85
|
+
};
|
|
86
|
+
export declare function dragInertiaBounce(elastic: number | undefined): {
|
|
87
|
+
readonly bounceStiffness: number;
|
|
88
|
+
readonly bounceDamping: number;
|
|
89
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { SpringPhysics } from "./spring.js";
|
|
2
|
+
import type { Generator, GeneratorFactory } from "./types.js";
|
|
3
|
+
import type { Transition } from "./component/types.js";
|
|
4
|
+
export interface SpringConfig {
|
|
5
|
+
stiffness?: number;
|
|
6
|
+
damping?: number;
|
|
7
|
+
mass?: number;
|
|
8
|
+
duration?: number;
|
|
9
|
+
bounce?: number;
|
|
10
|
+
visualDuration?: number;
|
|
11
|
+
velocity?: number;
|
|
12
|
+
restSpeed?: number;
|
|
13
|
+
restDelta?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedSpring {
|
|
16
|
+
physics: SpringPhysics;
|
|
17
|
+
carryVelocity: boolean;
|
|
18
|
+
isResolvedFromDuration: boolean;
|
|
19
|
+
calculatedDuration: number | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a spring transition config to concrete physics + carry/settle flags (REQ-SPRING-006
|
|
23
|
+
* precedence). Presence is tested on `!== undefined`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveSpring(config: SpringConfig): ResolvedSpring;
|
|
26
|
+
/**
|
|
27
|
+
* Build a `GeneratorFactory` from a target + config, honoring velocity carry/zero (REQ-SPRING-007).
|
|
28
|
+
* Duration/visualDuration springs drop the seed's incoming velocity; physics springs keep it —
|
|
29
|
+
* unless the config carries an AUTHORED `velocity`, which replaces it (REQ-API-053, T21): the pin's
|
|
30
|
+
* animateMotionValue spreads the authored transition over the live-velocity default
|
|
31
|
+
* (motion-dom@12.42.2 motion-value.ts:45-50), so the authored number wins on every start.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveSpringGenerator(target: number, config: SpringConfig): GeneratorFactory;
|
|
34
|
+
/**
|
|
35
|
+
* Interrupt/retarget (REQ-SPRING-009): build a new generator for `newTarget` from the OUTGOING
|
|
36
|
+
* generator's analytic state at `atMs` — its exact value and analytic velocity (preferred over any
|
|
37
|
+
* finite-diff, which avoids systematic velocity loss at high frame rates). Whether that incoming
|
|
38
|
+
* velocity carries (physics), is replaced by an authored config `velocity` (REQ-API-053), or is
|
|
39
|
+
* zeroed (duration/visualDuration) is decided by
|
|
40
|
+
* `resolveSpringGenerator` (REQ-SPRING-007). The result's `value(0)` equals the outgoing `value(atMs)`
|
|
41
|
+
* exactly — no teleport, no velocity reset. The graph's own interruption seam does the equivalent via
|
|
42
|
+
* `motionValue.getVelocity()`; this is the explicit spring-layer helper for consumers driving
|
|
43
|
+
* generators directly (e.g. the Reanimated driver).
|
|
44
|
+
*/
|
|
45
|
+
export declare function retargetSpring(outgoing: Generator, atMs: number, newTarget: number, config: SpringConfig): Generator;
|
|
46
|
+
export declare function springKeyframeCountRefusal(count: number): Error | null;
|
|
47
|
+
export type DefaultTransition = ({
|
|
48
|
+
type: 'spring';
|
|
49
|
+
stiffness: number;
|
|
50
|
+
damping: number;
|
|
51
|
+
restSpeed: number;
|
|
52
|
+
} & Pick<Transition, 'delay' | 'repeat' | 'repeatType' | 'repeatDelay'>) | ({
|
|
53
|
+
type: 'keyframes';
|
|
54
|
+
ease?: readonly [number, number, number, number];
|
|
55
|
+
duration: number;
|
|
56
|
+
} & Pick<Transition, 'delay' | 'repeat' | 'repeatType' | 'repeatDelay'>);
|
|
57
|
+
/**
|
|
58
|
+
* Default transition per property when none is specified (REQ-SPRING-012), keyframe-count-aware to
|
|
59
|
+
* match the pinned `motion-dom` `getDefaultTransition(valueKey, { keyframes })`
|
|
60
|
+
* (default-transitions.ts): MORE than two keyframes → an 800ms keyframes transition (regardless of
|
|
61
|
+
* property); otherwise a transform prop gets an underdamped spring (scale: critically-damped 550,
|
|
62
|
+
* damping 30 for a non-zero target and 2√550 at exactly 0; other transforms: 500/25), and every
|
|
63
|
+
* other property gets the 300ms shallow-browser tween. A scalar animation is the two-keyframe case
|
|
64
|
+
* (`[from, target]`); the last keyframe drives the scale-at-zero branch (Motion reads `keyframes[1]`).
|
|
65
|
+
*/
|
|
66
|
+
export declare function getDefaultTransition(valueKey: string, keyframes: readonly (number | null)[]): DefaultTransition;
|
|
67
|
+
export interface InertiaTransition {
|
|
68
|
+
readonly type: 'inertia';
|
|
69
|
+
/** Pinned drag-layer defaults (VisualElementDragControls.startAnimation); all fields resolved */
|
|
70
|
+
readonly power: number;
|
|
71
|
+
readonly timeConstant: number;
|
|
72
|
+
readonly bounceStiffness: number;
|
|
73
|
+
readonly bounceDamping: number;
|
|
74
|
+
readonly restDelta: number;
|
|
75
|
+
readonly restSpeed: number;
|
|
76
|
+
/** Constraint bounds for the boundary spring; ±Infinity sentinels are legal (open sides). */
|
|
77
|
+
readonly min?: number;
|
|
78
|
+
readonly max?: number;
|
|
79
|
+
}
|
|
80
|
+
export declare const DRAG_INERTIA_DEFAULTS: {
|
|
81
|
+
readonly power: 0.8;
|
|
82
|
+
readonly timeConstant: 750;
|
|
83
|
+
readonly restDelta: 1;
|
|
84
|
+
readonly restSpeed: 10;
|
|
85
|
+
};
|
|
86
|
+
export declare function dragInertiaBounce(elastic: number | undefined): {
|
|
87
|
+
readonly bounceStiffness: number;
|
|
88
|
+
readonly bounceDamping: number;
|
|
89
|
+
};
|