From 40a62557e8dbf5380a345204ac17d6b28cac07b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Wi=C5=9Bniewski?= Date: Fri, 5 Dec 2025 15:32:46 +0100 Subject: [PATCH 1/3] Implement SVG Path interpolation and examples --- .../src/apps/css/examples/animations/routes/properties/svg.ts | 4 ++++ .../animations/screens/animatedProperties/svg/index.ts | 2 ++ .../Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp | 4 +++- .../cpp/reanimated/CSS/common/values/CSSValueVariant.cpp | 2 ++ .../CSS/interpolation/values/SimpleValueInterpolator.cpp | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/common-app/src/apps/css/examples/animations/routes/properties/svg.ts b/apps/common-app/src/apps/css/examples/animations/routes/properties/svg.ts index 5a98fe61e07b..fc4d1611f9e0 100644 --- a/apps/common-app/src/apps/css/examples/animations/routes/properties/svg.ts +++ b/apps/common-app/src/apps/css/examples/animations/routes/properties/svg.ts @@ -18,6 +18,10 @@ export const svgPropertiesRoutes = { name: 'Line', Component: svgAnimatedProperties.Line, }, + Path: { + name: 'Path', + Component: svgAnimatedProperties.Path, + }, Common: { name: 'Common', routes: { diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/index.ts b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/index.ts index 80f34c066e8b..62cae39d72d1 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/index.ts +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/index.ts @@ -3,11 +3,13 @@ import common from './common'; import Ellipse from './Ellipse'; import Line from './Line'; import Rect from './Rect'; +import Path from './Path'; export default { Circle, Ellipse, Line, + Path, common, Rect, }; diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp index 95ff691911a9..b1ef6393ea1e 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -339,7 +340,8 @@ const InterpolatorFactoriesRecord SVG_RECT_INTERPOLATORS = mergeInterpolators( const InterpolatorFactoriesRecord SVG_PATH_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - // TODO - add more properties + {"d", value("")}, + {"opacity", value(1)}, }}); // ================== diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp index b0b80f407f60..8e63893c893f 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -168,6 +169,7 @@ template class CSSValueVariant>; template class CSSValueVariant; template class CSSValueVariant; +template class CSSValueVariant; template class CSSValueVariant; template class CSSValueVariant; diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp index 2e868ccc2784..86c0e3d57bb3 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ template class SimpleValueInterpolator>; template class SimpleValueInterpolator; template class SimpleValueInterpolator; +template class SimpleValueInterpolator; template class SimpleValueInterpolator; template class SimpleValueInterpolator; From 52d1b5a4595576039d360198cbfc2237958e1201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Wi=C5=9Bniewski?= Date: Fri, 5 Dec 2025 15:35:27 +0100 Subject: [PATCH 2/3] Add missing files --- .../screens/animatedProperties/svg/Path.tsx | 278 +++++++++++++++++ .../cpp/reanimated/CSS/svg/values/SVGPath.cpp | 281 ++++++++++++++++++ .../cpp/reanimated/CSS/svg/values/SVGPath.h | 65 ++++ 3 files changed, 624 insertions(+) create mode 100644 apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx create mode 100644 packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.cpp create mode 100644 packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.h diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx new file mode 100644 index 000000000000..11d2818f20f7 --- /dev/null +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx @@ -0,0 +1,278 @@ +import Animated, { type CSSAnimationKeyframes } from 'react-native-reanimated'; +// TODO: Fix me +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 +import { Path, type PathProps, Svg } from 'react-native-svg'; + +import { ExamplesScreen } from '@/apps/css/components'; + +const AnimatedPath = Animated.createAnimatedComponent(Path); + +export default function PathExample() { + return ( + ; viewBox?: string }, + PathProps + > + buildAnimation={({ keyframes }) => ({ + animationName: keyframes, + animationDirection: 'alternate', + animationDuration: '1s', + animationIterationCount: 'infinite', + animationTimingFunction: 'ease-in-out', + })} + renderExample={({ animation, viewBox }) => ( + + + + )} + tabs={[ + { + name: 'Paths with the same number of points', + sections: [ + { + examples: [ + { + keyframes: { + from: { + d: 'M2,2 L8,8', + }, + to: { + d: 'M8,2 L2,8', + }, + }, + title: 'Line', + }, + { + keyframes: { + from: { + d: 'M2,8 L5,2 L8,8', + }, + to: { + d: 'M2,2 L5,8 L8,2', + }, + }, + title: 'Polygonal chain', + }, + { + keyframes: { + from: { + d: 'M2,2 Q8,2 8,8', + }, + to: { + d: 'M2,2 Q2,8 8,8', + }, + }, + title: 'Quadratic Bézier curve', + }, + { + keyframes: { + from: { + d: 'M2,5 C2,8 8,8 8,5', + }, + to: { + d: 'M2,5 C2,2 8,2 8,5', + }, + }, + title: 'Cubic Bézier curve', + }, + { + keyframes: { + from: { + d: 'M2,2 L8,2 L2,5 L8,5 L2,8 L8,8', + }, + to: { + d: 'M3,3 L8,3 L2,5 L8,5 L3,7 L7,7', + }, + }, + title: 'Zigzag', + }, + { + keyframes: { + from: { + d: 'M2,5 A 5 25 0 0 1 8 8', + }, + to: { + d: 'M2,5 A 5 25 -15 0 1 8 8', + }, + }, + title: 'Arch', + }, + { + keyframes: { + from: { + d: 'M2,5 S2,-2 4,5 S7,8 8,4', + }, + to: { + d: 'M2,5 S2,14 4,5 S7,8 8,4', + }, + }, + title: 'Smooth Cubic Bézier curve', + }, + { + keyframes: { + from: { + d: 'M5,2 Q 2,5 5,8', + }, + to: { + d: 'M5,2 Q 8,5 5,8', + }, + }, + title: 'Quadratic Bézier curve 2', + }, + { + keyframes: { + from: { + d: 'M2,2 Q5,2 5,5 T8,8', + }, + to: { + d: 'M2,2 Q8,2 5,5 T8,8', + }, + }, + title: 'Smooth Quadratic Bézier curve', + }, + ], + title: 'Paths with the same number of points', + }, + ], + }, + { + name: 'Open paths with differing number of points', + renderExample: ({ animation, viewBox }) => ( + + + + ), + sections: [ + { + examples: [ + { + viewBox: '-5 2 32 20', + keyframes: { + from: { + d: 'M19 7.11111C17.775 5.21864,15.8556 4,13.6979 4C9.99875 4,7 7.58172,7 12C7 16.4183,9.99875 20,13.6979 20C15.8556 20,17.775 18.7814,19 16.8889 M5 10C6 10,7 10,8 10C9 10,10 10,11 10C12 10,13 10,14 10 M5 14C6 14,7 14,8 14C9 14,10 14,11 14C12 14,13 14,14 14', + stroke: '#b7b41aff', + }, + to: { + d: 'M12 3C12 4.5,12 6,12 7.5C12 9,12 10.5,12 12C12 13.5,12 15,12 16.5C12 18,12 19.5,12 21 M15.679 6.63439C14.063 4.2691,7.94541 4.02196,7.94541 8.16745C7.94541 12.3129,16.7524 10.33,16.2439 15.2118C15.8199 19.2823,9.19299 19.3384,7.21094 16.0891 M15.679 6.63439C14.063 4.2691,7.94541 4.02196,7.94541 8.16745C7.94541 12.3129,16.7524 10.33,16.2439 15.2118C15.8199 19.2823,9.19299 19.3384,7.21094 16.0891', + stroke: '#3B8C4F', + }, + }, + title: 'Cash', + }, + { + keyframes: { + from: { + d: 'M2 2C3 3,4 4,5 5C6 6,7 7,8 8 M8 2C7 3,6 4,5 5C4 6,3 7,2 8', + stroke: '#e71515ff', + }, + to: { + d: 'M4 6C4.333333333333333 6.333333333333333,4.666666666666667 6.666666666666667,5 7C6 5.333333333333334,7 3.666666666666667,8 2', + stroke: '#06c034ff', + }, + }, + title: 'Cash', + }, + ], + title: 'Open paths with differing number of points', + }, + ], + }, + { + name: 'Closed paths with differing number of points', + renderExample: ({ animation, viewBox }) => ( + + + + ), + sections: [ + { + examples: [ + { + viewBox: '-150 0 780 500', + keyframes: { + from: { + d: 'M445.898 83.886C408.6635 83.886,368.48775 106.35074999999999,335.894 131.467875C303.30025 156.58499999999998,278.28850000000006 184.3545,271.38200000000006 194.964C269.58500000000004 192.675,267.30775000000006 190.78050000000002,264.69650000000007 189.45825000000002C262.0852500000001 188.136,259.1400000000001 187.386,256.00700000000006 187.386C252.86650000000006 187.386,249.91725000000008 188.136,247.30387500000006 189.45825000000002C244.69050000000007 190.78050000000002,242.41300000000007 192.675,240.61600000000007 194.964C233.71050000000002 184.34699999999998,208.699 156.5775,176.105375 131.46224999999998C143.51175 106.347,103.336 83.886,66.102 83.886C27.688000000000002 83.886,10.051250000000003 101.132,3.3891250000000035 123.866375C-3.272999999999996 146.60075,1.0395000000000039 174.8235,6.524000000000001 196.777C12.008500000000002 218.738,26.12175 241.867,45.133375 259.703C64.14500000000001 277.539,88.055 290.082,113.133 290.871C84.91399999999999 303.40999999999997,69.62875 325.75374999999997,63.55449999999999 348.68537499999996C57.48024999999999 371.61699999999996,60.61699999999999 395.13649999999996,69.24199999999999 410.027C77.4215 424.152,103.238 447.15599999999995,134.99587499999998 448.83975C166.75374999999997 450.5235,204.45299999999997 430.887,236.398 359.731C236.398 364.5878333333333,236.398 369.44466666666665,236.398 374.30150000000003C236.398 379.15833333333336,236.398 384.0151666666667,236.398 388.872C236.398 394.2785,238.59325 399.17675,242.142 402.72337500000003C245.69075 406.27000000000004,250.59300000000002 408.46500000000003,256.007 408.46500000000003C261.4135 408.46500000000003,266.312 406.26975000000004,269.858875 402.72300000000007C273.40575 399.17625000000004,275.601 394.278,275.601 388.872C275.601 384.0126666666667,275.601 379.1533333333333,275.601 374.294C275.601 369.43466666666666,275.601 364.57533333333333,275.601 359.716C307.54650000000004 430.88,345.24975 450.52049999999997,377.0095 448.83875C408.76925 447.15700000000004,434.5855 424.153,442.757 410.028C451.382 395.13750000000005,454.51875 371.61800000000005,448.44450000000006 348.68637500000006C442.37025000000006 325.75475000000006,427.08500000000004 303.41100000000006,398.866 290.872C423.952 290.083,447.86225 277.54,466.872 259.704C485.88175 241.86800000000002,499.991 218.73900000000003,505.47499999999997 196.77800000000002C507.669 187.99660000000003,509.67548 178.21208000000001,510.867056 168.17694400000002C512.058632 158.14180800000003,512.435304 147.85605600000002,511.369688 138.07219200000003C510.304072 128.28832800000004,507.796168 119.00635200000002,503.218592 110.97876800000002C498.64101600000004 102.95118400000001,491.99376800000005 96.177992,482.6494640000001 91.411696C473.30516000000006 86.6454,461.26380000000006 83.886,445.898 83.886Z', + }, + to: { + d: 'M489.135 21.728C476.51 21.728,466.26 31.978,466.26 44.603C466.26 51.978,469.776 58.525000000000006,475.21299999999997 62.712C472.979 67.931,470.21299999999997 73.99300000000001,466.86899999999997 80.72800000000001C460.931 92.61900000000001,453.166 106.54100000000001,443.306 121.30600000000001C438.556 118.72800000000001,433.38399999999996 116.83700000000002,427.91499999999996 115.83700000000002C427.087 97.52400000000002,424.69599999999997 78.64900000000002,422.306 63.32100000000002C421.712 59.493000000000016,421.118 55.88300000000002,420.53999999999996 52.55500000000002C427.837 48.72700000000002,432.837 41.10200000000002,432.837 32.28900000000002C432.837 19.664000000000023,422.587 9.414000000000023,409.962 9.414000000000023C397.32099999999997 9.414000000000023,387.087 19.664000000000023,387.087 32.28900000000002C387.087 44.102000000000025,396.056 53.83600000000003,407.57099999999997 55.03900000000002C408.212 58.727000000000025,408.868 62.78900000000002,409.52399999999994 67.10200000000002C411.7269999999999 81.41500000000002,413.8519999999999 98.63300000000001,414.64899999999994 115.14900000000002C399.44599999999997 116.29000000000002,386.1329999999999 124.00800000000001,377.46099999999996 135.383C360.508 91.33600000000001,319.852 58.07000000000001,272.27299999999997 52.742000000000004C203.11699999999996 44.992000000000004,141.17899999999997 98.539,133.91399999999996 172.351C131.22599999999997 199.679,136.42999999999995 225.945,147.53899999999996 248.58499999999998C107.56999999999996 253.319,74.64799999999995 287.179,70.27299999999995 331.616C65.24199999999995 382.897,100.36699999999996 426.554,148.13199999999995 434.21C169.38199999999995 437.601,190.14799999999994 435.03799999999995,210.03799999999995 428.085C199.92899999999995 435.94399999999996,189.41299999999995 443.46,178.49099999999996 450.476C165.34999999999997 458.929,161.53799999999995 476.429,169.99099999999996 489.585C178.44399999999996 502.726,195.94399999999996 506.53799999999995,209.08499999999995 498.085C244.75699999999995 475.147,276.054 448.179,303.14799999999997 420.101C343.81999999999994 377.945,375.101 333.257,397.50699999999995 295.163C408.7099999999999 276.1,417.69499999999994 258.67900000000003,424.52299999999997 243.913C427.929 236.538,430.82 229.81900000000002,433.164 223.804C434.383 220.741,435.445 217.866,436.39799999999997 215.163C456.52299999999997 207.757,470.71099999999996 188.22500000000002,470.226 165.56900000000002C469.913 151.14700000000002,463.71 138.241,453.992 129.06900000000002C464.492 113.38100000000001,472.726 98.61600000000001,478.961 86.05300000000003C482.414 79.08400000000003,485.25800000000004 72.80300000000003,487.555 67.38100000000003C488.086 67.42800000000003,488.60200000000003 67.45900000000003,489.133 67.45900000000003C501.758 67.45900000000003,511.99199999999996 57.22500000000003,511.99199999999996 44.60000000000003C511.99199999999996 31.97500000000003,501.76 21.728,489.135 21.728Z', + }, + }, + title: 'Butterfly', + }, + { + viewBox: '0 0 100 100', + keyframes: { + from: { + d: 'M55 25C61.666666666666664 25,68.33333333333333 25,75 25C75 41.666666666666664,75 58.33333333333333,75 75C68.33333333333333 75,61.66666666666667 75,55 75Z M25 25C31.666666666666664 25,38.33333333333333 25,45 25C45 41.666666666666664,45 58.33333333333333,45 75C38.333333333333336 75,31.666666666666668 75,25 75Z', + }, + to: { + d: 'M30 25C45 33.33333333333333,60 41.666666666666664,75 50C60 58.33333333333333,45 66.66666666666666,30 75C30 58.333333333333336,30 41.66666666666667,30 25Z', + }, + }, + title: 'Pause', + }, + { + viewBox: '0 0 515 330', + keyframes: { + from: { + d: 'M143.1252 82.2198C143.4904 78.3354,146.5282 75.18140000000001,150.479 74.74980000000001C154.67880000000002 74.28500000000001,158.56320000000002 77.05720000000001,159.49280000000002 81.1906C165.76760000000002 109.3276,186.75000000000003 136.6014,218.5224 131.0238C223.9838 130.061,229.3788 127.32199999999999,233.5786 123.753C246.4934 112.7804,253.316 96.9108,257.5822 80.8752C258.6446 76.84140000000001,262.5456 74.2352,266.679 74.7664C270.61319999999995 75.281,273.60119999999995 78.5014,273.8834 82.41900000000001C280.3574 110.27380000000001,301.2568 137.0164,332.7304 131.472C338.2084 130.50920000000002,343.5868 127.7702,347.78659999999996 124.20120000000001C360.7014 113.24520000000001,367.5406 97.35900000000001,371.79019999999997 81.32340000000002C372.76959999999997 77.63820000000003,376.15599999999995 75.08180000000002,379.974 75.16480000000001C383.8086 75.23120000000002,387.0788 77.92040000000001,387.9088 81.65540000000001C394.2002 109.79240000000001,415.1826 137.0662,446.9384 131.472C452.4164 130.50920000000002,457.7948 127.7702,461.9946 124.20120000000001C474.9094 113.24520000000001,481.7486 97.35900000000001,485.9982 81.32340000000002C487.1768 76.90780000000002,491.7252 74.26840000000001,496.1574 75.43040000000002C500.5896 76.60900000000002,503.229 81.15740000000002,502.05039999999997 85.58960000000002C496.9376 104.86220000000002,488.27239999999995 123.68660000000003,472.7514 136.86700000000002C466.36039999999997 142.2786,458.1434 146.36220000000003,449.8268 147.823C417.573 153.5002,392.8888 134.2442,379.808 108.09920000000001C374.7118 118.97220000000002,367.8726 128.93220000000002,358.5268 136.86700000000002C352.1524 142.2786,343.9188 146.36220000000003,335.6022 147.823C303.2654 153.51680000000002,278.548 134.12800000000001,265.4838 107.86680000000001C260.40419999999995 118.6568,253.58159999999998 128.5338,244.31879999999998 136.40220000000002C237.94439999999997 141.83040000000003,229.71079999999998 145.89740000000003,221.39419999999998 147.37480000000002C189.22339999999997 153.0354,164.60559999999998 133.89560000000003,151.49159999999998 107.86680000000001C146.39539999999997 118.82280000000002,139.50639999999999 128.88240000000002,130.11079999999998 136.86700000000002C123.71979999999998 142.2786,115.50279999999998 146.36220000000003,107.18619999999999 147.823C66.03479999999999 155.0606,37.21719999999999 121.7278,29.06659999999998 85.27420000000001C28.07059999999998 80.79220000000001,30.89259999999998 76.36000000000001,35.35799999999998 75.364C39.83999999999998 74.3514,44.272199999999984 77.1734,45.26819999999998 81.6554C51.55959999999998 109.7924,72.54199999999997 137.0662,104.29779999999998 131.472C109.77579999999998 130.50920000000002,115.15419999999997 127.7702,119.35399999999998 124.20120000000001C132.0364 113.44440000000002,138.8424 97.95660000000001,143.12519999999998 82.21980000000002C143.12519999999998 82.21980000000002,143.1252 82.2198,143.1252 82.2198Z', + }, + to: { + d: 'M471 79.483C458.788 72.932,448.304 63.509,440.466 52.144000000000005C435.86733333333336 45.47733333333334,431.26866666666666 38.81066666666668,426.67 32.144000000000005C422.071 38.81066666666667,417.472 45.477333333333334,412.873 52.144000000000005C405.034 63.50900000000001,394.543 72.932,382.331 79.483C370.119 86.043,356.221 89.754,341.331 89.763C326.44100000000003 89.754,312.55100000000004 86.043,300.331 79.483C288.127 72.932,277.637 63.509,269.797 52.144000000000005C265.1983333333334 45.47733333333334,260.5996666666667 38.81066666666668,256.00100000000003 32.144000000000005C251.40200000000004 38.81066666666667,246.80300000000003 45.477333333333334,242.20400000000004 52.144000000000005C234.36500000000004 63.50900000000001,223.87400000000002 72.932,211.67100000000005 79.483C199.45100000000005 86.043,185.56100000000004 89.754,170.67100000000005 89.763C155.78100000000006 89.754,141.88300000000004 86.043,129.67100000000005 79.483C117.45900000000005 72.932,106.96800000000005 63.509,99.12800000000004 52.144000000000005C94.52933333333338 45.47733333333334,89.93066666666671 38.81066666666668,85.33200000000005 32.144000000000005C80.73333333333339 38.81066666666667,76.13466666666672 45.477333333333334,71.53600000000006 52.144000000000005C63.694 63.509,53.212 72.932,41 79.483C28.788 86.043,14.89 89.754,0 89.763C0 100.93533333333333,0 112.10766666666666,0 123.28C20.509 123.289,39.94 118.119,56.864 109.017C67.398 103.357,76.983 96.178,85.33 87.78099999999999C93.68599999999999 96.17899999999999,103.262 103.357,113.79599999999999 109.017C130.72799999999998 118.119,150.152 123.289,170.66899999999998 123.28C191.177 123.289,210.601 118.119,227.533 109.017C238.06699999999998 103.357,247.652 96.178,255.999 87.78099999999999C264.346 96.17899999999999,273.931 103.357,284.465 109.017C301.397 118.119,320.82 123.289,341.32899999999995 123.28C361.84599999999995 123.289,381.26899999999995 118.119,398.20199999999994 109.017C408.73599999999993 103.357,418.31199999999995 96.178,426.66799999999995 87.78099999999999C435.01499999999993 96.17899999999999,444.59999999999997 103.357,455.13399999999996 109.017C472.05799999999994 118.119,491.489 123.289,511.99799999999993 123.28C511.99799999999993 112.10766666666667,511.99799999999993 100.93533333333335,511.99799999999993 89.763C508.27599999999995 89.76075,504.61587499999996 89.527125,501.02849999999995 89.075453125C497.44112499999994 88.62378125,493.9265 87.95406249999999,490.4955 87.079625C487.06449999999995 86.2051875,483.71712499999995 85.12603125,480.46425 83.855484375C477.211375 82.5849375,474.053 81.123,471 79.483Z', + }, + }, + title: 'Filled wave', + }, + { + viewBox: '-100 28 705 460', + keyframes: { + from: { + d: 'M43.875 301.17C46.292 292.41900000000004,49.167 284.79200000000003,52.5 278.291C55.833 271.79,59.125 265.372,62.375 259.038C65.625 252.704,68.458 245.578,70.875 237.66000000000003C73.292 229.74200000000002,74.667 221.44800000000004,75 212.78000000000003C75.5 198.44500000000002,70.917 189.11,61.25 184.77600000000004C50.657 178.36300000000003,39.034 174.48600000000005,27.394 170.60300000000004C18.101999999999997 167.50300000000004,8.799 164.40000000000003,0 160.00000000000003C6.021 154.67300000000003,11.93 149.02000000000004,17.862 143.34600000000003C27.721999999999998 133.91500000000002,37.644999999999996 124.42300000000003,48.25 116.26400000000004C37.917 109.43000000000004,32.75 99.67800000000004,32.75 87.00900000000004C32.75 77.84100000000004,36.333 69.79800000000004,43.5 62.88000000000004C50.667 55.96200000000004,58.417 52.503000000000036,66.75 52.503000000000036C73.917 52.503000000000036,80.5 55.37900000000003,86.5 61.13000000000004C92.5 66.88100000000004,97.25 73.25700000000003,100.75 80.25800000000004C99.583 72.42300000000004,99.5 65.13100000000004,100.5 58.37900000000003C101.5 51.628000000000036,104.542 45.54400000000003,109.625 40.12600000000003C114.708 34.70900000000003,121.833 32.000000000000036,131 32.000000000000036C140.333 32.000000000000036,148.333 35.37600000000003,155 42.12700000000004C161.667 48.878000000000036,165 57.08700000000004,165 66.75600000000004C165 74.59000000000005,162.583 81.75800000000004,157.75 88.25900000000004C159.083 88.42600000000004,160.333 88.67600000000004,161.5 89.01000000000005C162.667 89.34300000000005,163.667 89.63500000000005,164.5 89.88500000000005C165.333 90.13500000000005,166.25 90.59300000000005,167.25 91.26000000000005C168.25 91.92700000000005,169.042 92.38500000000005,169.625 92.63500000000005C170.208 92.88500000000005,170.958 93.55200000000005,171.875 94.63500000000005C172.792 95.71900000000005,173.417 96.38600000000005,173.75 96.63600000000005C174.083 96.88600000000005,174.792 97.76100000000005,175.875 99.26100000000005C176.958 100.76200000000006,177.625 101.72000000000006,177.875 102.13700000000006C178.125 102.55400000000006,178.875 103.72000000000006,180.125 105.63700000000006C181.375 107.55400000000006,182.167 108.76300000000006,182.5 109.26300000000006C187.5 116.59800000000006,192.208 127.59900000000006,196.625 142.26800000000006C201.042 156.93800000000005,204.792 171.14800000000005,207.875 184.90100000000007C210.958 198.65300000000008,213.083 206.86300000000006,214.25 209.53000000000006C223.75 217.69800000000006,234.042 224.57400000000007,245.125 230.15800000000007C256.208 235.74300000000008,266.41700000000003 238.61800000000008,275.75 238.78500000000008C286.25 238.95100000000008,297.54200000000003 235.90900000000008,309.625 229.65800000000007C321.708 223.40700000000007,333.04200000000003 215.53100000000006,343.625 206.02900000000008C354.208 196.52800000000008,364.45799999999997 185.9420000000001,374.375 174.2740000000001C384.292 162.60500000000008,392.79200000000003 151.5200000000001,399.875 141.0180000000001C406.958 130.51700000000008,412.583 121.01500000000009,416.75 112.51400000000008C419.25 119.51500000000009,421.25 125.80700000000007,422.75 131.39200000000008C424.25 136.97600000000008,425.417 144.3110000000001,426.25 153.3950000000001C427.083 162.4800000000001,426.792 170.6900000000001,425.375 178.0250000000001C423.958 185.3590000000001,420.75 193.1520000000001,415.75 201.40300000000008C410.75 209.6550000000001,403.833 216.8640000000001,395 223.03200000000007C395.333 223.36500000000007,397.583 223.65700000000007,401.75 223.90700000000007C405.917 224.15700000000007,410.292 224.65700000000007,414.875 225.40700000000007C419.458 226.15800000000007,424.333 228.70000000000007,429.5 233.03400000000008C434.667 237.36800000000008,438.5 243.28500000000008,441 250.7870000000001C432.167 250.7870000000001,424.33299999999997 253.4950000000001,417.5 258.91300000000007C410.667 264.3310000000001,406.333 269.87300000000005,404.5 275.54100000000005C410.333 274.20700000000005,418.25 276.333,428.25 281.91700000000003C438.25 287.50100000000003,444.83299999999997 294.961,448 304.29600000000005C440.5 304.96200000000005,434.583 307.54600000000005,430.25 312.047C425.917 316.548,421.583 324.54900000000004,417.25 336.05100000000004C411.583 351.38700000000006,402.625 363.97200000000004,390.375 373.807C378.125 383.642,364.58299999999997 390.14300000000003,349.75 393.31100000000004C334.917 396.478,319.16700000000003 397.56100000000004,302.5 396.56100000000004C285.83299999999997 395.56100000000004,270.125 392.56000000000006,255.375 387.56000000000006C240.625 382.5590000000001,227.333 376.09900000000005,215.5 368.18100000000004C203.667 360.26300000000003,195 351.63700000000006,189.5 342.302C201.167 369.307,218.083 390.35200000000003,240.25 405.43800000000005C262.41700000000003 420.523,285.75 428.15000000000003,310.25 428.31600000000003C328.25 428.483,346.33299999999997 422.81600000000003,364.5 411.314C359.333 423.149,351.125 433.692,339.875 442.944C328.625 452.195,316.375 459.322,303.125 464.32300000000004C289.875 469.32300000000004,277.25 473.074,265.25 475.574C253.25 478.075,242.333 479.492,232.5 479.825C170.667 481.659,122.75 469.073,88.75 442.06899999999996C54.75 415.06399999999996,38.417 377.47499999999997,39.75 329.29999999999995C40.083 319.29799999999994,41.458 309.92199999999997,43.875 301.16999999999996C43.875 301.16999999999996,43.875 301.17,43.875 301.17Z', + }, + to: { + d: 'M576 288C576 283.4437142857143,573.660918367347 276.92391836734697,569.238862973761 269.0946005830904C564.816807580175 261.2652827988339,558.311778425656 252.1264431486881,549.9798833819242 242.33206997084554C541.6479883381924 232.53769679300297,531.4892274052478 222.0877900874636,519.7597084548105 211.63633819241986C508.0301895043732 201.18488629737612,494.7299125364432 190.731889212828,480.1149854227406 180.93133527696796C465.5000583090379 171.13078134110788,449.57048104956266 161.98267055393586,432.58236151603495 154.1409912536443C415.59424198250724 146.29931195335274,397.5475801749271 139.76406413994167,378.6984839650146 135.1892361516035C359.84938775510204 130.6144081632653,340.1978571428572 128,320 128C309.09985714285716 128,298.026306122449 129.08363265306122,286.9146064139942 131.06636734693876C275.8029067055394 133.0491020408163,264.65305830903793 135.93093877551019,253.60032069970848 139.52734693877548C242.54758309037902 143.12375510204078,231.5919562682216 147.43473469387752,220.86869970845484 152.2757551020408C210.14544314868806 157.11677551020406,199.65455685131195 162.48783673469387,189.5313002915452 168.2044081632653C179.40804373177843 173.92097959183673,169.652416909621 179.9830612244898,160.39967930029155 186.20612244897958C151.1469416909621 192.42918367346937,142.39709329446066 198.8132244897959,134.28539358600585 205.17371428571428C126.17369387755105 211.53420408163265,118.70014285714288 217.87114285714284,112 224C108.95242857142857 220.97614285714286,105.37763265306123 217.67338775510206,101.45491545189505 214.20980758017495C97.53219825072887 210.74622740524785,93.26155976676385 207.12182215743442,88.82230320699709 203.4546647230321C84.38304664723033 199.78750728862977,79.77517201166182 196.0775976676385,75.17798250728865 192.4430087463557C70.58079300291547 188.8084198250729,65.99428862973762 185.24915160349855,61.5977725947522 181.88327696793004C57.201256559766776 178.5174023323615,52.99472886297377 175.34492128279882,49.157492711370274 172.48390670553934C45.320256559766776 169.6228921282799,41.852311953352775 167.0733440233236,38.93296209912536 164.95333527696795C36.013612244897956 162.83332653061225,33.64285714285714 161.14285714285717,32 160C30.498142857142856 158.9552857142857,28.772326530612244 158.23967346938775,26.917189504373177 157.82272886297375C25.06205247813411 157.40578425655974,23.077594752186588 157.2875072886297,21.058454810495626 157.4374635568513C19.039314868804663 157.58741982507289,16.98549271137026 158.00560932944606,14.991626822157432 158.6615976676385C12.997760932944605 159.31758600583092,11.063851311953352 160.21137317784257,9.284536443148687 161.31252478134112C7.505221574344023 162.41367638483968,5.880501457725947 163.7221924198251,4.505014577259475 165.20763848396504C3.129527696793003 166.693084548105,2.003274052478134 168.35546064139945,1.2208921282798832 170.16433236151607C0.4385102040816326 171.97320408163267,0 173.92857142857144,0 176C0 177.65714285714284,0.43536734693877543 180.46326530612242,1.212810495626822 184.15102040816325C1.9902536443148686 187.83877551020407,3.109772594752186 192.40816326530611,4.47807580174927 197.59183673469386C5.8463790087463545 202.77551020408163,7.463466472303206 208.5734693877551,9.236046647230319 214.71836734693878C11.008626822157433 220.86326530612246,12.936699708454809 227.35510204081635,14.926973760932942 233.9265306122449C16.917247813411077 240.4979591836735,18.969723032069968 247.14897959183676,20.991107871720114 253.61224489795921C23.012492711370257 260.07551020408164,25.002787172011658 266.35102040816327,26.868699708454805 272.1714285714286C28.734612244897956 277.9918367346939,30.476142857142854 283.3571428571429,32 288C30.476142857142857 292.64285714285717,28.73461224489796 298.00816326530617,26.868699708454812 303.8285714285715C25.002787172011665 309.6489795918368,23.012492711370264 315.9244897959184,20.991107871720118 322.38775510204084C18.96972303206997 328.85102040816327,16.91724781341108 335.50204081632654,14.926973760932945 342.0734693877551C12.936699708454812 348.64489795918365,11.008626822157435 355.13673469387754,9.23604664723032 361.2816326530612C7.463466472303208 367.42653061224485,5.846379008746356 373.2244897959183,4.478075801749272 378.4081632653061C3.1097725947521875 383.59183673469386,1.9902536443148695 388.16122448979587,1.2128104956268226 391.8489795918367C0.43536734693877566 395.5367346938775,0 398.34285714285716,0 400C0 402.07142857142856,0.43851020408163255 404.0267959183673,1.2208921282798832 405.8356676384839C2.003274052478134 407.6445393586006,3.129527696793003 409.30691545189507,4.505014577259475 410.792361516035C5.880501457725947 412.2778075801749,7.505221574344023 413.5863236151603,9.284536443148689 414.68747521865885C11.063851311953353 415.7886268221574,12.997760932944608 416.6824139941691,14.991626822157436 417.3384023323615C16.985492711370263 417.9943906705539,19.039314868804667 418.4125801749271,21.05845481049563 418.56253644314864C23.07759475218659 418.71249271137026,25.062052478134113 418.5942157434402,26.91718950437318 418.1772711370262C28.772326530612247 417.7603265306122,30.49814285714286 417.04471428571424,32 416C33.642857142857146 414.85714285714283,36.01361224489796 413.1666734693877,38.93296209912537 411.04666472303205C41.852311953352775 408.9266559766764,45.32025655976677 406.3771078717201,49.15749271137027 403.51609329446063C52.994728862973766 400.65507871720115,57.20125655976677 397.48259766763846,61.59777259475219 394.11672303206996C65.99428862973761 390.75084839650145,70.58079300291546 387.19158017492714,75.17798250728863 383.55699125364436C79.77517201166181 379.92240233236157,84.38304664723033 376.2124927113703,88.82230320699709 372.545335276968C93.26155976676387 368.87817784256566,97.53219825072888 365.25377259475226,101.45491545189506 361.79019241982513C105.37763265306124 358.326612244898,108.95242857142858 355.0238571428572,112 352C118.70014285714286 358.12885714285716,126.17369387755103 364.46579591836735,134.28539358600585 370.8262857142857C142.39709329446066 377.18677551020403,151.1469416909621 383.5708163265306,160.39967930029155 389.7938775510204C169.652416909621 396.0169387755102,179.40804373177843 402.0790204081633,189.5313002915452 407.79559183673473C199.65455685131195 413.5121632653062,210.14544314868806 418.88322448979596,220.8686997084548 423.72424489795924C231.59195626822157 428.5652653061225,242.547583090379 432.8762448979592,253.60032069970845 436.4726530612245C264.6530583090379 440.0690612244898,275.8029067055393 442.9508979591837,286.91460641399414 444.93363265306124C298.02630612244894 446.9163673469388,309.0998571428571 448,320 448C335.70944444444444 448,351.0883950617284 446.41844444444445,366.01635116598084 443.56303978052125C380.94430727023325 440.70763511659806,395.4212688614541 436.5783813443072,409.3267352537723 431.4829849108367C423.2322016460906 426.3875884773662,436.5661728395062 420.326049382716,449.20814814814815 413.60607407407406C461.85012345679013 406.88609876543205,473.8001028806584 399.5076872427983,484.93758573388203 391.7785459533607C496.07506858710565 384.04940466392316,506.40005486968454 375.96953360768174,515.7920438957476 367.8466392318244C525.1840329218107 359.723744855967,533.643024691358 351.5578271604938,541.0485185185186 343.6565925925926C548.4540123456791 335.7553580246913,554.8060082304527 328.11880658436206,559.9840054869685 321.0546447187928C565.1620027434842 313.9904828532235,569.1660013717421 307.4987105624142,571.8755006858711 301.8870342935528C574.585 296.27535802469134,576 291.5437777777778,576 288Z', + }, + }, + title: 'Chicken 1', + }, + { + viewBox: '-100 28 705 460', + keyframes: { + from: { + d: 'M255.5 48C299.345 48,339.897 56.5332,377.156 73.5996C414.415 90.666,443.871 113.873,465.522 143.22C487.174 172.566,498 204.577,498 239.252C498 273.926,487.174 305.982,465.522 335.42C443.871 364.857,414.46 388.109,377.291 405.175C340.122 422.241,299.525 430.775,255.5 430.775C241.607 430.775,227.262 429.781,212.467 427.795C148.233 472.402,114.042 494.977,109.892 495.518C107.907 496.241,106.012 496.15,104.208 495.248C103.486 494.706,102.945 493.983,102.584 493.08C102.223 492.177,102.043 491.365,102.043 490.642C102.043 490.281,102.043 489.92,102.043 489.559C103.126 482.515,111.335 453.169,126.672 401.518C91.8486 384.181,64.1974 361.2,43.7185 332.575C23.2395 303.951,13 272.843,13 239.252C13 204.577,23.8259 172.566,45.4777 143.22C67.1295 113.873,96.5849 90.666,133.844 73.5996C171.103 56.5332,211.655 48,255.5 48Z', + }, + to: { + d: 'M387.4151 302.0051C383.8622 305.53693333333337,380.3093 309.06876666666665,376.7564 312.6006C376.7564 312.6006,351.4235 337.7907,282.2765 269.0345C213.13 200.2808,238.4624 175.0921,238.4624 175.0921C240.69943333333333 172.86763333333332,242.93646666666666 170.64316666666667,245.1735 168.4187C261.7079 151.9793,263.2664 125.5857,248.8403 106.3174C239.0049666666667 93.1791,229.16963333333334 80.0408,219.3343 66.9025C201.4806 43.0541,166.9815 39.9038,146.5179 60.251C134.27503333333334 72.42439999999999,122.03216666666667 84.59779999999999,109.7893 96.7712C99.6426 106.8603,92.843 119.9388,93.6676 134.4473C95.7771 171.5646,112.5706 251.426,206.2794 344.6024C305.6531 443.4113,398.8951 447.3378,437.0254 443.7833C449.0858 442.6601,459.5737 436.5176,468.0257 428.1124C479.1064 417.09566666666666,490.1871 406.07893333333334,501.2678 395.0622C523.706 372.7503,517.3787 334.5007,488.6692 318.8952C473.7673 310.7941333333333,458.8654 302.69306666666665,443.9635 294.592C437.67983333333336 291.17636666666664,430.9390777777778 289.23363333333333,424.19849259259263 288.7040037037037C417.45790740740745 288.1743740740741,410.71749259259263 289.05784814814814,404.4345074074074 291.29462962962964C398.1515222222222 293.5314111111111,392.32596666666666 297.1215,387.4151 302.0051Z', + }, + }, + title: 'Message', + }, + ], + title: 'Closed paths with differing number of points', + }, + ], + }, + ]} + /> + ); +} diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.cpp new file mode 100644 index 000000000000..26c44ae3d944 --- /dev/null +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.cpp @@ -0,0 +1,281 @@ +#include +#include + +#include + +#include +#include +#include +#include + +namespace reanimated::css { + +using Point = Vector2D; +using Cubic = std::array; +using SubPath = SVGPath::SubPath; + +SVGPath::SVGPath() : subPaths() {} + +SVGPath::SVGPath(std::vector &&subPaths) : subPaths(std::move(subPaths)) {} + +SVGPath::SVGPath(jsi::Runtime &rt, const jsi::Value &jsiValue) : SVGPath(jsiValue.getString(rt).utf8(rt)) {} + +SVGPath::SVGPath(const folly::dynamic &value) : SVGPath(value.getString()) {} + +bool SVGPath::canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue) { + return jsiValue.isString(); +} + +bool SVGPath::canConstruct(const folly::dynamic &value) { + return value.isString(); +} + +folly::dynamic SVGPath::toDynamic() const { + return toString(); +} + +std::string SVGPath::toString() const { + std::ostringstream oss; + oss << std::defaultfloat; + for (size_t i = 0; i < subPaths.size(); ++i) { + const auto &segment = subPaths[i]; + + if (i > 0) { + oss << " "; + } + + oss << "M" << segment.M[0] << " " << segment.M[1]; + + for (const auto &point : segment.C) { + oss << " C"; + for (int j = 1; j < 4; ++j) { + // In SVGPath C command start point is implicit + oss << " " << point[j][0] << " " << point[j][1]; + } + } + + if (segment.Z) { + oss << " Z"; + } + } + return oss.str(); +} + +SVGPath SVGPath::interpolate(const double progress, const SVGPath &to) const { + const auto &longerPath = (subPaths.size() >= to.subPaths.size()) ? subPaths : to.subPaths; + const auto &shorterPath = (subPaths.size() < to.subPaths.size()) ? subPaths : to.subPaths; + + size_t longerSize = longerPath.size(); + size_t shorterSize = shorterPath.size(); + + std::vector> fromRef; + std::vector> toRef; + + fromRef.reserve(longerSize); + toRef.reserve(longerSize); + + if (shorterSize == 0) { + return to; + } + + size_t baseGroupSize = longerSize / shorterSize; + size_t remainder = longerSize % shorterSize; + + size_t longerPathIndex = 0; + + for (size_t i = 0; i < shorterSize; ++i) { + size_t currentGroupSize = baseGroupSize + (i < remainder ? 1 : 0); + + for (size_t j = 0; j < currentGroupSize; ++j) { + if (subPaths.size() <= to.subPaths.size()) { + fromRef.push_back(std::cref(subPaths[i])); + toRef.push_back(std::cref(to.subPaths[longerPathIndex])); + } else { + fromRef.push_back(std::cref(subPaths[longerPathIndex])); + toRef.push_back(std::cref(to.subPaths[i])); + } + longerPathIndex++; + } + } + + std::vector interpolatedSubPaths; + interpolatedSubPaths.reserve(longerSize); + + for (size_t i = 0; i < longerSize; ++i) { + interpolatedSubPaths.push_back(interpolateSubPaths(fromRef[i], toRef[i], progress)); + } + + return SVGPath(std::move(interpolatedSubPaths)); +} + +bool SVGPath::operator==(const SVGPath &other) const { + return toString() == other.toString(); +} + +#ifndef NDEBUG + +std::ostream &operator<<(std::ostream &os, const SVGPath &value) { + os << "SVGPath(" << value.toString() << ")"; + return os; +} + +#endif // NDEBUG + +std::vector SVGPath::parseSVGPath(const std::string &value) const { + std::vector result; + std::stringstream ss(value); + Point currPos; + + // Format of input: (M num num |C num num num num num num |Z)* + while (ss >> std::ws && !ss.eof()) { + char cmd; + ss >> cmd; + + switch (cmd) { + case 'M': + double x, y; + ss >> x >> y; + result.emplace_back(Point(x, y)); + currPos = Point(x, y); + break; + case 'C': + if (!result.empty()) { + Point p0(currPos), p1, p2, p3; + ss >> p1[0] >> p1[1] >> p2[0] >> p2[1] >> p3[0] >> p3[1]; + result.back().C.push_back({p0, p1, p2, p3}); + currPos = p3; + break; + } + // Fallthrough + case 'Z': + if (!result.empty()) { + result.back().Z = true; + currPos = result.back().M; + break; + } + // Fallthrough + default: + std::invalid_argument("[Reanimated] Invalid SVGPath string format."); + } + } + + return result; +} + +std::vector SVGPath::splitCubic(Cubic cubic, int count) const { + std::vector result; + for (int i = 0; i < count; i++) { + double t = 1.0 / (count - i); + auto [st, nd] = singleSplitCubic(cubic, t); + result.push_back(st); + cubic = nd; + } + return result; +} + +SubPath SVGPath::interpolateSubPaths(const SubPath &from, const SubPath &to, double t) const { + Point newM = from.M.interpolate(t, to.M); + SubPath result(newM); + + result.Z = to.Z; + + size_t longerSize = std::max(from.C.size(), to.C.size()); + size_t shorterSize = std::min(from.C.size(), to.C.size()); + + if (shorterSize == 0) { + return result; + } + + size_t baseGroupSize = longerSize / shorterSize; + size_t remainder = longerSize % shorterSize; + + std::vector prolongatedShorter; + prolongatedShorter.reserve(longerSize); + + for (size_t i = 0; i < shorterSize; ++i) { + size_t currentGroupSize = baseGroupSize + (i < remainder ? 1 : 0); + std::vector x = + from.C.size() <= to.C.size() ? splitCubic(from.C[i], currentGroupSize) : splitCubic(to.C[i], currentGroupSize); + prolongatedShorter.insert(prolongatedShorter.end(), x.begin(), x.end()); + } + + auto &fromRef = from.C.size() <= to.C.size() ? prolongatedShorter : from.C; + auto &toRef = from.C.size() <= to.C.size() ? to.C : prolongatedShorter; + + for (size_t i = 0; i < longerSize; ++i) { + const auto &c1 = fromRef[i]; + const auto &c2 = toRef[i]; + + Cubic newCubic; + + for (size_t j = 0; j < 4; ++j) { + newCubic[j] = c1[j].interpolate(t, c2[j]); + } + + // ensure continuity + if (i == 0) { + newCubic[0] = result.M; + } else { + newCubic[0] = result.C.back()[3]; + } + + // Ensure tangent differs from 0 + { + constexpr double NUDGE_EPS = 5e-1; + newCubic[1] = applyDirectionalNudge(newCubic[1], newCubic[0], newCubic[2], newCubic[3], NUDGE_EPS); + newCubic[2] = applyDirectionalNudge(newCubic[2], newCubic[3], newCubic[1], newCubic[0], NUDGE_EPS); + } + + result.C.push_back(newCubic); + } + + return result; +} + +Point SVGPath::lineAt(Point p0, Point p1, double t) const { + return Point(p0[0] + t * (p1[0] - p0[0]), p0[1] + t * (p1[1] - p0[1])); +} + +Point SVGPath::applyDirectionalNudge( + Point target, + const Point &anchor, + const Point &guide, + const Point &altGuide, + double epsilon) const { + double dx0 = target[0] - anchor[0]; + double dy0 = target[1] - anchor[1]; + + if (dx0 * dx0 + dy0 * dy0 < epsilon * epsilon) { + + Point v = Point(guide[0] - anchor[0], guide[1] - anchor[1]); + double vLen = v.length(); + + if (vLen < epsilon) { + v = Point(altGuide[0] - anchor[0], altGuide[1] - anchor[1]); + vLen = v.length(); + } + + if (vLen < epsilon) { + target[0] += epsilon; + return target; + } + + v.normalize(); + return Point(target[0] + v[0] * epsilon, target[1] + v[1] * epsilon); + } + + return target; +} + +std::pair SVGPath::singleSplitCubic(const Cubic &p, double t) const { + Point p01 = lineAt(p[0], p[1], t); + Point p12 = lineAt(p[1], p[2], t); + Point p23 = lineAt(p[2], p[3], t); + Point c0 = lineAt(p01, p12, t); + Point c1 = lineAt(p12, p23, t); + Point q = lineAt(c0, c1, t); + + return {{p[0], p01, c0, q}, {q, c1, p23, p[3]}}; +} + +} // namespace reanimated::css \ No newline at end of file diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.h b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.h new file mode 100644 index 000000000000..cb9abf06105a --- /dev/null +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGPath.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace reanimated::css { + +struct SVGPath : public CSSSimpleValue { + using Point = Vector2D; + using Cubic = std::array; + struct SubPath { + Point M; + std::vector C; + bool Z; + SubPath(Point M) : M(M) {} + }; + + std::vector subPaths; + + SVGPath(); + template + requires std::constructible_from + explicit SVGPath(T &&value) : subPaths(parseSVGPath(std::forward(value))) {} + explicit SVGPath(std::vector &&SubPaths); + explicit SVGPath(jsi::Runtime &rt, const jsi::Value &jsiValue); + explicit SVGPath(const folly::dynamic &value); + + static bool canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue); + static bool canConstruct(const folly::dynamic &value); + + folly::dynamic toDynamic() const override; + std::string toString() const override; + SVGPath interpolate(double progress, const SVGPath &to) const override; + + bool operator==(const SVGPath &other) const; + +#ifndef NDEBUG + friend std::ostream &operator<<(std::ostream &os, const SVGPath &dimension); +#endif // NDEBUG + + protected: + std::vector parseSVGPath(const std::string &value) const; + + std::vector splitCubic(Cubic cubic, int count) const; + + SubPath interpolateSubPaths(const SubPath &from, const SubPath &to, double t) const; + + private: + Point lineAt(Point p0, Point p1, double t) const; + + Point applyDirectionalNudge( + Point target, + const Point &anchor, + const Point &guide, + const Point &altGuide, + double epsilon = 5e-1) const; + + std::pair singleSplitCubic(const Cubic &cubic, double t) const; +}; +} // namespace reanimated::css \ No newline at end of file From 5f27e1f7a501492a52ca0092776246d9bb136883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Wi=C5=9Bniewski?= Date: Fri, 5 Dec 2025 15:49:08 +0100 Subject: [PATCH 3/3] Make examples more colorful --- .../screens/animatedProperties/svg/Path.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx index 11d2818f20f7..fa5a484fc4c9 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Path.tsx @@ -35,7 +35,7 @@ export default function PathExample() { )} tabs={[ { - name: 'Paths with the same number of points', + name: 'Primitives', sections: [ { examples: [ @@ -144,7 +144,7 @@ export default function PathExample() { ], }, { - name: 'Open paths with differing number of points', + name: 'Complex open', renderExample: ({ animation, viewBox }) => ( (