1684237440
Component-wrapper for collapse animation for elements with variable (and dynamic) height
npm install --save react-collapse
yarn add react-collapse
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-collapse/build/react-collapse.min.js"></script>
(Module exposed as `ReactCollapse`)
.ReactCollapse--collapse {
transition: height 500ms;
}
IMPORTANT: Without adding a CSS transition there will be no animation and component will open/close instantly.
import {Collapse} from 'react-collapse';
// ...
<Collapse isOpened={true || false}>
<div>Random content</div>
</Collapse>
Use Unmount
component provided as:
import {UnmountClosed} from 'react-collapse';
// ...
<UnmountClosed isOpened={true || false}>
<div>Random content</div>
</UnmountClosed>
Example example/App/AutoUnmount.js
If you want a controlled and accessible implementation, check out this example
isOpened
: PropTypes.boolean.isRequiredExpands or collapses content.
children
: PropTypes.node.isRequiredOne or multiple children with static, variable or dynamic height.
<Collapse isOpened={true}>
<p>Paragraph of text</p>
<p>Another paragraph is also OK</p>
<p>Images and any other content are ok too</p>
<img src="nyancat.gif" />
</Collapse>
theme
: PropTypes.objectOf(PropTypes.string)It is possible to set className
for extra div
elements that ReactCollapse creates.
Example:
<Collapse theme={{collapse: 'foo', content: 'bar'}}>
<div>Customly animated container</div>
</Collapse>
Default values:
const theme = {
collapse: 'ReactCollapse--collapse',
content: 'ReactCollapse--content'
}
Which ends up in the following markup:
<div class="ReactCollapse--collapse">
<div class="ReactCollapse--content">
{children}
</div>
</div>
IMPORTANT: these are not style objects, but class names!
onRest
, onWork
: PropTypes.funcCallback functions, triggered when animation has completed (onRest
) or has just started (onWork
)
Both functions are called with argument:
const arg = {
isFullyOpened: true || false, // `true` only when Collapse reached final height
isFullyClosed: true || false, // `true` only when Collapse is fully closed and height is zero
isOpened: true || false, // `true` if Collapse has any non-zero height
containerHeight: 123, // current pixel height of Collapse container (changes until reaches `contentHeight`)
contentHeight: 123 // determined height of supplied Content
}
<Collapse onRest={console.log} onWork={console.log}>
<div>Container text</div>
</Collapse>
Example example/App/Hooks.js
initialStyle
: PropTypes.shapeinitialStyle: PropTypes.shape({
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
overflow: PropTypes.string
})
You may control initial element style, for example to force initial animation from 0 to height by using initialStyle={{height: '0px', overflow: 'hidden'}}
IMPORTANT Any updates to this prop will be ignored after first render. Default value is determined based on initial isOpened
value:
initialStyle = props.isOpened
? {height: 'auto', overflow: 'initial'}
: {height: '0px', overflow: 'hidden'};
Example: example/App/ForceInitialAnimation.js
checkTimeout
: PropTypes.numberNumber in ms
.
Collapse will check height after thins timeout to determine if animation is completed, the shorter the number - the faster onRest
will be triggered and the quicker height: auto
will be applied. The downside - more calculations. Default value is: 50
.
IMPORTANT Collapse does not support any pass-through props, so any non-supported props will be ignored
Because we need to have control over when Collapse
component is updated and it is not possible or very hard to achieve when any random props can be passed to the component.
initially opened Collapse elements will be statically rendered with no animation. You can override this behaviour by using initialStyle
prop
due to the complexity of margins and their potentially collapsible nature, ReactCollapse
does not support (vertical) margins on their children. It might lead to the animation "jumping" to its correct height at the end of expanding. To avoid this, use padding instead of margin. See #101 for more details
v4
to v5
v5
was another complete rewrite that happened quite a while ago, it was published as @nkbt/react-collapse
and tested in real projects for a long time and now fully ready to be used.
In the most common scenario upgrade is trivial (add CSS transition to collapse element), but if you were using a few deprecated props - there might be some extra work required.
Luckily almost every deprecated callback or prop has fully working analogue in v5
. Unfortunately not all of them could maintain full backward compatibility, so please check this migration guide below.
New Collapse does not implement animations anymore, it only determines Content
height and updates Collapse
wrapper height to match it. Only after Collapse
height reaches Content
height (animation finished), Collapse's style is updated to have height: auto; overflow: initial
.
The implications is that you will need to update your CSS with transition:
.ReactCollapse--collapse {
transition: height 500ms;
}
IMPORTANT: Without adding a CSS transition there will be no animation and component will open/close instantly.
onRest
/onWork
callbacks (see above for full description). Though onRest
did exist previously, now it is called with arguments containing few operational params and flags.
initialStyle
you may control initial element style, for example to force initial animation from 0 to height by using initialStyle={{height: '0px', overflow: 'hidden'}}
IMPORTANT Any updates to this prop will be ignored after first render. Default value is:
initialStyle = props.isOpened
? {height: 'auto', overflow: 'initial'}
: {height: '0px', overflow: 'hidden'};
checkTimeout
number in ms
. Collapse will check height after thins timeout to determine if animation is completed, the shorter the number - the faster onRest
will be triggered and the quicker height: auto
will be applied. The downside - more calculations. Default value is: 50
.
v5
)Pass-through props - any unknown props passed to Collapse
component will be ignored
hasNestedCollapse - no longer necessary, as v5 does not care if there are nested Collapse elements, see example/App/Nested.js
fixedHeight - no longer necessary, just set whatever height you need for content element and Collapse will work as expected, see example/App/VariableHeight.js
springConfig - as new Collapse relies on simple CSS transitions (or your own implementation of animation) and does not use react-collapse, springConfig is no longer necessary. You can control control animation with css like
.ReactCollapse--collapse {
transition: height 500ms;
}
forceInitialAnimation - you can use new prop initialStyle={{height: '0px', overflow: 'hidden'}}
instead, so when new height will be set after component is rendered - it should naturally animate.
onMeasure - please use onRest
and onWork
instead and pick contentHeight
from argument
<Collapse
onRest={({contentHeight}) => console.log(contentHeight)}
onWork={({contentHeight}) => console.log(contentHeight)}>
<div>content</div>
</Collapse>
onRender - since animations are fully controlled by external app (e.g. with CSS) we no draw each frame and do not actually re-render component anymore, so it is impossible to have onRender
callback
Currently is being developed and tested with the latest stable Node
on OSX
.
To run example covering all ReactCollapse
features, use yarn start
, which will compile example/Example.js
git clone git@github.com:nkbt/react-collapse.git
cd react-collapse
yarn install
yarn start
# then
open http://localhost:8080
# to run ESLint check
yarn lint
# to run tests
yarn test
http://nkbt.github.io/react-collapse
http://codepen.io/nkbt/pen/MarzEg
Author: nkbt
Source Code: https://github.com/nkbt/react-collapse
License: MIT license
1683209200
Motion Toast
A well designed toast with animations for all platforms Support material3 themes
![]() | ![]() | ![]() |
---|---|---|
![]() | ![]() | ![]() |
In order to add motion toast to your project add this line to your pubspec.yaml
file
dependencies:
motion_toast: ^2.6.7
Or you can reference the main repository directly by adding those lines
dependencies:
motion_toast:
git: https://github.com/koukibadr/Motion-Toast.git
/// the text widget used for description message
final Widget description;
/// The title of the motion toast
/// if it's null it will not be rendered in the widget
final Widget? title;
/// The motion toast type possible values:
/// sucess
/// error
/// warning
/// info
/// delete
/// custom
late final MotionToastType motionToastType;
/// The motion toast icon, for types other than custom
/// the icon will get the default type icon
/// if [motionToastType] set to [MotionToastType.custom] the icon parameter is required
late final IconData icon;
/// The motion toast background color
/// if `motionToastType == MOTION_TOAST_TYPE.CUSTOM` color parameter is required
/// else the color will get the default type color from [motionToastColors]
late final Color primaryColor;
/// Color applied on the motion toast side widget (sidebar) and the icon
/// if it's null secondary color will be the primary color
/// can be customized when using the default constructor
late final Color? secondaryColor;
/// the type of the background that will be applied on the motion toast content
/// available values:
/// - solid: the primary color will be applied as it is on the content background
/// - transparent: an opacity will be added to the primary color
/// - lighter: a white background added to the motion toast with little opacity added to the primary color
late final BackgroundType backgroundType;
/// The design type icon (Material design or Cupertino)
/// if [motionToastType] set to [MOTION_TOAST_TYPE.CUSTOM] [iconType] will not be used
/// possible values
/// MATERIAL_DESIGN,
/// CUPERTINO
late final IconType? iconType;
/// The motion toast width by default it's set to 250
final double? width;
/// define the height of the motion toast
final double? height;
/// The constraint of the motion toast to size itself to the content
/// for responsive design
/// If it's `null`, then [width] and [height] will be used as it is.
final BoxConstraints? constraints;
/// the motion toast icon size
/// by default it's 40
final double iconSize;
/// disable or enable the heartbeat animation on the icon
/// by default the animation is enabled
final bool enableAnimation;
/// The layout ToastOrientation (from right to left or from left to right)
/// {
/// LTR,
/// RTL
/// }
final ToastOrientation layoutOrientation;
/// The type of animation, by default it's [AnimationType.fromBottom]
/// {
/// FROM_BOTTOM,
/// FROM_LEFT,
/// FROM_RIGHT
final AnimationType animationType;
/// the Duration of the toast animation
/// by default it's 1.5 seconds
final Duration animationDuration;
/// How long the toast will be shown
/// by default it's 3 seconds.
final Duration toastDuration;
/// The toast animation curve
/// by default it's `Curves.ease`
final Curve animationCurve;
/// The position where the motion toast will be displayed
/// possible values
/// CENTER,
/// TOP,
/// BOTTOM
final MotionToastPosition position;
/// Define the border radius of the toast
/// by default it's 20
final double borderRadius;
/// Function invoked when the toast is closed
final Function? onClose;
/// define whether the motion toast can be dismissed or not
/// applied on bottom motion toast
final bool dismissable;
/// The barrier color applied to the dialog display
/// by default the barrier is transparent [Colors.transparent]
final Color barrierColor;
///padding added to the main widget motion taost
///by default the padding is set to 0
final EdgeInsets padding;
/// define whether the borders are rendered or not
/// by default `= false`
final bool displayBorder;
/// define whether the side bar is displayed or not
/// default `= true`
final bool displaySideBar;
When creating you custom toast you don't have to use iconType
it will not be used when rendering the toast
if secondaryColor
not defined sidebar and icon will be rendered with primaryColor
if constraint
and width
and height
are not defined the toast will be displayed with
BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.75,
minWidth: 200,
maxHeight: 100,
)
otherwise if width
and height
are defined the constraints
attribute will be ignored
and if you define width
you need to define height also and vice versa
MotionToast.success(
title: Text("Success Motion Toast"),
description: Text("Example of success motion toast"),
).show(context);
MotionToast.warning(
title: Text("Warning Motion Toast"),
description: Text("This is a Warning")
).show(context);
MotionToast.error(
title: Text("Error"),
description: Text("Please enter your name")
).show(context);
MotionToast.info(
title: Text("Info Motion Toast"),
description: Text("Example of Info Toast")
).show(context);
MotionToast.delete(
title: Text("Deleted"),
description: Text("The item is deleted")
).show(context);
To create your custom toast just use the default constructor,
icon
description
and color
are required
MotionToast(
icon: Icons.alarm,
primaryColor: Colors.pink,
title: Text("Custom Toast"),
description: Text("You can customize the toast!"),
width: 300,
height: 100,
).show(context);
To change the toast layout you need to use layoutOrientation
,
icon
description
and color
are required
MotionToast.success(
title: Text("من اليمين"),
description: Text("هذا مثال بالعربية"),
layoutOrientation: ToastOrientation.rtl,
animationType: AnimationType.fromRight,width: 300,
).show(context);
To change the display position of the motion toast use position
attribute
MotionToast(
icon: Icons.zoom_out,
color: Colors.deepOrange,
title: Text("Top Motion Toast"),
description: Text("Another motion toast example"),
position: MotionToastPosition.top,
animationType: AnimationType.fromTop,
).show(context);
MotionToast(
icon: Icons.zoom_out,
color: Colors.deepOrange,
title: Text("Center Motion Toast"),
description: Text("Another motion toast example"),
position: MotionToastPosition.center
).show(context);
MotionToast.success(
title: Text("User Data"),
description: Text("Your data has been deleted"),
onClose: (){
MotionToast.error(
title: Text("User Data"),
description: Text("Your data has been deleted"),
).show(context);
},
).show(context);
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.orange[500]!,
secondaryColor: Colors.grey,
backgroundType: BackgroundType.solid,
title: Text('Two Color Motion Toast'),
description: Text('Another motion toast example'),
position: MotionToastPosition.top,
animationType: AnimationType.fromTop,
height: 100,
width: 300,
).show(context);
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.grey[400]!,
secondaryColor: Colors.yellow,
backgroundType: BackgroundType.transparent,
title: Text('Two Color Motion Toast'),
description: Text('Another motion toast example'),
position: MotionToastPosition.center,
height: 100,
width: 300,
).show(context);
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.orange[500]!,
secondaryColor: Colors.grey,
backgroundType: BackgroundType.solid,
title: Text('Two Color Motion Toast'),
description: Text('Another motion toast example'),
displayBorder: true,
displaySideBar: false,
).show(context);
MotionToast toast = MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.orange[500]!,
secondaryColor: Colors.grey,
backgroundType: BackgroundType.solid,
title: Text('Two Color Motion Toast'),
description: Text('Another motion toast example'),
displayBorder: true,
displaySideBar: false,
).show(context);
toast.dismiss();
Of course the project is open source, and you can contribute to it repository link
If you found a bug, open an issue.
If you have a feature request, open an issue.
If you want to contribute, submit a pull request.
Run this command:
With Flutter:
$ flutter pub add motion_toast
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
motion_toast: ^2.6.7
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:motion_toast/motion_toast.dart';
import 'package:flutter/material.dart';
import 'package:motion_toast/motion_toast.dart';
import 'package:motion_toast/resources/arrays.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Motion Toast Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({
Key? key,
}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: SizedBox(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'Motion Toast Examples',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(
height: 15,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displaySuccessMotionToast();
},
child: const Text('Success Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayWarningMotionToast();
},
child: const Text('Warning Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayErrorMotionToast();
},
child: const Text('Error Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayInfoMotionToast();
},
child: const Text('Info Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayDeleteMotionToast();
},
child: const Text('Delete Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayResponsiveMotionToast();
},
child: const Text('Responsive Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayCustomMotionToast();
},
child: const Text('Custom Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayMotionToastWithoutSideBar();
},
child: const Text('Without sidebar'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayMotionToastWithBorder();
},
child: const Text('With border'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayTwoColorsMotionToast();
},
child: const Text('Two-color Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displayTransparentMotionToast();
},
child: const Text('Transparent Motion Toast'),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
_displaySimultaneouslyToasts();
},
child: const Text('Simultaneously taosts'),
),
),
],
),
),
),
),
),
);
}
void _displaySuccessMotionToast() {
MotionToast toast = MotionToast.success(
title: const Text(
'Lorum Ipsum',
style: TextStyle(fontWeight: FontWeight.bold),
),
description: const Text(
'Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor, sed do eiusmod tempor, sed do eiusmod tempor',
style: TextStyle(fontSize: 12),
),
layoutOrientation: ToastOrientation.rtl,
animationType: AnimationType.fromRight,
dismissable: true,
);
toast.show(context);
Future.delayed(const Duration(seconds: 4)).then((value) {
toast.dismiss();
});
}
void _displayWarningMotionToast() {
MotionToast.warning(
title: const Text(
'Warning Motion Toast',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('This is a Warning'),
animationCurve: Curves.bounceIn,
borderRadius: 0,
animationDuration: const Duration(milliseconds: 1000),
).show(context);
}
void _displayErrorMotionToast() {
MotionToast.error(
title: const Text(
'Error',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('Please enter your name'),
position: MotionToastPosition.top,
barrierColor: Colors.black.withOpacity(0.3),
width: 300,
height: 80,
dismissable: false,
).show(context);
}
void _displayInfoMotionToast() {
MotionToast.info(
title: const Text(
'Info Motion Toast',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
position: MotionToastPosition.center,
description: const Text('Example of Info Toast'),
).show(context);
}
void _displayDeleteMotionToast() {
MotionToast.delete(
title: const Text(
'Deleted',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('The item is deleted'),
animationType: AnimationType.fromTop,
position: MotionToastPosition.top,
).show(context);
}
void _displayResponsiveMotionToast() {
MotionToast(
icon: Icons.rocket_launch,
primaryColor: Colors.purple,
title: const Text(
'Custom Toast',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text(
'Hello my name is Flutter dev',
),
).show(context);
}
void _displayCustomMotionToast() {
MotionToast(
primaryColor: Colors.pink,
title: const Text(
'Bugatti',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
dismissable: false,
description: const Text(
'Automobiles Ettore Bugatti was a German then French manufacturer of high-performance automobiles. The company was founded in 1909 in the then-German city of Molsheim, Alsace, by the Italian-born industrial designer Ettore Bugatti. ',
),
).show(context);
}
void _displayMotionToastWithoutSideBar() {
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.orange[500]!,
secondaryColor: Colors.grey,
backgroundType: BackgroundType.solid,
title: const Text('Two Color Motion Toast'),
description: const Text('Another motion toast example'),
displayBorder: true,
displaySideBar: false,
).show(context);
}
void _displayMotionToastWithBorder() {
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.deepOrange,
title: const Text('Top Motion Toast'),
description: const Text('Another motion toast example'),
position: MotionToastPosition.top,
animationType: AnimationType.fromTop,
displayBorder: true,
width: 350,
height: 100,
padding: const EdgeInsets.only(
top: 30,
),
).show(context);
}
void _displayTwoColorsMotionToast() {
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.orange[500]!,
secondaryColor: Colors.grey,
backgroundType: BackgroundType.solid,
title: const Text(
'Two Color Motion Toast',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('Another motion toast example'),
position: MotionToastPosition.top,
animationType: AnimationType.fromTop,
width: 350,
height: 100,
).show(context);
}
void _displayTransparentMotionToast() {
MotionToast(
icon: Icons.zoom_out,
primaryColor: Colors.grey[400]!,
secondaryColor: Colors.yellow,
backgroundType: BackgroundType.transparent,
title: const Text(
'Two Color Motion Toast',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('Another motion toast example'),
position: MotionToastPosition.center,
width: 350,
height: 100,
).show(context);
}
void _displaySimultaneouslyToasts() {
MotionToast.warning(
title: const Text(
'Warning Motion Toast',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('This is a Warning'),
animationCurve: Curves.bounceIn,
borderRadius: 0,
animationDuration: const Duration(milliseconds: 1000),
).show(context);
MotionToast.error(
title: const Text(
'Error',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
description: const Text('Please enter your name'),
animationType: AnimationType.fromLeft,
position: MotionToastPosition.top,
width: 300,
height: 80,
).show(context);
}
}
Download Details:
Author: koukibadr
Source Code: https://github.com/koukibadr/Motion-Toast
1679029140
A light-weight and extensible C++ library for trajectory optimization for legged robots.
A base-set of variables, costs and constraints that can be combined and extended to formulate trajectory optimization problems for legged systems. These implementations have been used to generate a variety of motions such as monoped hopping, biped walking, or a complete quadruped trotting cycle, while optimizing over the gait and step durations in less than 100ms (paper).
Features:
✔️ Intuitive and efficient formulation of variables, cost and constraints using Eigen.
✔️ ifopt enables using the high-performance solvers Ipopt and Snopt.
✔️ Elegant rviz visualization of motion plans using xpp.
✔️ ROS/catkin integration (optional).
✔️ Light-weight (~6k lines of code) makes it easy to use and extend.
The easiest way to install is through the ROS binaries:
sudo apt-get install ros-<ros-distro>-towr-ros
In case these don't yet exist for your distro, there are two ways to build this code from source:
Install dependencies CMake, Eigen, Ipopt:
Install ifopt, by cloning the repo and then: cmake .. && make install
on your system.
sudo apt-get install cmake libeigen3-dev coinor-libipopt-dev
Build towr:
git clone https://github.com/ethz-adrl/towr.git && cd towr/towr
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make
sudo make install # copies files in this folder to /usr/local/*
# sudo xargs rm < install_manifest.txt # in case you want to uninstall the above
Test (hopper_example.cc): Generates a motion for a one-legged hopper using Ipopt
./towr-example # or ./towr-test if gtest was found
Use: You can easily customize and add your own constraints and variables to the optimization problem. Herefore, add the following to your CMakeLists.txt:
find_package(towr 1.2 REQUIRED)
add_executable(main main.cpp) # Your custom variables, costs and constraints added to TOWR
target_link_libraries(main PUBLIC towr::towr) # adds include directories and libraries
We provide a ROS-wrapper for the pure cmake towr library, which adds a keyboard interface to modify goal state and motion types as well as visualizes the produces motions plans in rviz using xpp.
Install dependencies CMake, catkin, Eigen, Ipopt, ROS, xpp, ncurses, xterm:
sudo apt-get install cmake libeigen3-dev coinor-libipopt-dev libncurses5-dev xterm
sudo apt-get install ros-<ros-distro>-desktop-full ros-<ros-distro>-xpp
Build workspace:
cd catkin_workspace/src
git clone https://github.com/ethz-adrl/ifopt.git
git clone https://github.com/ethz-adrl/towr.git
cd ..
catkin_make_isolated -DCMAKE_BUILD_TYPE=Release # or `catkin build`
source ./devel_isolated/setup.bash
Use: Include in your catkin project by adding to your CMakeLists.txt
Add the following to your package.xml:
<package>
<depend>towr</depend>
</package>
add_compile_options(-std=c++11)
find_package(catkin COMPONENTS towr)
include_directories(${catkin_INCLUDE_DIRS})
target_link_libraries(foo ${catkin_LIBRARIES})
Launch the program using
roslaunch towr_ros towr_ros.launch # debug:=true (to debug with gdb)
Click in the xterm terminal and hit 'o'.
Information about how to tune the paramters can be found here.
nlp.AddConstraintSet(your_custom_constraints);
as shown here.We love pull request, whether its new constraint formulations, additional robot models, bug fixes, unit tests or updating the documentation. Please have a look at CONTRIBUTING.md for more information.
See here the list of contributors who participated in this project.
All publications underlying this code can be found here. The core paper is:
@article{winkler18,
author = {Winkler, Alexander W and Bellicoso, Dario C and
Hutter, Marco and Buchli, Jonas},
title = {Gait and Trajectory Optimization for Legged Systems
through Phase-based End-Effector Parameterization},
journal = {IEEE Robotics and Automation Letters (RA-L)},
year = {2018},
month = {July},
pages = {1560-1567},
volume = {3},
doi = {10.1109/LRA.2018.2798285},
}
A broader overview of the topic of Trajectory optimization and derivation of the Single-Rigid-Body Dynamics model used in this work: DOI 10.3929/ethz-b-000272432
Author: Ethz-adrl
Source Code: https://github.com/ethz-adrl/towr
License: BSD-3-Clause license
#machinelearning #cpluplus #robots #compute #motion #planning
1679021160
toppra
: Time-Optimal Path ParameterizationOverview
toppra is a library for computing the time-optimal path parametrization for robots subject to kinematic and dynamic constraints. In general, given the inputs:
p(s)
, s
in [0, s_end]
;toppra returns the time-optimal path parameterization: s_dot (s)
, from which the fastest trajectory q(t)
that satisfies the given constraints can be found.
Documentation and tutorials are available here.
You can install the package with pip:
pip install toppra
To install from source for development:
pip install -r requirement3.txt
pip install -e .
Support
Please report any issues, questions or feature request via Github issues tracker.
Have a quick question? Try asking in our slack channel.
Pull Requests are welcome! Create a Pull Request and we will review your proposal!
Credits
toppra
was originally developed by Hung Pham (Eureka Robotics, former CRI Group) and Phạm Quang Cưong (Eureka Robotics, CRI Group) with major contributions from talented contributors:
If you have taken part in developing and supporting the library, feel free to add your name to the list.
The development is also generously supported by Eureka Robotics.
Citing toppra
If you use this library for your research, we encourage you to
Author: Hungpham2511
Source Code: https://github.com/hungpham2511/toppra
License: MIT license
#machinelearning #python #robotics #motion #planning #algorithms
1679017260
Instantaneous Motion Generation for Robots and Machines.
Ruckig generates trajectories on-the-fly, allowing robots and machines to react instantaneously to sensor input. Ruckig calculates a trajectory to a target waypoint (with position, velocity, and acceleration) starting from any initial state limited by velocity, acceleration, and jerk constraints. Besides the target state, Ruckig allows to define intermediate positions for waypoint following. For state-to-state motions, Ruckig guarantees a time-optimal solution. With intermediate waypoints, Ruckig calculates the path and its time parametrization jointly, resulting in significantly faster trajectories compared to traditional methods.
More information can be found at ruckig.com and in the corresponding paper Jerk-limited Real-time Trajectory Generation with Arbitrary Target States, accepted for the Robotics: Science and Systems (RSS), 2021 conference.
Ruckig has no dependencies (except for testing). To build Ruckig using CMake, just run
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
To install Ruckig in a system-wide directory, use (sudo) make install
. An example of using Ruckig in your CMake project is given by examples/CMakeLists.txt
. However, you can also include Ruckig as a directory within your project and call add_subdirectory(ruckig)
in your parent CMakeLists.txt
. To enable the Online API for intermediate waypoints, just pass the BUILD_ONLINE_CLIENT
flag to CMake.
Ruckig is also available as a Python module, in particular for development or debugging purposes. The Ruckig Community Version can be installed from PyPI via
pip install ruckig
When using CMake, the Python module can be built using the BUILD_PYTHON_MODULE
flag. If you're only interested in the Python module (and not in the C++ library), you can build and install Ruckig via pip install .
.
Furthermore, we will explain the basics to get started with online generated trajectories within your application. There is also a collection of examples that guide you through the most important features of Ruckig. A time-optimal trajectory for a single degree of freedom is shown in the figure below. We also added plots for the resulting trajectories of all examples. Let's get started!
Ruckig provides three main interface classes: the Ruckig, the InputParameter, and the OutputParameter class.
First, you'll need to create a Ruckig instance with the number of DoFs as a template parameter, and the control cycle (e.g. in seconds) in the constructor.
Ruckig<6> ruckig {0.001}; // Number DoFs; control cycle in [s]
The input type has 3 blocks of data: the current state, the target state and the corresponding kinematic limits.
InputParameter<6> input; // Number DoFs
input.current_position = {0.2, ...};
input.current_velocity = {0.1, ...};
input.current_acceleration = {0.1, ...};
input.target_position = {0.5, ...};
input.target_velocity = {-0.1, ...};
input.target_acceleration = {0.2, ...};
input.max_velocity = {0.4, ...};
input.max_acceleration = {1.0, ...};
input.max_jerk = {4.0, ...};
OutputParameter<6> output; // Number DoFs
Given all input and output resources, we can iterate over the trajectory at each discrete time step. For most applications, this loop must run within a real-time thread and controls the actual hardware.
while (ruckig.update(input, output) == Result::Working) {
// Make use of the new state here!
// e.g. robot->setJointPositions(output.new_position);
output.pass_to_input(input); // Don't forget this!
}
Within the control loop, you need to update the current state of the input parameter according to the calculated trajectory. Therefore, the pass_to_input
method copies the new kinematic state of the output to the current kinematic state of the input parameter. If (in the next step) the current state is not the expected, pre-calculated trajectory, Ruckig will calculate a new trajectory based on the novel input. When the trajectory has reached the target state, the update
function will return Result::Finished
.
The Ruckig Community Version now supports intermediate waypoints via a remote API. Make sure to include -DBUILD_ONLINE_CLIENT=ON
as a CMake flag when compiling - the PyPI Python version should bring that out of the box. To allocate the necessary memory for a variable number of waypoints beforehand, we need to pass the maximum number of waypoints to Ruckig via
Ruckig<6> otg {0.001, 8};
InputParameter<6> input {8};
OutputParameter<6> output {8};
The InputParameter
class takes the number of waypoints as an optional input, however usually you will fill in the values (and therefore reserve its memory) yourself. Then you're ready to set intermediate via points by
input.intermediate_positions = {
{0.2, ...},
{0.8, ...},
};
As soon as at least one intermediate positions is given, the Ruckig Community Version switches to the mentioned (of course, non real-time capable) remote API. If you require real-time calculation on your own hardware, please contact us for the Ruckig Pro Version.
When using intermediate positions, both the underlying motion planning problem as well as its calculation changes significantly. In particular, there are some fundamental limitations for jerk-limited online trajectory generation regarding the usage of waypoints. Please find more information about these limitations here, and in general we recommend to use
input.intermediate_positions = otg.filter_intermediate_positions(input.intermediate_positions, {0.1, ...});
to filter waypoints according to a (high) threshold distance. Setting interrupt_calculation_duration makes sure to be real-time capable by refining the solution in the next control invocation. Note that this is a soft interruption of the calculation. Currently, no minimum or discrete durations are supported when using intermediate positions.
To go into more detail, the InputParameter type has following members:
using Vector = std::array<double, DOFs>; // By default
Vector current_position;
Vector current_velocity; // Initialized to zero
Vector current_acceleration; // Initialized to zero
std::vector<Vector> intermediate_positions; // (only in Pro Version)
Vector target_position;
Vector target_velocity; // Initialized to zero
Vector target_acceleration; // Initialized to zero
Vector max_velocity;
Vector max_acceleration;
Vector max_jerk;
std::optional<Vector> min_velocity; // If not given, the negative maximum velocity will be used.
std::optional<Vector> min_acceleration; // If not given, the negative maximum acceleration will be used.
std::optional<Vector> min_position; // (only in Pro Version)
std::optional<Vector> max_position; // (only in Pro Version)
std::array<bool, DOFs> enabled; // Initialized to true
std::optional<double> minimum_duration;
std::optional<double> interrupt_calculation_duration; // [µs], (only in Pro Version)
ControlInterface control_interface; // The default position interface controls the full kinematic state.
Synchronization synchronization; // Synchronization behavior of multiple DoFs
DurationDiscretization duration_discretization; // Whether the duration should be a discrete multiple of the control cycle (off by default)
std::optional<Vector<ControlInterface>> per_dof_control_interface; // Sets the control interface for each DoF individually, overwrites global control_interface
std::optional<Vector<Synchronization>> per_dof_synchronization; // Sets the synchronization for each DoF individually, overwrites global synchronization
On top of the current state, target state, and constraints, Ruckig allows for a few more advanced settings:
per_section_max_velocity
.We refer to the API documentation of the enumerations within the ruckig
namespace for all available options.
To check that Ruckig is able to generate a trajectory before the actual calculation step,
ruckig.validate_input(input, check_current_state_within_limits=false, check_target_state_within_limits=true);
// returns boolean
returns false
if an input is not valid. The two boolean arguments check that the current or target state are within the limits. The check includes a typical catch of jerk-limited trajectory generation: When the current state is at maximal velocity, any positive acceleration will inevitable lead to a velocity violation at a future timestep. In general, this condition is fulfilled when
Abs(acceleration) <= Sqrt(2 * max_jerk * (max_velocity - Abs(velocity))).
If both arguments are set to true, the calculated trajectory is guaranteed to be within the kinematic limits throughout its duration. Also, note that there are range constraints of the input due to numerical reasons, see below for more details.
The update
function of the Ruckig class returns a Result type that indicates the current state of the algorithm. This can either be working, finished if the trajectory has finished, or an error type if something went wrong during calculation. The result type can be compared as a standard integer.
State | Error Code |
---|---|
Working | 0 |
Finished | 1 |
Error | -1 |
ErrorInvalidInput | -100 |
ErrorTrajectoryDuration | -101 |
ErrorPositionalLimits | -102 |
ErrorExecutionTimeCalculation | -110 |
ErrorSynchronizationCalculation | -111 |
The output class includes the new kinematic state and the overall trajectory.
Vector new_position;
Vector new_velocity;
Vector new_acceleration;
Trajectory trajectory; // The current trajectory
double time; // The current, auto-incremented time. Reset to 0 at a new calculation.
size_t new_section; // Index of the section between two (possibly filtered) intermediate positions.
bool did_section_change; // Was a new section reached in the last cycle?
bool new_calculation; // Whether a new calculation was performed in the last cycle
bool was_calculation_interrupted; // Was the trajectory calculation interrupted? (only in Pro Version)
double calculation_duration; // Duration of the calculation in the last cycle [µs]
Moreover, the trajectory class has a range of useful parameters and methods.
double duration; // Duration of the trajectory
std::array<double, DOFs> independent_min_durations; // Time-optimal profile for each independent DoF
<...> at_time(double time); // Get the kinematic state of the trajectory at a given time
<...> get_position_extrema(); // Returns information about the position extrema and their times
Again, we refer to the API documentation for the exact signatures.
Ruckig also supports an offline approach for calculating a trajectory:
result = ruckig.calculate(input, trajectory);
When only using this method, the Ruckig
constructor does not need a control cycle (delta_time
) as an argument. However if given, Ruckig supports stepping through the trajectory with
while (ruckig.update(trajectory, output) == Result::Working) {
// Make use of the new state here!
// e.g. robot->setJointPositions(output.new_position);
}
starting from the current output.time
(currently Ruckig Pro only).
When following an arbitrary signal with position, velocity, acceleration, and jerk-limitation, the straight forward way would be to pass the current state to Ruckig's target state. However, as the resulting trajectory will take time to catch up, this approach will always lag behind the signal. The tracking interface solves this problem by predicting ahead (e.g. with constant acceleration by default) and is therefore able to follow signals very closely in a time-optimal way. This might be very helpful for (general) tracking, robot servoing, or trajectory post-processing applications.
To use the tracking interface, construct
Trackig<1> otg {0.01}; // control cycle
and set the current state as well as the kinematic constraints via
input.current_position = {0.0};
input.current_velocity = {0.0};
input.current_acceleration = {0.0};
input.max_velocity = {0.8};
input.max_acceleration = {2.0};
input.max_jerk = {5.0};
Then, we can track a signal in an online manner within the real-time control loop
for (double t = 0; t < 10.0; t += otg.delta_time) {
auto target_state = signal(t); // signal returns position, velocity, and acceleration
auto res = otg.update(target_state, input, output);
// Make use of the smooth target motion here (e.g. output.new_position)
output.pass_to_input(input);
}
Please find a complete example here. This functionality can also be used in an offline manner, e.g. when the entire signal is known beforehand. Here, we call the
smooth_trajectory = otg.calculate_trajectory(target_states, input);
method with the trajectory given as a std::vector
of target states. The Tracking interface is available in the Ruckig Pro version.
So far, we have told Ruckig the number of DoFs as a template parameter. If you don't know the number of DoFs at compile-time, you can set the template parameter to ruckig::DynamicDOFs
and pass the DoFs to the constructor:
Ruckig<DynamicDOFs> otg {6, 0.001};
InputParameter<DynamicDOFs> input {6};
OutputParameter<DynamicDOFs> output {6};
However, we recommend to keep the template parameter when possible: First, it has a performance benefit of a few percent. Second, it is convenient for real-time programming due to its easier handling of memory allocations. When using dynamic degrees of freedom, make sure to allocate the memory of all vectors beforehand.
Ruckig supports custom vector types to make interfacing with your code even easier and more flexible. Most importantly, you can switch to Eigen Vectors simply by including Eigen (3.4 or later) before Ruckig
#include <Eigen/Core> // Version 3.4 or later
#include <ruckig/ruckig.hpp>
and then call the constructors with the ruckig::EigenVector
parameter.
Ruckig<6, EigenVector> otg {0.001};
InputParameter<6, EigenVector> input;
OutputParameter<6, EigenVector> output;
Now every in- and output of Ruckig's API (such as current_position
, new_position
or max_jerk
) are Eigen types! To define completely custom vector types, you can pass a C++ template template parameter to the constructor. This template template parameter needs to fulfill a range of template arguments and methods:
template<class Type, size_t DOFs>
struct MinimalVector {
Type operator[](size_t i) const; // Array [] getter
Type& operator[](size_t i); // Array [] setter
size_t size() const; // Current size
bool operator==(const MinimalVector<T, DOFs>& rhs) const; // Equal comparison operator
// Only required in combination with DynamicDOFs, e.g. to allocate memory
void resize(size_t size);
};
Note that DynamicDOFs
corresponds to DOFs = 0
. We've included a range of examples for using Ruckig with (10) Eigen, (11) custom vector types, and (12) custom types with a dynamic number of DoFs.
The current test suite validates over 5.000.000.000 random trajectories as well as many additional edge cases. The numerical exactness is tested for the final position and final velocity to be within 1e-8
, for the final acceleration to be within 1e-10
, and for the velocity, acceleration and jerk limit to be within of a numerical error of 1e-12
. These are absolute values - we suggest to scale your input so that these correspond to your required precision of the system. For example, for most real-world systems we suggest to use input values in [m]
(instead of e.g. [mm]
), as 1e-8m
is sufficient precise for practical trajectory generation. Furthermore, all kinematic limits should be below 1e12
. The maximal supported trajectory duration is 7e3
, and you can scale your input parameter to avoid that limitation. Note that Ruckig will also output values outside of this range, there is however no guarantee for correctness.
We find that Ruckig is more than twice as fast as Reflexxes Type IV for state-to-state motions and well-suited for control cycles as low as 250 microseconds. The Ruckig Community Version is in general a more powerful and open-source alternative to the Reflexxes Type IV library. In fact, Ruckig is the first Type V trajectory generator for arbitrary target states and even supports directional velocity and acceleration limits, while also being faster on top.
For trajectories with intermediate waypoints, we compare Ruckig to Toppra, a state-of-the-art library for robotic motion planning. Ruckig is able to improve the trajectory duration on average by around 10%, as the path planning and time parametrization are calculated jointly. Moreover, Ruckig is real-time capable and supports jerk-constraints.
Ruckig is written in C++17. It is continuously tested on ubuntu-latest
, macos-latest
, and windows-latest
against following versions
If you still need to use C++11, you can patch the Ruckig Community Version by calling bash scripts/patch-c++11.sh
. Note that this will result in a performance drop of a few percent. Moreover, the Python module is not supported.
Ruckig is used by over hundred research labs, companies, and open-source projects worldwide, including:
@article{berscheid2021jerk,
title={Jerk-limited Real-time Trajectory Generation with Arbitrary Target States},
author={Berscheid, Lars and Kr{\"o}ger, Torsten},
journal={Robotics: Science and Systems XVII},
year={2021}
}
Author: pantor
Source Code: https://github.com/pantor/ruckig
License: MIT license
1679009160
Linux / macOS - Windows
Visit the OMPL installation page for detailed installation instructions.
OMPL has the following required dependencies:
The following dependencies are optional:
Once dependencies are installed, you can build OMPL on Linux, macOS, and MS Windows. Go to the top-level directory of OMPL and type the following commands:
mkdir -p build/Release
cd build/Release
cmake ../..
# next step is optional
make -j 4 update_bindings # if you want Python bindings
make -j 4 # replace "4" with the number of cores on your machine
Author: ompl
Source Code: https://github.com/ompl/ompl
License: View license
1678993440
Crocoddyl is an optimal control library for robot control under contact sequence. Its solvers are based on novel and efficient Differential Dynamic Programming (DDP) algorithms. Crocoddyl computes optimal trajectories along with optimal feedback gains. It uses Pinocchio for fast computation of robots dynamics and their analytical derivatives.
If you want to follow the current developments, you can directly refer to the devel branch. If you want to directly dive into Crocoddyl, only one single line is sufficient
conda install crocoddyl -c conda-forge
and if you prefer pip (in Python 3 or 2):
pip install --user crocoddyl
Crocoddyl can be easily installed on various Linux (Ubuntu, Fedora, etc.) and Unix distributions (Mac OS X, BSD, etc.).
![]() | ![]() ![]() |
Crocoddyl is versatible:
Crocoddyl is efficient and flexible:
You can install this package through robotpkg. robotpkg is a package manager tailored for robotics softwares. It greatly simplifies the release of new versions along with the management of their dependencies. You just need to add the robotpkg apt repository to your sources.list and then use sudo apt install robotpkg-py27-crocoddyl
(or py3X
for python 3.X, depending on your system):
If you have never added robotpkg as a softwares repository, please follow first the instructions from 1 to 3; otherwise, go directly to instruction 4. Those instructions are similar to the installation procedures presented in http://robotpkg.openrobots.org/debian.html.
sudo tee /etc/apt/sources.list.d/robotpkg.list <<EOF
deb [arch=amd64] http://robotpkg.openrobots.org/wip/packages/debian/pub $(lsb_release -sc) robotpkg
deb [arch=amd64] http://robotpkg.openrobots.org/packages/debian/pub $(lsb_release -sc) robotpkg
EOF
curl http://robotpkg.openrobots.org/packages/debian/robotpkg.key | sudo apt-key add -
sudo apt-get update
sudo apt install robotpkg-py36-crocoddyl # for Python 3
sudo apt install robotpkg-py27-crocoddyl # for Python 2
Finally you will need to configure your environment variables, e.g.:
export PATH=/opt/openrobots/bin:$PATH
export PKG_CONFIG_PATH=/opt/openrobots/lib/pkgconfig:$PKG_CONFIG_PATH
export LD_LIBRARY_PATH=/opt/openrobots/lib:$LD_LIBRARY_PATH
export PYTHONPATH=/opt/openrobots/lib/python2.7/site-packages:$PYTHONPATH
Crocoddyl is c++ library with Python bindings for versatile and fast prototyping. It has the following dependencies:
You can run examples, unit-tests and benchmarks from your build dir:
cd build
make test
make -s examples-quadrupedal_gaits INPUT="display plot" # enable display and plot
make -s benchmarks-cpp-quadrupedal_gaits INPUT="100 walk" # number of trials ; type of gait
Alternatively, you can see the 3D result and/or graphs of your run examples (through gepetto-viewer and matplotlib), you can use
export CROCODDYL_DISPLAY=1
export CROCODDYL_PLOT=1
After installation, you could run the examples as follows:
python -m crocoddyl.examples.quadrupedal_gaits "display" "plot" # enable display and plot
If you want to learn about Crocoddyl, take a look at the Jupyter notebooks. Start in the following order.
The documentation of Crocoddyl of its last release is available here.
To cite Crocoddyl in your academic research, please use the following bibtex lines:
@inproceedings{mastalli20crocoddyl,
author={Mastalli, Carlos and Budhiraja, Rohan and Merkt, Wolfgang and Saurel, Guilhem and Hammoud, Bilal
and Naveau, Maximilien and Carpentier, Justin and Righetti, Ludovic and Vijayakumar, Sethu and Mansard, Nicolas},
title={{Crocoddyl: An Efficient and Versatile Framework for Multi-Contact Optimal Control}},
booktitle = {IEEE International Conference on Robotics and Automation (ICRA)},
year={2020}
}
and the following one to reference this website:
@misc{crocoddylweb,
author = {Carlos Mastalli, Rohan Budhiraja and Nicolas Mansard and others},
title = {Crocoddyl: a fast and flexible optimal control library for robot control under contact sequence},
howpublished = {https://github.com/loco-3d/crocoddyl/wikis/home},
year = {2019}
}
Crocoddyl contributions go beyond efficient software implementation as well. Please also consider to cite the algorithm contributions of our different solvers and formulations:
Finally, please also consider citing Pinocchio, which contributes to the efficient implementation of rigid body algorithms and their derivatives. For more details how to cite Pinocchio visit: https://github.com/stack-of-tasks/pinocchio.
Below, there is list of the selected publications that describe different components of Crocoddyl. For a complete list see PUBLICATIONS.md.
[1] C. Mastalli, R. Budhiraja, W. Merkt, G. Saurel, B. Hammoud, M. Naveau, J. Carpentier, L. Righetti, S. Vijayakumar and N. Mansard. Crocoddyl: An Efficient and Versatile Framework for Multi-Contact Optimal Control, IEEE International Conference on Robotics and Automation (ICRA), 2020
[2] C. Mastalli, W. Merkt, J. Marti-Saumell, H. Ferrolho, J. Sola, N. Mansard, S. Vijayakumar. A Direct-Indirect Hybridization Approach to Control-Limited DDP, 2021
[3] R. Budhiraja, J. Carpentier, C. Mastalli and N. Mansard. Differential Dynamic Programming for Multi-Phase Rigid Contact Dynamics, IEEE RAS International Conference on Humanoid Robots (ICHR), 2018
You have a question or an issue? You may either directly open a new issue or use the mailing list crocoddyl@laas.fr.
Crocoddyl is being managed by a steering committee which meets every two weeks to discuss the ongoing developments.
The committee is being led by Carlos Mastalli (University of Edinburgh) and Rohan Budhiraja (LAAS-CNRS). Nicolas Mansard (LAAS-CNRS), Guilhem Saurel (LAAS-CNRS) and Justin Carpentier (INRIA) are other members of the committee.
The following people have been involved in the development of Crocoddyl:
The development of Crocoddyl is supported by the EU MEMMO project, and the EU RoboCom++ project. It is maintained by the Gepetto team @LAAS-CNRS, the Statistical Machine Learning and Motor Control Group @University of Edinburgh, and the Willow team @INRIA.
Author: loco-3d
Source Code: https://github.com/loco-3d/crocoddyl
License: BSD-3-Clause license
1676354520
Animations on web pages involve moving elements on the screen to improve the visual experience of users. These animations are visually appealing and tend to draw users’ attention to buttons, images, and other important information. Overall, it contributes to establishing a solid connection between users and the content on the screen.
In the past, web pages were very plain and lacked interactivity because they were only intended to display information, and there was no capability to create appealing visual experiences. Things have changed dramatically in recent years, thanks to the availability of libraries and packages that make it easier to animate and add visual experiences to your web pages.
This article will teach you how to use the Framer Motion library to animate a React application. Why should you use Framer Motion? And how it works by animating a mini-project.
Framer Motion is an open-source production-ready motion library for React. It allows you to add all forms of animations and transitions directly to Document Object Model (DOM) elements defined in your React components. Its syntax is easy to understand, and with a few lines of code, you will be able to implement awesome animations.
Framer Motion uses an awesome API that gives you access to the motion component. You can plug this component into your React DOM elements giving you access to additional props for animation. For example, the div
element will become motion.div
.
The Framer Motion also has beginner-friendly documentation with lots of practical examples and illustrations showing how to perform simple to complex forms of animations and transitions.
Framer Motion uses the motion
component, which you can attach to any DOM element to implement an animation or transition effect.
<motion.div>
<p> An animated text </p>
</motion.div>
Code language: HTML, XML (xml)
Nothing changes when you attach the motion
component to your element. Instead, it supercharges that element with animation capabilities, giving you access to props, keys, and values you can use to add any animation. For example, you can access the animate
prop, which takes in a dynamic value — an object which contains the different properties and values you want to animate.
<motion.div animate={{x: -10, y: 10}}>
<p> An animated text </p>
</motion.div>
Code language: HTML, XML (xml)
The above animation will cause the div
element to slide 10px
to the left and then 10px
to the bottom when it loads from the original position specified in style.
When units are not specified, calculations are done in pixels. You can also specify your preferred units by attaching them. For example:
animate={{x:"-10rem"}}
.
Framer Motion is a popular library with over 1.6 million weekly downloads. You can install the library into your React project using the command below in your terminal:
$ npm i framer-motion
Once you have installed it, you can verify if it has been installed in your package.json
file’s dependencies
object:
"dependencies": {
// ...
"framer-motion": "^7.5.3",
"react": "^18.2.0",
// ...
},
Code language: JSON / JSON with Comments (json)
Once you have installed the Framer Motion library, you can import the motion
component into a component you wish to use within your project, and everything will work fine.
import { motion } from 'framer-motion';
<motion.h1 animate={{x: 10, y: 20}}>
An animated text
</motion.h1>
Code language: JavaScript (javascript)
The motion
component can be applied to any DOM element within your React component. You can apply it to the container elements, headings, text elements, images, and other elements. This motion component gives you access to props like animate
, which you can use to adjust the color, size, position, display, and add other animation effects to the DOM element.
<motion.div
animate={{
x: 10,
backgroundColor: '#fff',
boxShadow: '10px 10px 0 rgba(0, 0, 0, 0.2)',
}}
>
<h1>Hi</h1>
<img src={myImage} alt="" />
</motion.div>
Code language: HTML, XML (xml)
In the example above, the background color changes to white. A box shadow is added to the div
when it loads, and the elements contained in the div
moves 10px
to the right.
It is also important to know that you can apply any form of animation based on CSS attributes. For example, you use x
, y
, and z
to move elements similar to translateX
, translateY
, and translateZ
.
You can also scale the size of an element using the scale
attribute for both x
and y
or scaleX
and scaleY
if you wish to apply separate values. Example:
<motion.div animate={{ scale: 0.8 }} >
<h1>Hi</h1>
<motion.img animate={{ scaleX: 1.2 }} src={myImage} alt="" />
</motion.div>
Code language: HTML, XML (xml)
The same applies to transformation values like skew
and rotate
. It’s also important to mention that it supports all forms of value types, such as numbers, strings, and colors in Hex, RGB, and HSLA as strings. You can also calculate values using the calc()
function.
<motion.img animate={{ x: "calc(100vw - 50%)" }} src={myImage} alt="" />
Code language: HTML, XML (xml)
At this point, you have only used the animate
prop, which makes you animate elements from the default CSS style to your specified values. But this is not always what you want; sometimes, you want to specify where your animation starts and ends. For example, you might want your text to slide from the left of your screen to the middle.
You can specify initial animation values using the initial
props, which work similarly to the animate
prop and uses similar attributes and values.
<motion.div
initial={{ opacity: 0, x: '-100vh' }}
animate={{ opacity: 1, x: 0 }}
>
<h1>Hi</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt
perspiciatis voluptates nihil dolores eum architecto eligendi
</p>
</motion.div>
Code language: HTML, XML (xml)
You will notice that these animations happen fast to the extent that you might not see them unless you pay close attention.
The page animates a block of Lorem ipsum text by indenting it and reverting it to its original position.
You can fix this by adding transition effects using the transition
prop. This transition
prop defines the type of animation used when animating between two values and how these values animate from one state to another.
For example, if you add a duration
of 1
, the animation will run for 1 second.
<motion.div
initial={{ opacity: 0, x: '-100vh' }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 1 }}
>
<h1>Hi</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt
perspiciatis voluptates nihil dolores eum architecto eligendi
</p>
</motion.div>
Code language: HTML, XML (xml)The page animates a block of Lorem ipsum text for a second by indenting it and reverting it to its original position.
There are three major transition types, and they all have their specific effect; they include Tween
, Spring
, or Inertia
. Tween
is the default type for all animation, so if you want a spring form of animation, you will need to specify the transition type as Spring
.
<motion.div
initial={{ opacity: 0, x: '-100vh' }}
animate={{ opacity: 1, x: 0 }}
transition={{ type: 'spring', duration: 1 }}
>
<h1>Hi</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt
perspiciatis voluptates nihil dolores eum architecto eligendi
</p>
</motion.div>
Code language: HTML, XML (xml)
Each type has some attributes peculiar to them. For example, when you use the transition type of spring
, you have access to an attribute like bounce
which specifies how elastic the spring effect is on the element.
<motion.div
initial={{ opacity: 0, x: '-100vh' }}
animate={{ opacity: 1, x: 0 }}
transition={{ type: 'spring', bounce: 0.6 }}
>
<h1>Hi</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt
perspiciatis voluptates nihil dolores eum architecto eligendi
</p>
</motion.div>
Code language: HTML, XML (xml)Spring animation.
There are other attributes like delay
, which you can use to set a delay time before the animation renders.
Sometimes, you may want your elements to animate through several different animation values, which may be from left to right, depending on what you want. In CSS, this is handled with keyframes
, but for Framer Motion, you can do this with a square bracket holding as many values as you want.
<motion.button
animate={{ x: [0, -20, 20, -20, 20, 0] }}
transition={{ delay: 1 }}
>
My Button
</motion.button>
The page animates a button to the left after a second from the initial render.
Note that in the example above, the animation waited for 1 second before moving the button to the left 20px
and right 20px
twice before returning to its original position. This can be applied to any animation transform attribute such as x,
y
, scale
, rotate
and others.
<motion.button
animate={{ scale: [1, 1.2, 1, 1.2, 1] }}
transition={{ delay: 1 }}
>
My Button
</motion.button>
Code language: HTML, XML (xml)
You will notice that these animations stop after it has completed the number of times specified. The example above will start at 1, which is the default. It will then scale up and down twice to its default value.
However, you may want the animation effect to repeat by using the transition
property yoyo
and set its value to Infinity
or the number of times you wish your animation repeats.
The transition property
yoyo
lets you specify the number of times you want an animation to repeat.
<motion.button
animate={{ scale: 1.2 }}
transition={{ delay: 1, yoyo: Infinity }}
>
My Button
</motion.button>
Code language: HTML, XML (xml)
In the code block above, you will notice you no longer need the square bracket. All you need is the value it should change to when it leaves the default, 1
.
The page animates a Generate Quote button once the button is hovered on.
You often want to apply hover gestures to buttons, cards, and other elements to draw the user’s attention. You might want a button to scale up and down when a user hovers over the button instead of just scaling up and down without any action from the user. To do this, you can use the whileHover
prop, which works similarly to previous props.
<motion.button
whileHover={{
scale: 1.2,
transition: { yoyo: Infinity },
}}
>
My Button
</motion.button>
Code language: HTML, XML (xml)
The transition property for
whileHover
prop is placed within the curly braces and not outside thewhileHover
prop.
The page animation transitions once the Generate Quote button is hovered on.
At this point, you have learned the basics of Framer Motion, how it works and how you could use it to implement animations directly on your DOM elements. You must have started asking yourself why you should add all animation properties and values directly on each element because it tends to make your code clumsy and not easy to understand.
This is where variants come in. You use variants to remove the props object and place them outside your component, so you only use the object names within your DOM element. This also helps you use the same animation effect for multiple elements within your component to avoid repetition.
import { Link } from 'react-router-dom';
import logo from './../images/logo.svg';
import { motion } from 'framer-motion';
const headerVariants = {
initial: {
y: '-100vh',
},
animate: {
y: 0,
transition: {
delay: 0.5,
duration: 0.5,
type: 'spring',
},
},
};
const Header = () => {
return (
<div className="container">
<motion.div
className="header"
variants={headerVariants}
initial="initial"
animate="animate"
>
<Link to="/">
<img src={logo} alt="" />
</Link>
<h1>Quotes Circle</h1>
</motion.div>
</div>
);
};
export default Header;
Code language: JavaScript (javascript)
In the code block above, an object (variant) is created to hold all the animation properties and values. This object contained two child objects, one to hold the initial
animation and the second to hold the final animation (animate
). You can give them any name:
const headerVariants = {
initial: {
y: '-100vh',
},
animate: {
y: 0,
transition: {
delay: 0.5,
duration: 0.5,
type: 'spring',
},
},
};
Code language: JavaScript (javascript)
To make use of this variant in your React DOM elements, then you will use the variants
prop and pass the variant name into it. Also, you will assign the initial
and animate
prop with the name you used when creating your variant, but this time as a string and not a dynamic value.
<motion.div
variants={headerVariants}
initial="initial"
animate="animate"
>
<Link to="/">
<img src={logo} alt="" />
</Link>
<h1>Quotes Circle</h1>
</motion.div>
Code language: HTML, XML (xml)
You can have as many variants as possible, and if you use the same initial
and animate
value, you would not need to declare that for children elements in your component.
const headerVariants = {
initial: {
y: '-100vh',
},
animate: {
y: 0,
transition: {
delay: 0.5,
duration: 0.5,
type: 'spring',
},
},
};
const logoVariants = {
initial: {
x: '-100vw',
},
animate: {
x: 0,
transition: {
delay: 1,
},
},
};
const Header = () => {
return (
<div className="container">
<motion.div
className="header"
variants={headerVariants}
initial="initial"
animate="animate"
>
<Link to="/">
<motion.img src={logo} variants={logoVariants} />
</Link>
<h1>Quotes Circle</h1>
</motion.div>
</div>
);
};
Code language: JavaScript (javascript)
If you look at the logo image element, you will notice the variants
prop was only defined. There is no need to define the initial
and animate
prop because it has the same name as the previous one you already declared in the parent element.
When building applications that have more than one page, you will want to add animation between each page. These animations may not be conspicuous but can add a nice experience rather than having content suddenly leave the screen.
The page animates a new component once the route changes.
The GIF above almost looks like the routes are animated, but you will notice that it only animates in but not out. This means that the components disappear when they unmount, so you will want to add an animation instead.
This is done with the AnimatePresence
component, which notifies components when they will be unmounted and allows them to defer that unmounting until after the animation is complete. This animation is added with the exit prop to your component’s parent element.
To implement this, you will first import AnimatePresence
component to the App.js
file where you configured your routes or if it’s in the index.js
file. Once that is done, you will wrap the Routes
component with the AnimatePresence
component:
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import QuotesPage from './pages/QuotesPage';
import Header from './components/Header';
import { AnimatePresence } from 'framer-motion';
const App = () => {
return (
<>
<Header />
<AnimatePresence>
<Routes location={location} key={location.key}>
<Route path="/" element={<Home />} />
<Route path="/quote" element={<QuotesPage />} />
</Routes>
</AnimatePresence>
</>
);
};
export default App;
Code language: JavaScript (javascript)
Then you will need to use useLocation
router hook to know when the route changes. This will be attached to the Route
component:
import { Routes, Route, useLocation } from 'react-router-dom';
import Home from './pages/Home';
import QuotesPage from './pages/QuotesPage';
import Header from './components/Header';
import { AnimatePresence } from 'framer-motion';
const App = () => {
const location = useLocation();
return (
<>
<Header />
<AnimatePresence>
<Routes location={location} key={location.key}>
<Route path="/" element={<Home />} />
<Route path="/quote" element={<QuotesPage />} />
</Routes>
</AnimatePresence>
</>
);
};
export default App;
Code language: JavaScript (javascript)
At this point, you can now add exit animation to all your component’s parent elements, and the exit animation will work very fine.
For example, if you want to add it to the Home
component, which is a route as seen above. You can use variants
or add the animation object directly to the exit
prop.
// ...
import { motion } from 'framer-motion';
const Home = () => {
// ...
const containerVariants = {
hidden: {
opacity: 0,
x: '100vw',
},
visible: {
opacity: 1,
x: 0,
transition: {
type: 'spring',
mass: 0.4,
damping: 8,
when: 'beforeChildren',
staggerChildren: 0.4,
},
},
exit: {
x: '-100vw',
transition: {
ease: 'easeInOut',
},
},
};
return (
<motion.div
className="container"
variants={containerVariants}
initial="hidden"
animate="visible"
exit="exit"
>
{ // ... component elements }
</motion.div>
);
};
export default Home;
Code language: JavaScript (javascript)
At this point, your routes will be animated when any component leaves the screen. It will animate out by sliding to the left as specified in the exit object:
exit: {
x: '-100vw',
transition: {
ease: 'easeInOut',
},
},
Code language: JavaScript (javascript)
But you will notice that the animation of the new component already happens when the previous component leaves the screen. You can fix this by adding an exitBeforeEnter
prop to the <AnimatePresence
> component you used to wrap the App.js
component.
// ... imports
const App = () => {
const location = useLocation();
return (
<>
<Header />
<AnimatePresence exitBeforeEnter>
{ // ... routes }
</AnimatePresence>
</>
);
};
export default App;
Code language: JavaScript (javascript)Each page is animated once the route is changed.
Framer Motion allows you to animate your Scalable Vector Graphics (SVGs) via their path (A way of drawing your SVGs). This is possible by attaching the motion component to the path element of your SVG and then adding your preferred animation alongside the pathlength
property with a value of 0
and 1
for when the animation starts and when it ends.
Suppose you have an SVG, you will notice that these SVGs usually have a path or paths defined with so many attributes and values:
const AnimateSVG = () => {
return (
<div className="container">
<svg
className="my-svg"
viewBox="0 0 256 256"
xmlns="http://www.w3.org/2000/svg"
>
<rect fill="none" height="256" width="256" />
<path
d="M108,144H40a8,8,0,0,1-8-8V72a8,8,0,0,1,8-8h60a8,8,0,0,1,8,8v88a40,40,0,0,1-40,40"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="12"
/>
<path
d="M224,144H156a8,8,0,0,1-8-8V72a8,8,0,0,1,8-8h60a8,8,0,0,1,8,8v88a40,40,0,0,1-40,40"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="12"
/>
</svg>
</div>
);
};
export default AnimateSVG;
Code language: JavaScript (javascript)
You can attach the motion component to the path element and then use the initial
and animate
props to add animation to the path:
import { motion } from 'framer-motion';
const AnimateSVG = () => {
return (
<div className="container">
<svg
className="my-svg"
viewBox="0 0 256 256"
xmlns="http://www.w3.org/2000/svg"
>
<rect fill="none" height="256" width="256" />
<motion.path
d="M108,144H40a8,8,0,0,1-8-8V72a8,8,0,0,1,8-8h60a8,8,0,0,1,8,8v88a40,40,0,0,1-40,40"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="12"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 2 }}
/>
<motion.path
d="M224,144H156a8,8,0,0,1-8-8V72a8,8,0,0,1,8-8h60a8,8,0,0,1,8,8v88a40,40,0,0,1-40,40"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="12"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 2 }}
/>
</svg>
</div>
);
};
export default AnimateSVG;
Code language: JavaScript (javascript)
In the code block above, you will notice that pathLength
is used to add animation to the SVG. The initial animation is set to 0
, meaning nothing shows, and then within 2 seconds, the SVG will draw.
Animated SVG.
Instead of adding the animation directly, you can use variants
and add that single variant to both paths. You can also add more forms of animation, such as opacity
if you wish.
import { motion } from 'framer-motion';
const AnimateSVG = () => {
const pathVariants = {
hidden: {
opacity: 0,
pathLength: 0,
},
visible: {
opacity: 1,
pathLength: 1,
transition: {
duration: 2,
ease: 'easeInOut',
},
},
};
return (
<div className="container">
<motion.svg
className="my-svg"
viewBox="0 0 256 256"
xmlns="http://www.w3.org/2000/svg"
>
<rect fill="none" height="256" width="256" />
<motion.path
d="M108,144H40a8,8,0,0,1-8-8V72a8,8,0,0,1,8-8h60a8,8,0,0,1,8,8v88a40,40,0,0,1-40,40"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="12"
variants={pathVariants}
initial="hidden"
animate="visible"
/>
<motion.path
d="M224,144H156a8,8,0,0,1-8-8V72a8,8,0,0,1,8-8h60a8,8,0,0,1,8,8v88a40,40,0,0,1-40,40"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="12"
variants={pathVariants}
initial="hidden"
animate="visible"
/>
</motion.svg>
</div>
);
};
export default AnimateSVG;
Code language: JavaScript (javascript)
Run the sandbox to preview the application in action:
In this guide, you have learned how to use Framer Motion to add animation to your React application elements, routes, and SVGs. It is important to note that the Framer Motion offers more than what has been covered in this guide, with many more animation options.
This guide has laid a proper foundation to help you navigate through and use the library in your React application for the first time. You can now check out the Framer Motion documentation to understand more options and animate your React application better. You can also get the animated demo project from this article’s GitHub repository.
Have fun coding!
I’m Joel Olawanle, a frontend developer and technical writer interested in making the web accessible to everyone by always looking for ways to give back to the tech community. Follow me and connect with me on Twitter.
Original article source at: https://coderpad.io
1675331520
🗡️ Pokedex demonstrates modern Android development with Hilt, Coroutines, Flow, Jetpack (Room, ViewModel), and Material Design based on MVVM architecture.
Go to the Releases to download the latest APK.
Pokedex is based on the MVVM architecture and the Repository pattern, which follows the Google's official architecture guidance.
The overall architecture of Pokedex is composed of two layers; the UI layer and the data layer. Each layer has dedicated components and they have each different responsibilities, as defined below:
Pokedex was built with Guide to app architecture, so it would be a great sample to show how the architecture works in real-world projects.
With this loosely coupled architecture, you can increase the reusability of components and scalability of your app.
The UI layer consists of UI elements to configure screens that could interact with users and ViewModel that holds app states and restores data when configuration changes.
The data Layer consists of repositories, which include business logic, such as querying data from the local database and requesting remote data from the network. It is implemented as an offline-first source of business logic and follows the single source of truth principle.
Pokedex is an offline-first app is an app that is able to perform all, or a critical subset of its core functionality without access to the internet. So users don't need to be up-to-date on the network resources every time and it will decrease users' data consumption. For further information, you can check out Build an offline-first app.
Pokedex adopted modularization strategies below:
For more information, check out the Guide to Android app modularization.
Pokedex using the PokeAPI for constructing RESTful API.
PokeAPI provides a RESTful API interface to highly detailed objects built from thousands of lines of data related to Pokémon.
Support it by joining stargazers for this repository. :star:
Also, follow me on GitHub for my next creations! 🤩
Author: Skydoves
Source Code: https://github.com/skydoves/Pokedex
License: Apache-2.0 license
1628682360
Every website needs a contact section, but that doesn’t mean you need to go for a standard design. With Divi’s scroll effects, you can create a floating contact section that will stand out. Improve your user interaction with a vertical scrolling contact section layout that will invite visitors to engage with your contact form. In this post, we’ll show you how to create a full width floating contact section that you can add to any page. You could even add it at the top of a site-wide footer with the Divi Theme Builder.
Below, you’ll find a free downloadable folder with the JSON layout to upload to your own Divi Library. We’ve also included a PSD template to help you recreate the map background, plus an SVG of the map pin so you can personalize it with your own colors.
#divi #motion #effects
1627827360
Divi’s new scroll effects are made for you to easily take your web design experience to the next level. Of course, you can apply it to elements within your section directly, but you can choose to add motion to underlying elements too. Going for an underlying approach allows you to keep content static while having background motion going on. In this tutorial, we’ll use transformed motion shapes as our underlying elements to create an animated section. We’ll handle two different examples but the possibilities are truly endless. You’ll be able to download the JSON file for free as well!
#divi #motion #backgrounds
1596950927
Adding animations to your android app makes it more fun and interesting as compared to static text or pictures. The easiest way to do that is using a 3rd party library Lottie by airbnb.
The best part is you can use animations without having to write a single line of code.
For brevity, we will use ready made animations available on lottiefiles.com. Alternatively you can also build your own custom animations using Adobe after effects and use them in your app. (See it in action here)
Let’s start by downloading all the animation files you need for your project from LottieFiles. For this guide, I’ll use a total of three animation files for
This is shown for a brief 2 seconds when user opens the app.
#lottie #motion #android #kotlin #animatin