@vune-ui/animation 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/ARCHITECTURE.md +470 -0
  2. package/CHANGELOG.md +88 -0
  3. package/LICENSE +21 -0
  4. package/PERFORMANCE.md +151 -0
  5. package/README.md +630 -0
  6. package/dist/index.d.ts +474 -0
  7. package/dist/src/canvas/index.d.ts +15 -0
  8. package/dist/src/canvas/index.js +67 -0
  9. package/dist/src/constraints/index.d.ts +33 -0
  10. package/dist/src/constraints/index.js +346 -0
  11. package/dist/src/core/bezier.js +51 -0
  12. package/dist/src/core/composition.js +17 -0
  13. package/dist/src/core/controls.js +22 -0
  14. package/dist/src/core/default-engine.js +20 -0
  15. package/dist/src/core/easing.js +58 -0
  16. package/dist/src/core/engine.js +1031 -0
  17. package/dist/src/core/frame-budget.js +30 -0
  18. package/dist/src/core/index.d.ts +43 -0
  19. package/dist/src/core/index.js +17 -0
  20. package/dist/src/core/js-spring-batch.js +57 -0
  21. package/dist/src/core/kinetics.js +140 -0
  22. package/dist/src/core/math.js +20 -0
  23. package/dist/src/core/motion-value.js +53 -0
  24. package/dist/src/core/planner.js +72 -0
  25. package/dist/src/core/specs.js +70 -0
  26. package/dist/src/dom/index.d.ts +41 -0
  27. package/dist/src/dom/index.js +364 -0
  28. package/dist/src/gesture/index.d.ts +66 -0
  29. package/dist/src/gesture/index.js +376 -0
  30. package/dist/src/index.js +53 -0
  31. package/dist/src/interpolate/color.js +223 -0
  32. package/dist/src/interpolate/css.d.ts +13 -0
  33. package/dist/src/interpolate/css.js +34 -0
  34. package/dist/src/interpolate/index.d.ts +13 -0
  35. package/dist/src/interpolate/index.js +55 -0
  36. package/dist/src/interpolate/transform.js +247 -0
  37. package/dist/src/layout/index.d.ts +56 -0
  38. package/dist/src/layout/index.js +485 -0
  39. package/dist/src/material/index.d.ts +9 -0
  40. package/dist/src/material/index.js +70 -0
  41. package/dist/src/path/index.d.ts +37 -0
  42. package/dist/src/path/index.js +527 -0
  43. package/dist/src/render/frame-batcher.js +52 -0
  44. package/dist/src/scroll/index.d.ts +55 -0
  45. package/dist/src/scroll/index.js +233 -0
  46. package/dist/src/timeline/index.d.ts +147 -0
  47. package/dist/src/timeline/index.js +849 -0
  48. package/dist/src/transition/index.d.ts +88 -0
  49. package/dist/src/transition/index.js +369 -0
  50. package/dist/src/wasm/index.d.ts +29 -0
  51. package/dist/src/wasm/index.js +8 -0
  52. package/dist/src/wasm/loader.js +55 -0
  53. package/dist/src/wasm/shared-wasm-spring-batch.js +52 -0
  54. package/dist/src/wasm/wasm-spring-batch.js +52 -0
  55. package/dist/src/webgl/index.d.ts +22 -0
  56. package/dist/src/webgl/index.js +94 -0
  57. package/dist/src/webgpu/index.d.ts +35 -0
  58. package/dist/src/webgpu/index.js +73 -0
  59. package/dist/src/webgpu/spring-batch.js +218 -0
  60. package/dist/src/worker/index.d.ts +17 -0
  61. package/dist/src/worker/index.js +1 -0
  62. package/dist/src/worker/shared-spring-worker.js +218 -0
  63. package/dist/src/worker/shared-worker.js +75 -0
  64. package/dist/wasm/kernel-scalar.wasm +0 -0
  65. package/dist/wasm/kernel-shared-scalar.wasm +0 -0
  66. package/dist/wasm/kernel-shared-simd.wasm +0 -0
  67. package/dist/wasm/kernel-simd.wasm +0 -0
  68. package/package.json +113 -0
