@remotion/paths 4.0.528 → 4.0.530
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/dist/esm/index.mjs +96 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/interpolate-paths.d.ts +6 -0
- package/dist/interpolate-paths.js +128 -0
- package/package.json +5 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -3297,6 +3297,101 @@ var interpolatePath = (value, firstPath, secondPath) => {
|
|
|
3297
3297
|
const commandInterpolator = interpolateInstructions(aCommands, bCommands);
|
|
3298
3298
|
return serializeInstructions(commandInterpolator(value));
|
|
3299
3299
|
};
|
|
3300
|
+
// src/interpolate-paths.ts
|
|
3301
|
+
import {
|
|
3302
|
+
interpolate
|
|
3303
|
+
} from "remotion/no-react";
|
|
3304
|
+
var normalizeInterpolatedPath = (path) => {
|
|
3305
|
+
return path.replace(/-?\d*\.?\d+(?:e[+-]?\d+)?/gi, (value) => {
|
|
3306
|
+
const number = Number(value);
|
|
3307
|
+
return Number.isInteger(number) ? value : String(Number(number.toPrecision(15)));
|
|
3308
|
+
});
|
|
3309
|
+
};
|
|
3310
|
+
var interpolatePaths = (input, inputRange, outputRange, options) => {
|
|
3311
|
+
if (!Array.isArray(outputRange)) {
|
|
3312
|
+
throw new TypeError("outputRange must be an array of SVG path strings");
|
|
3313
|
+
}
|
|
3314
|
+
for (const path of outputRange) {
|
|
3315
|
+
if (typeof path !== "string") {
|
|
3316
|
+
throw new TypeError("outputRange must contain only SVG path strings");
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
for (const side of ["extrapolateLeft", "extrapolateRight"]) {
|
|
3320
|
+
const extrapolation = options?.[side];
|
|
3321
|
+
if (extrapolation !== undefined && extrapolation !== "extend" && extrapolation !== "clamp" && extrapolation !== "wrap") {
|
|
3322
|
+
throw new TypeError(`${side} must be "extend", "clamp", or "wrap" for interpolatePaths()`);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
const weights = interpolate(input, inputRange, outputRange.map((_, pathIndex) => outputRange.map((__, index) => index === pathIndex ? 1 : 0)), options);
|
|
3326
|
+
const exactPathIndex = weights.findIndex((weight, index) => weight === 1 && weights.every((otherWeight, otherIndex) => otherIndex === index ? true : otherWeight === 0));
|
|
3327
|
+
if (exactPathIndex !== -1) {
|
|
3328
|
+
return outputRange[exactPathIndex];
|
|
3329
|
+
}
|
|
3330
|
+
const contributingPaths = outputRange.map((path, index) => ({ path, weight: weights[index] })).filter(({ weight }) => weight !== 0);
|
|
3331
|
+
const paths = contributingPaths.map(({ path }) => {
|
|
3332
|
+
const commands = reduceInstructions(parsePath(path));
|
|
3333
|
+
if (commands.length === 0) {
|
|
3334
|
+
throw new TypeError(`SVG Path "${path}" is not valid`);
|
|
3335
|
+
}
|
|
3336
|
+
return commands;
|
|
3337
|
+
});
|
|
3338
|
+
const closed = paths.every((commands) => commands[commands.length - 1].type === "Z");
|
|
3339
|
+
const openPaths = paths.map((commands) => commands[commands.length - 1].type === "Z" ? commands.slice(0, -1) : commands);
|
|
3340
|
+
const reference = openPaths.reduce((longest, commands) => commands.length > longest.length ? commands : longest);
|
|
3341
|
+
const extendedPaths = openPaths.map((commands) => commands.length < reference.length ? extendInstruction(commands, reference) : commands);
|
|
3342
|
+
const result = reference.map((_, instructionIndex) => {
|
|
3343
|
+
const commands = extendedPaths.map((path) => path[instructionIndex]);
|
|
3344
|
+
if (commands.some((command) => command.type === "Z")) {
|
|
3345
|
+
if (commands.every((command) => command.type === "Z")) {
|
|
3346
|
+
return { type: "Z" };
|
|
3347
|
+
}
|
|
3348
|
+
throw new TypeError("Cannot interpolate SVG paths with different subpath structures");
|
|
3349
|
+
}
|
|
3350
|
+
const target = commands.find((command) => command.type === "C") ?? commands[0];
|
|
3351
|
+
const normalized = commands.map((command, pathIndex) => {
|
|
3352
|
+
if (command.type === "M" !== (target.type === "M")) {
|
|
3353
|
+
throw new TypeError("Cannot interpolate SVG paths with different subpath structures");
|
|
3354
|
+
}
|
|
3355
|
+
return convertToSameInstructionType(command, target, getEndPosition(extendedPaths[pathIndex].slice(0, instructionIndex)));
|
|
3356
|
+
});
|
|
3357
|
+
const coordinates = normalized.map((command) => {
|
|
3358
|
+
if (command.type === "Z") {
|
|
3359
|
+
return [];
|
|
3360
|
+
}
|
|
3361
|
+
return command.type === "C" ? [
|
|
3362
|
+
command.x,
|
|
3363
|
+
command.y,
|
|
3364
|
+
command.cp1x,
|
|
3365
|
+
command.cp1y,
|
|
3366
|
+
command.cp2x,
|
|
3367
|
+
command.cp2y
|
|
3368
|
+
] : [command.x, command.y];
|
|
3369
|
+
});
|
|
3370
|
+
const values = coordinates[0].map((base, coordinateIndex) => {
|
|
3371
|
+
const interpolated = coordinates.reduce((value, path, pathIndex) => value + (path[coordinateIndex] - base) * contributingPaths[pathIndex].weight, base);
|
|
3372
|
+
if (Number.isFinite(interpolated)) {
|
|
3373
|
+
return interpolated;
|
|
3374
|
+
}
|
|
3375
|
+
return coordinates.reduce((sum, path, pathIndex) => sum + path[coordinateIndex] * contributingPaths[pathIndex].weight, 0);
|
|
3376
|
+
});
|
|
3377
|
+
if (target.type === "C") {
|
|
3378
|
+
return {
|
|
3379
|
+
type: "C",
|
|
3380
|
+
x: values[0],
|
|
3381
|
+
y: values[1],
|
|
3382
|
+
cp1x: values[2],
|
|
3383
|
+
cp1y: values[3],
|
|
3384
|
+
cp2x: values[4],
|
|
3385
|
+
cp2y: values[5]
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
return { type: target.type, x: values[0], y: values[1] };
|
|
3389
|
+
});
|
|
3390
|
+
if (closed) {
|
|
3391
|
+
result.push({ type: "Z" });
|
|
3392
|
+
}
|
|
3393
|
+
return normalizeInterpolatedPath(serializeInstructions(result));
|
|
3394
|
+
};
|
|
3300
3395
|
// src/reset-path.ts
|
|
3301
3396
|
var resetPath = (d) => {
|
|
3302
3397
|
const box = getBoundingBox(d);
|
|
@@ -3757,6 +3852,7 @@ export {
|
|
|
3757
3852
|
reduceInstructions,
|
|
3758
3853
|
parsePath,
|
|
3759
3854
|
normalizePath,
|
|
3855
|
+
interpolatePaths,
|
|
3760
3856
|
interpolatePath,
|
|
3761
3857
|
getTangentAtLength,
|
|
3762
3858
|
getSubpaths,
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { getSubpaths } from './get-subpaths';
|
|
|
10
10
|
export { getTangentAtLength } from './get-tangent-at-length';
|
|
11
11
|
export { AbsoluteInstruction, BoundingBox, Instruction, Part, ReducedInstruction, } from './helpers/types';
|
|
12
12
|
export { interpolatePath } from './interpolate-path/interpolate-path';
|
|
13
|
+
export { interpolatePaths, type InterpolatePathsOptions, } from './interpolate-paths';
|
|
13
14
|
export { normalizePath } from './normalize-path';
|
|
14
15
|
export { parsePath } from './parse-path';
|
|
15
16
|
export { reduceInstructions } from './reduce-instructions';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PathInternals = exports.warpPath = exports.translatePath = exports.serializeInstructions = exports.scalePath = exports.reversePath = exports.resetPath = exports.reduceInstructions = exports.parsePath = exports.normalizePath = exports.interpolatePath = exports.getTangentAtLength = exports.getSubpaths = exports.getPointAtLength = exports.getLength = exports.getInstructionIndexAtLength = exports.getBoundingBox = exports.extendViewBox = exports.evolvePath = exports.cutPath = exports.centerPath = void 0;
|
|
3
|
+
exports.PathInternals = exports.warpPath = exports.translatePath = exports.serializeInstructions = exports.scalePath = exports.reversePath = exports.resetPath = exports.reduceInstructions = exports.parsePath = exports.normalizePath = exports.interpolatePaths = exports.interpolatePath = exports.getTangentAtLength = exports.getSubpaths = exports.getPointAtLength = exports.getLength = exports.getInstructionIndexAtLength = exports.getBoundingBox = exports.extendViewBox = exports.evolvePath = exports.cutPath = exports.centerPath = void 0;
|
|
4
4
|
const cut_path_1 = require("./cut-path");
|
|
5
5
|
const debug_path_1 = require("./debug-path");
|
|
6
6
|
const get_bounding_box_1 = require("./get-bounding-box");
|
|
@@ -26,6 +26,8 @@ const get_tangent_at_length_1 = require("./get-tangent-at-length");
|
|
|
26
26
|
Object.defineProperty(exports, "getTangentAtLength", { enumerable: true, get: function () { return get_tangent_at_length_1.getTangentAtLength; } });
|
|
27
27
|
const interpolate_path_1 = require("./interpolate-path/interpolate-path");
|
|
28
28
|
Object.defineProperty(exports, "interpolatePath", { enumerable: true, get: function () { return interpolate_path_1.interpolatePath; } });
|
|
29
|
+
const interpolate_paths_1 = require("./interpolate-paths");
|
|
30
|
+
Object.defineProperty(exports, "interpolatePaths", { enumerable: true, get: function () { return interpolate_paths_1.interpolatePaths; } });
|
|
29
31
|
const normalize_path_1 = require("./normalize-path");
|
|
30
32
|
Object.defineProperty(exports, "normalizePath", { enumerable: true, get: function () { return normalize_path_1.normalizePath; } });
|
|
31
33
|
const parse_path_1 = require("./parse-path");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ExtrapolateType, type InterpolateOptions } from 'remotion/no-react';
|
|
2
|
+
export type InterpolatePathsOptions = Pick<InterpolateOptions, 'easing' | 'posterize'> & {
|
|
3
|
+
extrapolateLeft?: Exclude<ExtrapolateType, 'identity'>;
|
|
4
|
+
extrapolateRight?: Exclude<ExtrapolateType, 'identity'>;
|
|
5
|
+
};
|
|
6
|
+
export declare const interpolatePaths: (input: number, inputRange: readonly number[], outputRange: readonly string[], options?: InterpolatePathsOptions | undefined) => string;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.interpolatePaths = void 0;
|
|
4
|
+
const no_react_1 = require("remotion/no-react");
|
|
5
|
+
const get_end_position_1 = require("./get-end-position");
|
|
6
|
+
const convert_to_same_instruction_type_1 = require("./interpolate-path/convert-to-same-instruction-type");
|
|
7
|
+
const extend_command_1 = require("./interpolate-path/extend-command");
|
|
8
|
+
const parse_path_1 = require("./parse-path");
|
|
9
|
+
const reduce_instructions_1 = require("./reduce-instructions");
|
|
10
|
+
const serialize_instructions_1 = require("./serialize-instructions");
|
|
11
|
+
const normalizeInterpolatedPath = (path) => {
|
|
12
|
+
// Remove floating-point artifacts without rounding small coordinates to zero.
|
|
13
|
+
return path.replace(/-?\d*\.?\d+(?:e[+-]?\d+)?/gi, (value) => {
|
|
14
|
+
const number = Number(value);
|
|
15
|
+
return Number.isInteger(number)
|
|
16
|
+
? value
|
|
17
|
+
: String(Number(number.toPrecision(15)));
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
/*
|
|
21
|
+
* @description Interpolates between multiple SVG paths, with keyframes, easing, and extrapolation.
|
|
22
|
+
* @see [Documentation](https://www.remotion.dev/docs/paths/interpolate-paths)
|
|
23
|
+
*/
|
|
24
|
+
const interpolatePaths = (input, inputRange, outputRange, options) => {
|
|
25
|
+
if (!Array.isArray(outputRange)) {
|
|
26
|
+
throw new TypeError('outputRange must be an array of SVG path strings');
|
|
27
|
+
}
|
|
28
|
+
for (const path of outputRange) {
|
|
29
|
+
if (typeof path !== 'string') {
|
|
30
|
+
throw new TypeError('outputRange must contain only SVG path strings');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const side of ['extrapolateLeft', 'extrapolateRight']) {
|
|
34
|
+
const extrapolation = options === null || options === void 0 ? void 0 : options[side];
|
|
35
|
+
if (extrapolation !== undefined &&
|
|
36
|
+
extrapolation !== 'extend' &&
|
|
37
|
+
extrapolation !== 'clamp' &&
|
|
38
|
+
extrapolation !== 'wrap') {
|
|
39
|
+
throw new TypeError(`${side} must be "extend", "clamp", or "wrap" for interpolatePaths()`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Interpolating a basis vector for each path preserves segment selection,
|
|
43
|
+
// easing overshoot, and the contributions of earlier spring segments.
|
|
44
|
+
const weights = (0, no_react_1.interpolate)(input, inputRange, outputRange.map((_, pathIndex) => outputRange.map((__, index) => (index === pathIndex ? 1 : 0))), options);
|
|
45
|
+
const exactPathIndex = weights.findIndex((weight, index) => weight === 1 &&
|
|
46
|
+
weights.every((otherWeight, otherIndex) => otherIndex === index ? true : otherWeight === 0));
|
|
47
|
+
if (exactPathIndex !== -1) {
|
|
48
|
+
return outputRange[exactPathIndex];
|
|
49
|
+
}
|
|
50
|
+
const contributingPaths = outputRange
|
|
51
|
+
.map((path, index) => ({ path, weight: weights[index] }))
|
|
52
|
+
.filter(({ weight }) => weight !== 0);
|
|
53
|
+
const paths = contributingPaths.map(({ path }) => {
|
|
54
|
+
const commands = (0, reduce_instructions_1.reduceInstructions)((0, parse_path_1.parsePath)(path));
|
|
55
|
+
if (commands.length === 0) {
|
|
56
|
+
throw new TypeError(`SVG Path "${path}" is not valid`);
|
|
57
|
+
}
|
|
58
|
+
return commands;
|
|
59
|
+
});
|
|
60
|
+
const closed = paths.every((commands) => commands[commands.length - 1].type === 'Z');
|
|
61
|
+
const openPaths = paths.map((commands) => commands[commands.length - 1].type === 'Z'
|
|
62
|
+
? commands.slice(0, -1)
|
|
63
|
+
: commands);
|
|
64
|
+
const reference = openPaths.reduce((longest, commands) => commands.length > longest.length ? commands : longest);
|
|
65
|
+
const extendedPaths = openPaths.map((commands) => commands.length < reference.length
|
|
66
|
+
? (0, extend_command_1.extendInstruction)(commands, reference)
|
|
67
|
+
: commands);
|
|
68
|
+
const result = reference.map((_, instructionIndex) => {
|
|
69
|
+
var _a;
|
|
70
|
+
const commands = extendedPaths.map((path) => path[instructionIndex]);
|
|
71
|
+
if (commands.some((command) => command.type === 'Z')) {
|
|
72
|
+
if (commands.every((command) => command.type === 'Z')) {
|
|
73
|
+
return { type: 'Z' };
|
|
74
|
+
}
|
|
75
|
+
throw new TypeError('Cannot interpolate SVG paths with different subpath structures');
|
|
76
|
+
}
|
|
77
|
+
// A common cubic command preserves every curve while allowing paths with
|
|
78
|
+
// different instruction types to share the same coordinate interpolation.
|
|
79
|
+
const target = (_a = commands.find((command) => command.type === 'C')) !== null && _a !== void 0 ? _a : commands[0];
|
|
80
|
+
const normalized = commands.map((command, pathIndex) => {
|
|
81
|
+
if ((command.type === 'M') !== (target.type === 'M')) {
|
|
82
|
+
throw new TypeError('Cannot interpolate SVG paths with different subpath structures');
|
|
83
|
+
}
|
|
84
|
+
return (0, convert_to_same_instruction_type_1.convertToSameInstructionType)(command, target, (0, get_end_position_1.getEndPosition)(extendedPaths[pathIndex].slice(0, instructionIndex)));
|
|
85
|
+
});
|
|
86
|
+
const coordinates = normalized.map((command) => {
|
|
87
|
+
if (command.type === 'Z') {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
return command.type === 'C'
|
|
91
|
+
? [
|
|
92
|
+
command.x,
|
|
93
|
+
command.y,
|
|
94
|
+
command.cp1x,
|
|
95
|
+
command.cp1y,
|
|
96
|
+
command.cp2x,
|
|
97
|
+
command.cp2y,
|
|
98
|
+
]
|
|
99
|
+
: [command.x, command.y];
|
|
100
|
+
});
|
|
101
|
+
const values = coordinates[0].map((base, coordinateIndex) => {
|
|
102
|
+
const interpolated = coordinates.reduce((value, path, pathIndex) => value +
|
|
103
|
+
(path[coordinateIndex] - base) * contributingPaths[pathIndex].weight, base);
|
|
104
|
+
if (Number.isFinite(interpolated)) {
|
|
105
|
+
return interpolated;
|
|
106
|
+
}
|
|
107
|
+
// Opposite large coordinates can overflow when subtracting the base.
|
|
108
|
+
return coordinates.reduce((sum, path, pathIndex) => sum + path[coordinateIndex] * contributingPaths[pathIndex].weight, 0);
|
|
109
|
+
});
|
|
110
|
+
if (target.type === 'C') {
|
|
111
|
+
return {
|
|
112
|
+
type: 'C',
|
|
113
|
+
x: values[0],
|
|
114
|
+
y: values[1],
|
|
115
|
+
cp1x: values[2],
|
|
116
|
+
cp1y: values[3],
|
|
117
|
+
cp2x: values[4],
|
|
118
|
+
cp2y: values[5],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return { type: target.type, x: values[0], y: values[1] };
|
|
122
|
+
});
|
|
123
|
+
if (closed) {
|
|
124
|
+
result.push({ type: 'Z' });
|
|
125
|
+
}
|
|
126
|
+
return normalizeInterpolatedPath((0, serialize_instructions_1.serializeInstructions)(result));
|
|
127
|
+
};
|
|
128
|
+
exports.interpolatePaths = interpolatePaths;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/paths"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/paths",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.530",
|
|
7
7
|
"description": "Utilities for working with SVG paths",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
@@ -26,10 +26,13 @@
|
|
|
26
26
|
"utilities"
|
|
27
27
|
],
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
29
|
+
"@remotion/eslint-config-internal": "4.0.530",
|
|
30
30
|
"eslint": "9.19.0",
|
|
31
31
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|
|
32
32
|
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"remotion": "4.0.530"
|
|
35
|
+
},
|
|
33
36
|
"exports": {
|
|
34
37
|
"./package.json": "./package.json",
|
|
35
38
|
".": {
|