@@ -0,0 +1,13 @@
1
+ export {
2
+ animateInterpolated,
3
+ createInterpolator,
4
+ interpolateNumber,
5
+ interpolateColor,
6
+ mixColor,
7
+ parseColor,
8
+ formatColor,
9
+ interpolateTransform,
10
+ mixTransform,
11
+ parseTransform,
12
+ formatTransform,
13
+ } from '../../index.js';
@@ -0,0 +1,55 @@
1
+ import { AnimationControls } from '../core/controls.js';
2
+ import { defaultEngine } from '../core/default-engine.js';
3
+ import { motionValue } from '../core/motion-value.js';
4
+ import { interpolateColor } from './color.js';
5
+ import { interpolateTransform } from './transform.js';
6
+ import { interpolatePath } from '../path/index.js';
7
+ import { interpolateMaterial } from '../material/index.js';
8
+
9
+ export * from './color.js';
10
+ export * from './transform.js';
11
+
12
+ export function interpolateNumber(from, to) {
13
+ const a = Number(from);
14
+ const b = Number(to);
15
+ if (!Number.isFinite(a) || !Number.isFinite(b)) throw new TypeError('Numeric interpolation requires finite numbers.');
16
+ return (progress) => a + (b - a) * progress;
17
+ }
18
+
19
+ export function createInterpolator(from, to, options = {}) {
20
+ if (typeof options.interpolate === 'function') return (progress) => options.interpolate(from, to, progress);
21
+ if (typeof from === 'number' && typeof to === 'number') return interpolateNumber(from, to);
22
+ if (options.type === 'transform' || (typeof from === 'object' && typeof to === 'object' && ('x' in from || 'scale' in from || 'rotate' in from))) {
23
+ return interpolateTransform(from, to, options.transform);
24
+ }
25
+ if (options.type === 'color') return interpolateColor(from, to, options.color);
26
+ if (options.type === 'path') return interpolatePath(from, to, options.path);
27
+ if (options.type === 'material') return interpolateMaterial(from, to, options.material);
28
+ if (typeof from === 'string' && typeof to === 'string') {
29
+ try { return interpolateColor(from, to, options.color); } catch {}
30
+ try { return interpolateTransform(from, to, options.transform); } catch {}
31
+ }
32
+ throw new TypeError('No interpolator is available for these values. Pass options.type or options.interpolate.');
33
+ }
34
+
35
+ export function animateInterpolated(from, to, spec, onUpdate, {
36
+ engine = defaultEngine,
37
+ interpolate,
38
+ type,
39
+ color,
40
+ transform,
41
+ path,
42
+ material,
43
+ } = {}) {
44
+ if (typeof onUpdate !== 'function') throw new TypeError('animateInterpolated() requires an onUpdate callback.');
45
+ const mixer = interpolate ? (progress) => interpolate(from, to, progress) : createInterpolator(from, to, { type, color, transform, path, material });
46
+ const progress = motionValue(0);
47
+ const unsubscribe = (progress.subscribeValue ?? progress.subscribe).call(progress, (value) => onUpdate(mixer(value), value));
48
+ const inner = engine.animate(progress, 1, spec);
49
+ const finished = inner.finished.finally(unsubscribe);
50
+ return new AnimationControls(
51
+ () => inner.cancel(),
52
+ () => inner.finish(),
53
+ finished,
54
+ );
55
+ }
@@ -0,0 +1,247 @@
1
+ const EPSILON = 1e-10;
2
+ const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
3
+ const lerp = (a, b, t) => a + (b - a) * t;
4
+
5
+ export const identityTransform = Object.freeze({
6
+ x: 0, y: 0, z: 0,
7
+ scaleX: 1, scaleY: 1, scaleZ: 1,
8
+ rotateX: 0, rotateY: 0, rotateZ: 0,
9
+ skewX: 0, skewY: 0,
10
+ perspective: 0,
11
+ });
12
+
13
+ export const identityMatrix2D = Object.freeze([1, 0, 0, 1, 0, 0]);
14
+
15
+ export function multiplyMatrix2D(left, right) {
16
+ const [a1, b1, c1, d1, e1, f1] = left;
17
+ const [a2, b2, c2, d2, e2, f2] = right;
18
+ return [
19
+ a1 * a2 + c1 * b2,
20
+ b1 * a2 + d1 * b2,
21
+ a1 * c2 + c1 * d2,
22
+ b1 * c2 + d1 * d2,
23
+ a1 * e2 + c1 * f2 + e1,
24
+ b1 * e2 + d1 * f2 + f1,
25
+ ];
26
+ }
27
+
28
+ export function invertMatrix2D(matrix) {
29
+ const [a, b, c, d, e, f] = matrix;
30
+ const determinant = a * d - b * c;
31
+ if (Math.abs(determinant) < EPSILON) return [...identityMatrix2D];
32
+ const inv = 1 / determinant;
33
+ return [d * inv, -b * inv, -c * inv, a * inv, (c * f - d * e) * inv, (b * e - a * f) * inv];
34
+ }
35
+
36
+ export function translationMatrix2D(x, y) { return [1, 0, 0, 1, x, y]; }
37
+ export function scaleMatrix2D(x, y = x) { return [x, 0, 0, y, 0, 0]; }
38
+ export function rotationMatrix2D(degrees) {
39
+ const radians = degrees * Math.PI / 180;
40
+ const c = Math.cos(radians);
41
+ const s = Math.sin(radians);
42
+ return [c, s, -s, c, 0, 0];
43
+ }
44
+ export function skewXMatrix2D(degrees) { return [1, 0, Math.tan(degrees * Math.PI / 180), 1, 0, 0]; }
45
+ export function skewYMatrix2D(degrees) { return [1, Math.tan(degrees * Math.PI / 180), 0, 1, 0, 0]; }
46
+
47
+ function parseNumber(token) {
48
+ const value = Number.parseFloat(String(token).trim());
49
+ if (!Number.isFinite(value)) throw new TypeError(`Invalid transform number: ${token}`);
50
+ return value;
51
+ }
52
+
53
+ function parseLength(token) {
54
+ const text = String(token).trim().toLowerCase();
55
+ if (text === '0') return 0;
56
+ if (text.endsWith('px')) return parseNumber(text);
57
+ if (/^-?\d*\.?\d+(e[-+]?\d+)?$/i.test(text)) return parseNumber(text);
58
+ throw new TypeError(`Only px lengths can be interpolated without layout context: ${token}`);
59
+ }
60
+
61
+ function parseAngle(token) {
62
+ const text = String(token).trim().toLowerCase();
63
+ if (text.endsWith('deg')) return parseNumber(text);
64
+ if (text.endsWith('rad')) return parseNumber(text) * 180 / Math.PI;
65
+ if (text.endsWith('turn')) return parseNumber(text) * 360;
66
+ if (text.endsWith('grad')) return parseNumber(text) * 0.9;
67
+ if (text === '0' || /^-?\d*\.?\d+$/.test(text)) return parseNumber(text);
68
+ throw new TypeError(`Unsupported angle: ${token}`);
69
+ }
70
+
71
+ function splitArgs(body) {
72
+ return body.includes(',') ? body.split(',').map((v) => v.trim()) : body.trim().split(/\s+/).filter(Boolean);
73
+ }
74
+
75
+ export function decomposeMatrix2D(matrix) {
76
+ let [a, b, c, d, e, f] = matrix;
77
+ let scaleX = Math.hypot(a, b);
78
+ if (scaleX < EPSILON) return { ...identityTransform, x: e, y: f, scaleX: 0, scaleY: Math.hypot(c, d) };
79
+ a /= scaleX;
80
+ b /= scaleX;
81
+ let shear = a * c + b * d;
82
+ c -= a * shear;
83
+ d -= b * shear;
84
+ let scaleY = Math.hypot(c, d);
85
+ if (scaleY > EPSILON) {
86
+ c /= scaleY;
87
+ d /= scaleY;
88
+ shear /= scaleY;
89
+ }
90
+ if (a * d - b * c < 0) {
91
+ scaleY = -scaleY;
92
+ shear = -shear;
93
+ }
94
+ return {
95
+ ...identityTransform,
96
+ x: e,
97
+ y: f,
98
+ scaleX,
99
+ scaleY,
100
+ rotateZ: Math.atan2(b, a) * 180 / Math.PI,
101
+ skewX: Math.atan(shear) * 180 / Math.PI,
102
+ };
103
+ }
104
+
105
+ export function composeMatrix2D(transform) {
106
+ let matrix = translationMatrix2D(transform.x ?? 0, transform.y ?? 0);
107
+ matrix = multiplyMatrix2D(matrix, rotationMatrix2D(transform.rotateZ ?? transform.rotate ?? 0));
108
+ matrix = multiplyMatrix2D(matrix, skewXMatrix2D(transform.skewX ?? 0));
109
+ matrix = multiplyMatrix2D(matrix, skewYMatrix2D(transform.skewY ?? 0));
110
+ matrix = multiplyMatrix2D(matrix, scaleMatrix2D(transform.scaleX ?? transform.scale ?? 1, transform.scaleY ?? transform.scale ?? 1));
111
+ return matrix;
112
+ }
113
+
114
+ function parse2DString(text) {
115
+ if (text === 'none' || text === '') return [...identityMatrix2D];
116
+ const pattern = /([a-zA-Z0-9]+)\(([^)]*)\)/g;
117
+ let match;
118
+ let matrix = [...identityMatrix2D];
119
+ let consumed = '';
120
+ while ((match = pattern.exec(text))) {
121
+ consumed += match[0];
122
+ const name = match[1].toLowerCase();
123
+ const args = splitArgs(match[2]);
124
+ let next;
125
+ switch (name) {
126
+ case 'matrix':
127
+ if (args.length !== 6) return null;
128
+ next = args.map(parseNumber);
129
+ break;
130
+ case 'translate': next = translationMatrix2D(parseLength(args[0] ?? 0), parseLength(args[1] ?? 0)); break;
131
+ case 'translatex': next = translationMatrix2D(parseLength(args[0] ?? 0), 0); break;
132
+ case 'translatey': next = translationMatrix2D(0, parseLength(args[0] ?? 0)); break;
133
+ case 'scale': next = scaleMatrix2D(parseNumber(args[0] ?? 1), parseNumber(args[1] ?? args[0] ?? 1)); break;
134
+ case 'scalex': next = scaleMatrix2D(parseNumber(args[0] ?? 1), 1); break;
135
+ case 'scaley': next = scaleMatrix2D(1, parseNumber(args[0] ?? 1)); break;
136
+ case 'rotate': next = rotationMatrix2D(parseAngle(args[0] ?? 0)); break;
137
+ case 'skewx': next = skewXMatrix2D(parseAngle(args[0] ?? 0)); break;
138
+ case 'skewy': next = skewYMatrix2D(parseAngle(args[0] ?? 0)); break;
139
+ case 'skew':
140
+ next = multiplyMatrix2D(skewXMatrix2D(parseAngle(args[0] ?? 0)), skewYMatrix2D(parseAngle(args[1] ?? 0)));
141
+ break;
142
+ default: return null;
143
+ }
144
+ matrix = multiplyMatrix2D(matrix, next);
145
+ }
146
+ return consumed ? matrix : null;
147
+ }
148
+
149
+ function parse3DComponents(text) {
150
+ const result = { ...identityTransform };
151
+ const pattern = /([a-zA-Z0-9]+)\(([^)]*)\)/g;
152
+ let match;
153
+ let found = false;
154
+ while ((match = pattern.exec(text))) {
155
+ found = true;
156
+ const name = match[1].toLowerCase();
157
+ const args = splitArgs(match[2]);
158
+ switch (name) {
159
+ case 'translate3d': [result.x, result.y, result.z] = [parseLength(args[0]), parseLength(args[1]), parseLength(args[2])]; break;
160
+ case 'translatez': result.z = parseLength(args[0]); break;
161
+ case 'scale3d': [result.scaleX, result.scaleY, result.scaleZ] = args.slice(0, 3).map(parseNumber); break;
162
+ case 'scalez': result.scaleZ = parseNumber(args[0]); break;
163
+ case 'rotatex': result.rotateX = parseAngle(args[0]); break;
164
+ case 'rotatey': result.rotateY = parseAngle(args[0]); break;
165
+ case 'rotatez': result.rotateZ = parseAngle(args[0]); break;
166
+ case 'perspective': result.perspective = parseLength(args[0]); break;
167
+ case 'translate': result.x = parseLength(args[0] ?? 0); result.y = parseLength(args[1] ?? 0); break;
168
+ case 'translatex': result.x = parseLength(args[0]); break;
169
+ case 'translatey': result.y = parseLength(args[0]); break;
170
+ case 'scale': result.scaleX = parseNumber(args[0]); result.scaleY = parseNumber(args[1] ?? args[0]); break;
171
+ case 'scalex': result.scaleX = parseNumber(args[0]); break;
172
+ case 'scaley': result.scaleY = parseNumber(args[0]); break;
173
+ case 'rotate': result.rotateZ = parseAngle(args[0]); break;
174
+ case 'skewx': result.skewX = parseAngle(args[0]); break;
175
+ case 'skewy': result.skewY = parseAngle(args[0]); break;
176
+ default: throw new TypeError(`Unsupported 3D transform function: ${name}`);
177
+ }
178
+ }
179
+ if (!found) throw new TypeError(`Invalid transform: ${text}`);
180
+ return result;
181
+ }
182
+
183
+ export function parseTransform(input) {
184
+ if (!input || input === 'none') return { ...identityTransform };
185
+ if (typeof input === 'object') {
186
+ const scale = Number(input.scale ?? 1);
187
+ return {
188
+ ...identityTransform,
189
+ ...input,
190
+ x: Number(input.x ?? 0), y: Number(input.y ?? 0), z: Number(input.z ?? 0),
191
+ scaleX: Number(input.scaleX ?? scale), scaleY: Number(input.scaleY ?? scale), scaleZ: Number(input.scaleZ ?? scale),
192
+ rotateX: Number(input.rotateX ?? 0), rotateY: Number(input.rotateY ?? 0), rotateZ: Number(input.rotateZ ?? input.rotate ?? 0),
193
+ skewX: Number(input.skewX ?? 0), skewY: Number(input.skewY ?? 0), perspective: Number(input.perspective ?? 0),
194
+ };
195
+ }
196
+ if (typeof input !== 'string') throw new TypeError('Transform must be a string or component object.');
197
+ const text = input.trim();
198
+ const matrix = parse2DString(text);
199
+ return matrix ? decomposeMatrix2D(matrix) : parse3DComponents(text);
200
+ }
201
+
202
+ function shortestAngle(from, to) {
203
+ let delta = (to - from) % 360;
204
+ if (delta > 180) delta -= 360;
205
+ if (delta < -180) delta += 360;
206
+ return delta;
207
+ }
208
+
209
+ export function mixTransform(fromInput, toInput, progress, { shortestRotation = true } = {}) {
210
+ const from = parseTransform(fromInput);
211
+ const to = parseTransform(toInput);
212
+ const t = clamp(progress, 0, 1);
213
+ const angle = (key) => shortestRotation ? from[key] + shortestAngle(from[key], to[key]) * t : lerp(from[key], to[key], t);
214
+ return {
215
+ x: lerp(from.x, to.x, t), y: lerp(from.y, to.y, t), z: lerp(from.z, to.z, t),
216
+ scaleX: lerp(from.scaleX, to.scaleX, t), scaleY: lerp(from.scaleY, to.scaleY, t), scaleZ: lerp(from.scaleZ, to.scaleZ, t),
217
+ rotateX: angle('rotateX'), rotateY: angle('rotateY'), rotateZ: angle('rotateZ'),
218
+ skewX: angle('skewX'), skewY: angle('skewY'),
219
+ perspective: lerp(from.perspective, to.perspective, t),
220
+ };
221
+ }
222
+
223
+ function clean(value) { return Math.abs(value) < 1e-7 ? 0 : Math.round(value * 100000) / 100000; }
224
+
225
+ export function formatTransform(value) {
226
+ const t = parseTransform(value);
227
+ const parts = [];
228
+ if (t.perspective) parts.push(`perspective(${clean(t.perspective)}px)`);
229
+ if (t.x || t.y || t.z) parts.push(`translate3d(${clean(t.x)}px, ${clean(t.y)}px, ${clean(t.z)}px)`);
230
+ if (Math.abs(t.rotateX) > 1e-7) parts.push(`rotateX(${clean(t.rotateX)}deg)`);
231
+ if (Math.abs(t.rotateY) > 1e-7) parts.push(`rotateY(${clean(t.rotateY)}deg)`);
232
+ if (Math.abs(t.rotateZ) > 1e-7) parts.push(`rotate(${clean(t.rotateZ)}deg)`);
233
+ if (Math.abs(t.skewX) > 1e-7) parts.push(`skewX(${clean(t.skewX)}deg)`);
234
+ if (Math.abs(t.skewY) > 1e-7) parts.push(`skewY(${clean(t.skewY)}deg)`);
235
+ if (t.scaleX !== 1 || t.scaleY !== 1 || t.scaleZ !== 1) parts.push(`scale3d(${clean(t.scaleX)}, ${clean(t.scaleY)}, ${clean(t.scaleZ)})`);
236
+ return parts.length ? parts.join(' ') : 'none';
237
+ }
238
+
239
+ export function interpolateTransform(from, to, options) {
240
+ const start = parseTransform(from);
241
+ const end = parseTransform(to);
242
+ return (progress) => formatTransform(mixTransform(start, end, progress, options));
243
+ }
244
+
245
+ export function formatMatrix2D(matrix) {
246
+ return `matrix(${matrix.map(clean).join(', ')})`;
247
+ }
@@ -0,0 +1,56 @@
1
+ import type { AnimationControls, MotionEngine, MotionSpec } from '../../index.js';
2
+ export type LayoutRect = { left: number; top: number; width: number; height: number; right?: number; bottom?: number };
3
+ export type LayoutOptions = {
4
+ engine?: MotionEngine;
5
+ spec?: MotionSpec;
6
+ includeSize?: boolean;
7
+ preserveTransform?: boolean;
8
+ measureScroll?: () => { x: number; y: number };
9
+ };
10
+ export function captureLayout(elements: Element | Iterable<Element>, options?: Pick<LayoutOptions, 'measureScroll'>): Array<{ element: Element; rect: Required<LayoutRect>; scroll: { x: number; y: number } }>;
11
+ export function projectionMatrixForRects(first: LayoutRect, last: LayoutRect, options?: { includeSize?: boolean }): number[];
12
+ export class LayoutTransition {
13
+ constructor(elements: Element | Iterable<Element>, options?: LayoutOptions);
14
+ readonly first: Array<{ element: Element; rect: Required<LayoutRect>; scroll: { x: number; y: number } }>;
15
+ play(): AnimationControls | null;
16
+ cancel(): void;
17
+ }
18
+ export function createLayoutTransition(elements: Element | Iterable<Element>, options?: LayoutOptions): LayoutTransition;
19
+ export function animateLayout(elements: Element | Iterable<Element>, mutate: (() => void) | undefined, options?: LayoutOptions): { transition: LayoutTransition; controls: AnimationControls | null };
20
+
21
+ export type SharedLayoutKey = string | number;
22
+ export type SharedLayoutOptions = LayoutOptions & {
23
+ key?: string | ((element: Element) => SharedLayoutKey | null | undefined);
24
+ fadeTarget?: boolean;
25
+ };
26
+ export type SharedLayoutEntry = {
27
+ key: SharedLayoutKey;
28
+ element: Element;
29
+ rect: Required<LayoutRect>;
30
+ scroll: { x: number; y: number };
31
+ };
32
+ export class SharedLayoutSnapshot implements Iterable<[SharedLayoutKey, SharedLayoutEntry]> {
33
+ constructor(entries?: SharedLayoutEntry[]);
34
+ readonly size: number;
35
+ get(key: SharedLayoutKey): SharedLayoutEntry | undefined;
36
+ has(key: SharedLayoutKey): boolean;
37
+ [Symbol.iterator](): MapIterator<[SharedLayoutKey, SharedLayoutEntry]>;
38
+ }
39
+ export function captureSharedLayout(elements: Element | Iterable<Element>, options?: Pick<SharedLayoutOptions, 'key' | 'measureScroll'>): SharedLayoutSnapshot;
40
+ export class SharedLayoutTransition {
41
+ constructor(snapshot: SharedLayoutSnapshot, elements: Element | Iterable<Element>, options?: SharedLayoutOptions);
42
+ readonly snapshot: SharedLayoutSnapshot;
43
+ readonly progress: import('../../index.js').MotionValue | null;
44
+ play(): AnimationControls | null;
45
+ cancel(): void;
46
+ }
47
+ export function createSharedLayoutTransition(snapshot: SharedLayoutSnapshot, elements: Element | Iterable<Element>, options?: SharedLayoutOptions): SharedLayoutTransition;
48
+ export function animateSharedLayout(snapshot: SharedLayoutSnapshot, elements: Element | Iterable<Element>, options?: SharedLayoutOptions): { transition: SharedLayoutTransition; controls: AnimationControls | null };
49
+ export class SharedLayoutRegistry {
50
+ constructor(options?: SharedLayoutOptions);
51
+ snapshot: SharedLayoutSnapshot;
52
+ active: SharedLayoutTransition | null;
53
+ capture(elements: Element | Iterable<Element>, options?: SharedLayoutOptions): SharedLayoutSnapshot;
54
+ play(elements: Element | Iterable<Element>, options?: SharedLayoutOptions): { transition: SharedLayoutTransition; controls: AnimationControls | null };
55
+ cancel(): void;
56
+ }