diff --git a/VirtualRobot/CMakeLists.txt b/VirtualRobot/CMakeLists.txt
index 54e555329705bb870e0c963cf1fba2d167bf8a13..312cb8623bd754777eb8de264dc8371abd1714c8 100644
--- a/VirtualRobot/CMakeLists.txt
+++ b/VirtualRobot/CMakeLists.txt
@@ -200,329 +200,412 @@ ENDMACRO()
 
 #################################### FILES ##################################
 SET(SOURCES
-CollisionDetection/CollisionChecker.cpp
-CollisionDetection/CollisionModel.cpp
-CollisionDetection/CDManager.cpp
-EndEffector/EndEffector.cpp
-EndEffector/EndEffectorActor.cpp
-Nodes/RobotNode.cpp
-Nodes/RobotNodePrismatic.cpp
-Nodes/RobotNodePrismaticFactory.cpp
-Nodes/RobotNodeRevolute.cpp
-Nodes/RobotNodeRevoluteFactory.cpp
-Nodes/RobotNodeFixed.cpp
-Nodes/RobotNodeFixedFactory.cpp
-Nodes/RobotNodeActuator.cpp
-Nodes/Sensor.cpp
-Nodes/PositionSensor.cpp
-Nodes/ForceTorqueSensor.cpp
-Nodes/ContactSensor.cpp
-Nodes/CameraSensor.cpp
-Nodes/PositionSensorFactory.cpp
-Nodes/ForceTorqueSensorFactory.cpp
-Nodes/ContactSensorFactory.cpp
-Nodes/CameraSensorFactory.cpp
-Visualization/Visualization.cpp
-Visualization/VisualizationNode.cpp
-Visualization/ColorMap.cpp
-Visualization/TriMeshModel.cpp
-Visualization/TriMeshUtils.cpp
-XML/BaseIO.cpp
-XML/RobotIO.cpp
-XML/SceneIO.cpp
-XML/ObjectIO.cpp
-XML/FileIO.cpp
-XML/mjcf/MasslessBodySanitizer.cpp
-XML/mjcf/MjcfDocument.cpp
-XML/mjcf/MujocoIO.cpp
-XML/mjcf/utils.cpp
-IK/IKSolver.cpp
-IK/AdvancedIKSolver.cpp
-IK/DifferentialIK.cpp
-IK/GenericIKSolver.cpp
-IK/CoMIK.cpp
-IK/JacobiProvider.cpp
-IK/PoseQualityMeasurement.cpp
-IK/PoseQualityManipulability.cpp
-IK/PoseQualityExtendedManipulability.cpp
-IK/HierarchicalIK.cpp
-IK/HierarchicalIKSolver.cpp
-IK/JointLimitAvoidanceJacobi.cpp
-IK/GazeIK.cpp
-IK/StackedIK.cpp
-IK/SupportPolygon.cpp
-IK/FeetPosture.cpp
-IK/ConstrainedIK.cpp
-IK/ConstrainedHierarchicalIK.cpp
-IK/ConstrainedStackedIK.cpp
-IK/Constraint.cpp
-IK/constraints/BalanceConstraint.cpp
-IK/constraints/PoseConstraint.cpp
-IK/constraints/PositionConstraint.cpp
-IK/constraints/OrientationConstraint.cpp
-IK/constraints/TSRConstraint.cpp
-IK/constraints/ReferenceConfigurationConstraint.cpp
-IK/constraints/JointLimitAvoidanceConstraint.cpp
-IK/constraints/CoMConstraint.cpp
-IK/constraints/CollisionCheckConstraint.cpp
-Workspace/WorkspaceDataArray.cpp
-Workspace/WorkspaceRepresentation.cpp
-Workspace/Reachability.cpp
-Workspace/Manipulability.cpp
-Workspace/WorkspaceGrid.cpp
-#Workspace/ReachabilityInversion/InverseReachability.cpp
-#Workspace/ReachabilityInversion/OrientedWorkspaceGrid.cpp
-#Workspace/ReachabilityInversion/ReachabilityProcessor.cpp
-#Workspace/ReachabilityInversion/RobotPlacementIK.cpp
-#Workspace/ReachabilityInversion/RobotPlacementTrajectoryIK.cpp
-TimeOptimalTrajectory/Path.cpp
-TimeOptimalTrajectory/TimeOptimalTrajectory.cpp
-Grasping/Grasp.cpp
-Grasping/GraspSet.cpp
-Grasping/BasicGraspQualityMeasure.cpp
-MathTools.cpp
-Robot.cpp
-RobotConfig.cpp
-RobotNodeSet.cpp
-Trajectory.cpp
-KinematicChain.cpp
-RobotFactory.cpp
-SceneObject.cpp
-SceneObjectSet.cpp
-Scene.cpp
-Obstacle.cpp
-Primitive.cpp
-VirtualRobotException.cpp
-ManipulationObject.cpp
-BoundingBox.cpp
-RuntimeEnvironment.cpp
-Random.cpp
-LinkedCoordinate.cpp
-SphereApproximator.cpp
-VirtualRobot.cpp
-Compression/CompressionRLE.cpp
-Compression/CompressionBZip2.cpp
-Import/SimoxXMLFactory.cpp
-Import/RobotImporterFactory.cpp
-Import/MeshImport/STLReader.cpp
-Tools/Gravity.cpp
-math/AbstractFunctionR1R2.cpp
-math/AbstractFunctionR1R3.cpp
-math/AbstractFunctionR1R6.cpp
-math/AbstractFunctionR2R3.cpp
-math/Bezier.cpp
-math/CompositeFunctionR1R6.cpp
-math/Contact.cpp
-math/ContactList.cpp
-math/DataR3R1.cpp
-math/DataR3R2.cpp
-math/FitPlane.cpp
-math/GaussianImplicitSurface3D.cpp
-math/GaussianImplicitSurface3DNormals.cpp
-math/GaussianImplicitSurface3DCombined.cpp
-math/GaussianObjectModel.cpp
-math/GaussianObjectModelNormals.cpp
-math/Grid3D.cpp
-math/GridCacheFloat3.cpp
-math/Helpers.cpp
-math/ImplicitPlane.cpp
-math/ImplicitObjectModel.cpp
-math/Index3.cpp
-math/Kernels.cpp
-math/Line.cpp
-math/LinearContinuedBezier.cpp
-math/LinearInterpolatedOrientation.cpp
-math/LineR2.cpp
-math/LineStrip.cpp
-math/MarchingCubes.cpp
-math/TransformedFunctionR1R3.cpp
-math/TransformedFunctionR2R3.cpp
-math/Plane.cpp
-math/Primitive.cpp
-math/Triangle.cpp
-math/WeightedAverage.cpp
-math/statistics/measures.cpp
-math/statistics/BoxPlot.cpp
-math/statistics/Histogram.cpp
-Util/xml/tinyxml2.cpp
-Util/json/eigen_conversion.cpp
+    
+    BoundingBox.cpp
+    KinematicChain.cpp
+    LinkedCoordinate.cpp
+    ManipulationObject.cpp
+    MathTools.cpp
+    Obstacle.cpp
+    Primitive.cpp
+    Random.cpp
+    Robot.cpp
+    RobotConfig.cpp
+    RobotFactory.cpp
+    RobotNodeSet.cpp
+    RuntimeEnvironment.cpp
+    Scene.cpp
+    SceneObject.cpp
+    SceneObjectSet.cpp
+    SphereApproximator.cpp
+    Trajectory.cpp
+    VirtualRobot.cpp
+    VirtualRobotException.cpp
+    
+    CollisionDetection/CDManager.cpp
+    CollisionDetection/CollisionChecker.cpp
+    CollisionDetection/CollisionModel.cpp
+    
+    Compression/CompressionBZip2.cpp
+    Compression/CompressionRLE.cpp
+    
+    EndEffector/EndEffector.cpp
+    EndEffector/EndEffectorActor.cpp
+    
+    Grasping/BasicGraspQualityMeasure.cpp
+    Grasping/Grasp.cpp
+    Grasping/GraspSet.cpp
+    
+    IK/AdvancedIKSolver.cpp
+    IK/CoMIK.cpp
+    IK/ConstrainedHierarchicalIK.cpp
+    IK/ConstrainedIK.cpp
+    IK/ConstrainedStackedIK.cpp
+    IK/Constraint.cpp
+    IK/DifferentialIK.cpp
+    IK/FeetPosture.cpp
+    IK/GazeIK.cpp
+    IK/GenericIKSolver.cpp
+    IK/HierarchicalIK.cpp
+    IK/HierarchicalIKSolver.cpp
+    IK/IKSolver.cpp
+    IK/JacobiProvider.cpp
+    IK/JointLimitAvoidanceJacobi.cpp
+    IK/PoseQualityExtendedManipulability.cpp
+    IK/PoseQualityManipulability.cpp
+    IK/PoseQualityMeasurement.cpp
+    IK/StackedIK.cpp
+    IK/SupportPolygon.cpp
+    IK/constraints/BalanceConstraint.cpp
+    IK/constraints/CoMConstraint.cpp
+    IK/constraints/CollisionCheckConstraint.cpp
+    IK/constraints/JointLimitAvoidanceConstraint.cpp
+    IK/constraints/OrientationConstraint.cpp
+    IK/constraints/PoseConstraint.cpp
+    IK/constraints/PositionConstraint.cpp
+    IK/constraints/ReferenceConfigurationConstraint.cpp
+    IK/constraints/TSRConstraint.cpp
+    
+    Import/RobotImporterFactory.cpp
+    Import/SimoxXMLFactory.cpp
+    Import/MeshImport/STLReader.cpp
+    
+    math/AbstractFunctionR1R2.cpp
+    math/AbstractFunctionR1R3.cpp
+    math/AbstractFunctionR1R6.cpp
+    math/AbstractFunctionR2R3.cpp
+    math/Bezier.cpp
+    math/CompositeFunctionR1R6.cpp
+    math/Contact.cpp
+    math/ContactList.cpp
+    math/DataR3R1.cpp
+    math/DataR3R2.cpp
+    math/FitPlane.cpp
+    math/GaussianImplicitSurface3D.cpp
+    math/GaussianImplicitSurface3DNormals.cpp
+    math/GaussianImplicitSurface3DCombined.cpp
+    math/GaussianObjectModel.cpp
+    math/GaussianObjectModelNormals.cpp
+    math/Grid3D.cpp
+    math/GridCacheFloat3.cpp
+    math/Helpers.cpp
+    math/ImplicitPlane.cpp
+    math/ImplicitObjectModel.cpp
+    math/Index3.cpp
+    math/Kernels.cpp
+    math/Line.cpp
+    math/LinearContinuedBezier.cpp
+    math/LinearInterpolatedOrientation.cpp
+    math/LineR2.cpp
+    math/LineStrip.cpp
+    math/MarchingCubes.cpp
+    math/TransformedFunctionR1R3.cpp
+    math/TransformedFunctionR2R3.cpp
+    math/Plane.cpp
+    math/Primitive.cpp
+    math/Triangle.cpp
+    math/WeightedAverage.cpp
+    math/statistics/measures.cpp
+    math/statistics/BoxPlot.cpp
+    math/statistics/Histogram.cpp
+    
+    MJCF/Document.cpp
+    MJCF/elements/core/AnyElement.cpp
+    MJCF/elements/core/Attribute.cpp
+    MJCF/elements/core/Element.cpp
+    MJCF/elements/core/exceptions.cpp
+    MJCF/elements/core/mjcf_utils.cpp
+    MJCF/elements/core/Visitor.cpp
+    MJCF/elements/types/actuator.cpp
+    MJCF/elements/types/asset.cpp
+    MJCF/elements/types/body.cpp
+    MJCF/elements/types/contact.cpp
+    MJCF/elements/types/compiler.cpp
+    MJCF/elements/types/custom.cpp
+    MJCF/elements/types/default.cpp
+    MJCF/elements/types/equality.cpp
+    MJCF/elements/types/keyframe.cpp
+    MJCF/elements/types/meta.cpp
+    MJCF/elements/types/option.cpp
+    MJCF/elements/types/sensor.cpp
+    MJCF/elements/types/size.cpp
+    MJCF/elements/types/statistic.cpp
+    MJCF/elements/types/tendon.cpp
+    MJCF/elements/types/visual.cpp
+    MJCF/visitors/Collector.cpp
+    
+    Nodes/CameraSensor.cpp
+    Nodes/CameraSensorFactory.cpp
+    Nodes/ContactSensor.cpp
+    Nodes/ContactSensorFactory.cpp
+    Nodes/ForceTorqueSensor.cpp
+    Nodes/ForceTorqueSensorFactory.cpp
+    Nodes/PositionSensor.cpp
+    Nodes/PositionSensorFactory.cpp
+    Nodes/RobotNode.cpp
+    Nodes/RobotNodeActuator.cpp
+    Nodes/RobotNodeFixed.cpp
+    Nodes/RobotNodeFixedFactory.cpp
+    Nodes/RobotNodePrismatic.cpp
+    Nodes/RobotNodePrismaticFactory.cpp
+    Nodes/RobotNodeRevolute.cpp
+    Nodes/RobotNodeRevoluteFactory.cpp
+    Nodes/Sensor.cpp
+    
+    TimeOptimalTrajectory/Path.cpp
+    TimeOptimalTrajectory/TimeOptimalTrajectory.cpp
+    
+    Tools/Gravity.cpp
+    
+    Util/json/eigen_conversion.cpp
+    Util/xml/tinyxml2.cpp
+    
+    Visualization/ColorMap.cpp
+    Visualization/TriMeshModel.cpp
+    Visualization/TriMeshUtils.cpp
+    Visualization/Visualization.cpp
+    Visualization/VisualizationNode.cpp
+    
+    Workspace/Manipulability.cpp
+    Workspace/Reachability.cpp
+    Workspace/WorkspaceDataArray.cpp
+    Workspace/WorkspaceGrid.cpp
+    Workspace/WorkspaceRepresentation.cpp
+    #Workspace/ReachabilityInversion/InverseReachability.cpp
+    #Workspace/ReachabilityInversion/OrientedWorkspaceGrid.cpp
+    #Workspace/ReachabilityInversion/ReachabilityProcessor.cpp
+    #Workspace/ReachabilityInversion/RobotPlacementIK.cpp
+    #Workspace/ReachabilityInversion/RobotPlacementTrajectoryIK.cpp
+    
+    XML/BaseIO.cpp
+    XML/FileIO.cpp
+    XML/ObjectIO.cpp
+    XML/RobotIO.cpp
+    XML/SceneIO.cpp
+    XML/mujoco/MasslessBodySanitizer.cpp
+    XML/mujoco/MujocoIO.cpp
 )
 
 SET(INCLUDES
-CollisionDetection/CollisionChecker.h
-CollisionDetection/CollisionModel.h
-CollisionDetection/CDManager.h
-CollisionDetection/CollisionModelImplementation.h
-CollisionDetection/CollisionCheckerImplementation.h
-EndEffector/EndEffector.h
-EndEffector/EndEffectorActor.h
-Nodes/RobotNode.h
-Nodes/RobotNodeFactory.h
-Nodes/RobotNodePrismatic.h
-Nodes/RobotNodePrismaticFactory.h
-Nodes/RobotNodeRevolute.h
-Nodes/RobotNodeRevoluteFactory.h
-Nodes/RobotNodeFixed.h
-Nodes/RobotNodeFixedFactory.h
-Nodes/RobotNodeActuator.h
-Nodes/ConditionedLock.h
-Nodes/Sensor.h
-Nodes/PositionSensor.h
-Nodes/ForceTorqueSensor.h
-Nodes/CameraSensor.h
-Nodes/SensorFactory.h
-Nodes/PositionSensorFactory.h
-Nodes/ForceTorqueSensorFactory.h
-Nodes/CameraSensorFactory.h
-Transformation/DHParameter.h
-Visualization/VisualizationFactory.h
-Visualization/Visualization.h
-Visualization/VisualizationNode.h
-Visualization/ColorMap.h
-Visualization/TriMeshModel.h
-Visualization/TriMeshUtils.h
-XML/BaseIO.h
-XML/RobotIO.h
-XML/SceneIO.h
-XML/ObjectIO.h
-XML/FileIO.h
-XML/mjcf/MasslessBodySanitizer.h
-XML/mjcf/MjcfDocument.h
-XML/mjcf/MujocoIO.h
-XML/mjcf/utils.h
-IK/IKSolver.h
-IK/AdvancedIKSolver.h
-IK/DifferentialIK.h
-IK/GenericIKSolver.h
-IK/CoMIK.h
-IK/JacobiProvider.h
-IK/PoseQualityMeasurement.h
-IK/PoseQualityManipulability.h
-IK/PoseQualityExtendedManipulability.h
-IK/HierarchicalIK.h
-IK/HierarchicalIKSolver.h
-IK/JointLimitAvoidanceJacobi.h
-IK/GazeIK.h
-IK/StackedIK.h
-IK/SupportPolygon.h
-IK/FeetPosture.h
-IK/ConstrainedIK.h
-IK/ConstrainedHierarchicalIK.h
-IK/ConstrainedStackedIK.h
-IK/Constraint.h
-IK/constraints/BalanceConstraint.h
-IK/constraints/PoseConstraint.h
-IK/constraints/PositionConstraint.h
-IK/constraints/OrientationConstraint.h
-IK/constraints/TSRConstraint.h
-IK/constraints/ReferenceConfigurationConstraint.h
-IK/constraints/JointLimitAvoidanceConstraint.h
-IK/constraints/CoMConstraint.h
-IK/constraints/CollisionCheckConstraint.h
-Workspace/WorkspaceData.h
-Workspace/WorkspaceDataArray.h
-Workspace/WorkspaceRepresentation.h
-Workspace/Reachability.h
-Workspace/Manipulability.h
-Workspace/VoxelTree6D.hpp
-Workspace/VoxelTree6DElement.hpp
-Workspace/VoxelTreeND.hpp
-Workspace/VoxelTreeNDElement.hpp
-Workspace/WorkspaceGrid.h
-#Workspace/ReachabilityInversion/InverseReachability.h
-#Workspace/ReachabilityInversion/OrientedWorkspaceGrid.h
-#Workspace/ReachabilityInversion/ReachabilityProcessor.h
-#Workspace/ReachabilityInversion/RobotPlacementIK.h
-#Workspace/ReachabilityInversion/RobotPlacementTrajectoryIK.h
-TimeOptimalTrajectory/Path.h
-TimeOptimalTrajectory/TimeOptimalTrajectory.h
-Grasping/Grasp.h
-Grasping/GraspSet.h
-Grasping/BasicGraspQualityMeasure.h
-AbstractFactoryMethod.h
-VirtualRobot.h
-MathTools.h
-Robot.h
-RobotConfig.h
-RobotNodeSet.h
-Trajectory.h
-KinematicChain.h
-RobotFactory.h
-SceneObject.h
-SceneObjectSet.h
-Scene.h
-Obstacle.h
-Primitive.h
-VirtualRobotException.h
-VirtualRobotImportExport.h
-VirtualRobotTest.h
-ManipulationObject.h
-BoundingBox.h
-RuntimeEnvironment.h
-Random.h
-DataStructures/nanoflann.hpp
-DataStructures/KdTreePointCloud.h
-Compression/CompressionRLE.h
-Compression/CompressionBZip2.h
-SphereApproximator.h
-Import/SimoxXMLFactory.h
-Import/RobotImporterFactory.h
-Import/MeshImport/STLReader.h
-Tools/Gravity.h
-math/AbstractFunctionR1Ori.h
-math/AbstractFunctionR1R2.h
-math/AbstractFunctionR1R3.h
-math/AbstractFunctionR1R6.h
-math/AbstractFunctionR2R3.h
-math/AbstractFunctionR3R1.h
-math/Array3D.h
-math/Bezier.h
-math/ClampedNormalDistribution.hpp
-math/CompositeFunctionR1R6.h
-math/Contact.h
-math/ContactList.h
-math/DataR3R1.h
-math/DataR3R2.h
-math/FitPlane.h
-math/GaussianImplicitSurface3D.h
-math/GaussianImplicitSurface3DCombined.h
-math/GaussianImplicitSurface3DNormals.h
-math/GaussianObjectModel.h
-math/GaussianObjectModelNormals.h
-math/Grid3D.h
-math/GridCacheFloat3.h
-math/Helpers.h
-math/ImplicitObjectModel.cpp
-math/ImplicitPlane.h
-math/Index3.h
-math/Kernels.h
-math/Line.h
-math/LineR2.h
-math/LineStrip.h
-math/LineStripR1RM.h
-math/LinearContinuedBezier.h
-math/LinearInterpolatedOrientation.h
-math/MarchingCubes.h
-math/MathForwardDefinitions.h
-math/Plane.h
-math/Primitive.h
-math/SimpleAbstractFunctionR1Ori.h
-math/SimpleAbstractFunctionR1R3.h
-math/SimpleAbstractFunctionR1R6.h
-math/SimpleAbstractFunctionR2R3.h
-math/SimpleAbstractFunctionR3R1.h
-math/SimpleAbstractFunctionRNRM.h
-math/TransformedFunctionR1R3.h
-math/TransformedFunctionR2R3.h
-math/Triangle.h
-math/WeightedAverage.h
-math/statistics/measures.h
-math/statistics/BoxPlot.h
-math/statistics/Histogram.h
-Util/xml/tinyxml2.h
-Util/json/json.hpp
-Util/json/eigen_conversion.h
-Util/json/eigen_conversion.hpp
+    
+    AbstractFactoryMethod.h
+    BoundingBox.h
+    KinematicChain.h
+    ManipulationObject.h
+    MathTools.h
+    Obstacle.h
+    Primitive.h
+    Random.h
+    Robot.h
+    RobotConfig.h
+    RobotFactory.h
+    RobotNodeSet.h
+    RuntimeEnvironment.h
+    Scene.h
+    SceneObject.h
+    SceneObjectSet.h
+    SphereApproximator.h
+    Trajectory.h
+    VirtualRobot.h
+    VirtualRobotException.h
+    VirtualRobotImportExport.h
+    VirtualRobotTest.h
+    
+    CollisionDetection/CollisionChecker.h
+    CollisionDetection/CollisionModel.h
+    CollisionDetection/CDManager.h
+    CollisionDetection/CollisionModelImplementation.h
+    CollisionDetection/CollisionCheckerImplementation.h
+    
+    Compression/CompressionBZip2.h
+    Compression/CompressionRLE.h
+    
+    DataStructures/nanoflann.hpp
+    DataStructures/KdTreePointCloud.h
+    
+    EndEffector/EndEffector.h
+    EndEffector/EndEffectorActor.h
+    
+    Grasping/Grasp.h
+    Grasping/GraspSet.h
+    Grasping/BasicGraspQualityMeasure.h
+    
+    IK/AdvancedIKSolver.h
+    IK/CoMIK.h
+    IK/ConstrainedHierarchicalIK.h
+    IK/ConstrainedIK.h
+    IK/ConstrainedStackedIK.h
+    IK/Constraint.h
+    IK/DifferentialIK.h
+    IK/FeetPosture.h
+    IK/GazeIK.h
+    IK/GenericIKSolver.h
+    IK/HierarchicalIK.h
+    IK/HierarchicalIKSolver.h
+    IK/IKSolver.h
+    IK/JacobiProvider.h
+    IK/JointLimitAvoidanceJacobi.h
+    IK/PoseQualityExtendedManipulability.h
+    IK/PoseQualityManipulability.h
+    IK/PoseQualityMeasurement.h
+    IK/StackedIK.h
+    IK/SupportPolygon.h
+    IK/constraints/BalanceConstraint.h
+    IK/constraints/CoMConstraint.h
+    IK/constraints/CollisionCheckConstraint.h
+    IK/constraints/JointLimitAvoidanceConstraint.h
+    IK/constraints/OrientationConstraint.h
+    IK/constraints/PoseConstraint.h
+    IK/constraints/PositionConstraint.h
+    IK/constraints/ReferenceConfigurationConstraint.h
+    IK/constraints/TSRConstraint.h
+
+    Import/RobotImporterFactory.h
+    Import/SimoxXMLFactory.h
+    Import/MeshImport/STLReader.h
+    
+    math/AbstractFunctionR1Ori.h
+    math/AbstractFunctionR1R2.h
+    math/AbstractFunctionR1R3.h
+    math/AbstractFunctionR1R6.h
+    math/AbstractFunctionR2R3.h
+    math/AbstractFunctionR3R1.h
+    math/Array3D.h
+    math/Bezier.h
+    math/ClampedNormalDistribution.hpp
+    math/CompositeFunctionR1R6.h
+    math/Contact.h
+    math/ContactList.h
+    math/DataR3R1.h
+    math/DataR3R2.h
+    math/FitPlane.h
+    math/GaussianImplicitSurface3D.h
+    math/GaussianImplicitSurface3DCombined.h
+    math/GaussianImplicitSurface3DNormals.h
+    math/GaussianObjectModel.h
+    math/GaussianObjectModelNormals.h
+    math/Grid3D.h
+    math/GridCacheFloat3.h
+    math/Helpers.h
+    math/ImplicitObjectModel.cpp
+    math/ImplicitPlane.h
+    math/Index3.h
+    math/Kernels.h
+    math/Line.h
+    math/LineR2.h
+    math/LineStrip.h
+    math/LineStripR1RM.h
+    math/LinearContinuedBezier.h
+    math/LinearInterpolatedOrientation.h
+    math/MarchingCubes.h
+    math/MathForwardDefinitions.h
+    math/Plane.h
+    math/Primitive.h
+    math/SimpleAbstractFunctionR1Ori.h
+    math/SimpleAbstractFunctionR1R3.h
+    math/SimpleAbstractFunctionR1R6.h
+    math/SimpleAbstractFunctionR2R3.h
+    math/SimpleAbstractFunctionR3R1.h
+    math/SimpleAbstractFunctionRNRM.h
+    math/TransformedFunctionR1R3.h
+    math/TransformedFunctionR2R3.h
+    math/Triangle.h
+    math/WeightedAverage.h
+    math/statistics/measures.h
+    math/statistics/BoxPlot.h
+    math/statistics/Histogram.h
+    
+    MJCF/Document.h
+    MJCF/elements.h
+    MJCF/elements/has_member.hpp
+    MJCF/elements/core/AnyElement.h
+    MJCF/elements/core/Attribute.h
+    MJCF/elements/core/const_aware_ptr.hpp
+    MJCF/elements/core/Element.h
+    MJCF/elements/core/exceptions.h
+    MJCF/elements/core/mjcf_utils.h
+    MJCF/elements/core/Visitor.h
+    MJCF/elements/types/actuator.h
+    MJCF/elements/types/asset.h
+    MJCF/elements/types/body.h
+    MJCF/elements/types/compiler.h
+    MJCF/elements/types/contact.h
+    MJCF/elements/types/custom.h
+    MJCF/elements/types/default.h
+    MJCF/elements/types/equality.h
+    MJCF/elements/types/keyframe.h
+    MJCF/elements/types/meta.h
+    MJCF/elements/types/option.h
+    MJCF/elements/types/sensor.h
+    MJCF/elements/types/size.h
+    MJCF/elements/types/statistic.h
+    MJCF/elements/types/tendon.h
+    MJCF/elements/types/visual.h
+    MJCF/visitors.h
+    MJCF/visitors/Collector.h
+    
+    Nodes/CameraSensor.h
+    Nodes/CameraSensorFactory.h
+    Nodes/ConditionedLock.h
+    Nodes/ForceTorqueSensor.h
+    Nodes/ForceTorqueSensorFactory.h
+    Nodes/PositionSensor.h
+    Nodes/PositionSensorFactory.h
+    Nodes/RobotNode.h
+    Nodes/RobotNodeActuator.h
+    Nodes/RobotNodeFactory.h
+    Nodes/RobotNodeFixed.h
+    Nodes/RobotNodeFixedFactory.h
+    Nodes/RobotNodePrismatic.h
+    Nodes/RobotNodePrismaticFactory.h
+    Nodes/RobotNodeRevolute.h
+    Nodes/RobotNodeRevoluteFactory.h
+    Nodes/Sensor.h
+    Nodes/SensorFactory.h
+    
+    TimeOptimalTrajectory/Path.h
+    TimeOptimalTrajectory/TimeOptimalTrajectory.h
+    
+    Tools/Gravity.h
+    
+    Transformation/DHParameter.h
+    
+    Util/json/eigen_conversion.h
+    Util/json/eigen_conversion.hpp
+    Util/json/json.hpp
+    Util/xml/tinyxml2.h
+    
+    Visualization/ColorMap.h
+    Visualization/TriMeshModel.h
+    Visualization/TriMeshUtils.h
+    Visualization/Visualization.h
+    Visualization/VisualizationFactory.h
+    Visualization/VisualizationNode.h
+    
+    Workspace/Manipulability.h
+    Workspace/Reachability.h
+    Workspace/VoxelTree6D.hpp
+    Workspace/VoxelTree6DElement.hpp
+    Workspace/VoxelTreeND.hpp
+    Workspace/VoxelTreeNDElement.hpp
+    Workspace/WorkspaceData.h
+    Workspace/WorkspaceDataArray.h
+    Workspace/WorkspaceGrid.h
+    Workspace/WorkspaceRepresentation.h
+    #Workspace/ReachabilityInversion/InverseReachability.h
+    #Workspace/ReachabilityInversion/OrientedWorkspaceGrid.h
+    #Workspace/ReachabilityInversion/ReachabilityProcessor.h
+    #Workspace/ReachabilityInversion/RobotPlacementIK.h
+    #Workspace/ReachabilityInversion/RobotPlacementTrajectoryIK.h
+    
+    XML/BaseIO.h
+    XML/FileIO.h
+    XML/ObjectIO.h
+    XML/RobotIO.h
+    XML/SceneIO.h
+    XML/mujoco/MasslessBodySanitizer.h
+    XML/mujoco/MujocoIO.h
+    
 )
 
 if (Simox_USE_RBDL AND RBDL_FOUND)
diff --git a/VirtualRobot/MJCF/Document.cpp b/VirtualRobot/MJCF/Document.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a69b1066ac20c1b2d68f0f4902fa1f48b48fd5d4
--- /dev/null
+++ b/VirtualRobot/MJCF/Document.cpp
@@ -0,0 +1,111 @@
+#include "Document.h"
+
+#include "elements/core/exceptions.h"
+
+
+namespace mjcf
+{
+
+
+Document::Document()
+{
+    // create root element
+    tinyxml2::XMLElement* xml = doc.NewElement(MujocoRoot::tag.c_str());
+    doc.InsertEndChild(xml);
+    root.reset(new MujocoRoot(this, xml));
+}
+
+void Document::loadFile(const std::string& fileName)
+{
+    tinyxml2::XMLError error = doc.LoadFile(fileName.c_str());
+    if (error != tinyxml2::XML_SUCCESS)
+    {
+        throw MjcfIOError(doc.ErrorStr());
+    }
+}
+
+void Document::saveFile(const std::string& fileName)
+{
+    tinyxml2::XMLError error = doc.SaveFile(fileName.c_str());
+    if (error != tinyxml2::XML_SUCCESS)
+    {
+        throw MjcfIOError(doc.ErrorStr());
+    }
+}
+
+void Document::deepCopyFrom(const Document& source)
+{
+    source.doc.DeepCopy(&this->doc);
+}
+
+void Document::print(std::ostream& os) const
+{
+    tinyxml2::XMLPrinter printer;
+    doc.Print(&printer);
+    os << printer.CStr();
+}
+
+
+
+std::string Document::getModelName() const
+{
+    if (root->isAttributeSet("model"))
+    {
+        return root->getAttribute("model");
+    }
+    else
+    {
+        return "";
+    }
+}
+void Document::setModelName(const std::string& name)
+{
+    root->setAttribute("model", name);
+}
+
+Include Document::addInclude(const std::string& filename)
+{
+    Include include = root->addChild<Include>();
+    include.file = filename;
+    return include;
+}
+
+void Document::setNewElementClass(const std::string& className, bool excludeBody)
+{
+    this->newElementClass = className;
+    this->newElementClassExcludeBody = excludeBody;
+    
+    if (!className.empty() && !default_().hasChild<DefaultClass>("class", className))
+    {
+        default_().addClass(className);
+    }
+}
+
+
+float Document::getFloatCompPrecision() const
+{
+    return floatCompPrecision;
+}
+
+void Document::setFloatCompPrecision(float value)
+{
+    floatCompPrecision = value;
+}
+
+float Document::getDummyMass() const
+{
+    return dummyMass;
+}
+
+void Document::setDummyMass(float value)
+{
+    dummyMass = value;
+}
+
+std::ostream& operator<<(std::ostream& os, const Document& rhs)
+{
+    rhs.print(os);
+    return os;
+}
+
+}
diff --git a/VirtualRobot/MJCF/Document.h b/VirtualRobot/MJCF/Document.h
new file mode 100644
index 0000000000000000000000000000000000000000..1be06a178fec53bb9484ab1096cd91924e097428
--- /dev/null
+++ b/VirtualRobot/MJCF/Document.h
@@ -0,0 +1,231 @@
+#pragma once
+
+#include <iostream>
+#include <memory>
+#include <set>
+
+#include <Eigen/Eigen>
+
+#include <VirtualRobot/Util/xml/tinyxml2.h>
+
+#include "elements.h"
+
+
+namespace mjcf
+{
+
+    /**
+     * @brief A MJCF (Mujoco XML) document.
+     */
+    class Document
+    {
+        
+    public:
+
+        /// Constructor.
+        Document();
+        
+        /// Set the precision for float comparison.
+        float getFloatCompPrecision() const;
+        /// Set the precision for float comparison (used e.g. when comparing
+        /// to zero or identity).
+        void setFloatCompPrecision(float value);
+        /// Get the mass of dummy inertial elements.
+        float getDummyMass() const;
+        /// Set the mass of dummy inertial elements.
+        void setDummyMass(float value);
+        
+        /// Load from an MJCF file.
+        void loadFile(const std::string& fileName);
+        /// Save to an MJCF file.
+        void saveFile(const std::string& fileName);
+        
+        /// Make a deep copy of source to this.
+        void deepCopyFrom(const Document& source);
+        
+        void print(std::ostream& os = std::cout) const;
+
+        std::string getModelName() const;
+        /// Set the name of the Mujoco model.
+        void setModelName(const std::string& name);
+
+        
+        // Section elements (children of top-level 'mujoco' element).
+        CompilerSection  compiler()  { return section<CompilerSection>();   }
+        OptionSection    option()    { return section<OptionSection>();     }
+        SizeSection      size()      { return section<SizeSection>();       }
+        VisualSection    visual()    { return section<VisualSection>();     }
+        StatisticSection statistic() { return section<StatisticSection>();  }
+        DefaultSection   default_()  { return section<DefaultSection>();    }
+        AssetSection     asset()     { return section<AssetSection>();      }
+        Worldbody        worldbody() { return section<Worldbody>();         }
+        ContactSection   contact()   { return section<ContactSection>();    }
+        EqualitySection  equality()  { return section<EqualitySection>();   }
+        TendonSection    tendon()    { return section<TendonSection>();     }
+        ActuatorSection  actuator()  { return section<ActuatorSection>();   }
+        SensorSection    sensor()    { return section<SensorSection>();     } 
+        KeyframeSection  keyframe()  { return section<KeyframeSection>();   }
+
+        Include addInclude(const std::string& filename);
+        
+        /**
+         * @brief Set the class attribute of all new applicable elements
+         * (after calling this method). Pass an empty string to disable class attributes.
+         * @param excludeBody If true (default), the class will not be set on
+         *  new body elements and its children (inertial, joint, ...).
+         *  They should be the childclass attribute of the robot root body.
+         */
+        void setNewElementClass(const std::string& className, bool excludeBody = true);
+        
+        
+        template <class Derived>
+        friend class Element;
+
+        
+    private:
+
+        // METHODS
+
+        /**
+         * @brief Add a new element to a parent.
+         * @param className If not empty, set the class attribute of the new element.
+         * @param first If true, will be inserted as first, otherweise at end (default)
+         */
+        template <class ElementD, class ParentD>
+        ElementD createElement(Element<ParentD> parent, const std::string& className = "", bool front = false);
+        
+        /// Return the first child element of parent with the given element name.
+        /// If it does not exist, create it.
+        template <class ElementD, class ParentD>
+        ElementD getOrCreateElement(Element<ParentD>& parent);
+
+        /// Gets the section element (child of root element). If it does not exist, it is created.
+        template <class SectionD>
+        SectionD section();
+
+        /// Prints the document to os.
+        friend std::ostream& operator<<(std::ostream& os, const Document& rhs);
+        
+        
+    private:
+        
+        // ATTRIBUTES
+        
+        /// The document.
+        tinyxml2::XMLDocument doc;
+        
+        /// The "mujoco" root element.
+        std::unique_ptr<MujocoRoot> root;
+
+        
+        /// Precision when comparing floats (e.g. with zero).
+        float floatCompPrecision = 1e-6f;
+        /// Mass used for dummy inertial elements.
+        float dummyMass = 0.0001f;
+        
+        /// The class added to new elements, if applicable.
+        std::string newElementClass = "";
+        /// Indicate whether body elements and their children shall be
+        /// exluded from setting the class attribute.
+        bool newElementClassExcludeBody = true;
+
+        
+    };
+    
+    using DocumentPtr = std::unique_ptr<Document>;
+    
+
+    
+#include "elements/has_member.hpp"
+    
+    define_has_member(class_);
+    
+    template <class ElementD, class ParentD>
+    ElementD Document::createElement(Element<ParentD> parent, const std::string& className, bool front)
+    {
+        ElementD element(this, doc.NewElement(ElementD::Derived::tag.c_str()));
+
+        auto applyNewElementClass = [this]()
+        {
+            bool isSet = !newElementClass.empty();
+            bool hasClass = has_member(ElementD, class_);
+            bool excludeBecauseBody = std::is_same<ParentD, Body>() && newElementClassExcludeBody;
+                    // body itself does not have a class attribute
+            
+            bool inDefaultClass = std::is_same<ParentD, DefaultClass>();
+            
+            return isSet                     // must not be empty
+                    && hasClass              // must have class attribute
+                    && !excludeBecauseBody   // not excluded because of body exclusion
+                    && !inDefaultClass;      // not part of default class
+        };
+                
+        
+        if (!className.empty())
+        {
+            element.setAttribute("class", className);
+        }
+        else if (applyNewElementClass())
+        {
+            element.setAttribute("class", newElementClass);
+        }
+
+        if (front)
+        {
+            parent.insertFirstChild(element);
+        }
+        else
+        {
+            parent.insertEndChild(element);
+        }
+        return element;
+    }
+
+// cleanup macros by has_member.hpp
+#undef define_has_member
+#undef has_member
+    
+    
+    template <class ElementD, class ParentD>
+    ElementD Document::getOrCreateElement(Element<ParentD>& parent)
+    {
+        ElementD element = parent.template firstChild<ElementD>();
+        
+        if (!element)
+        {
+            element = createElement<ElementD>(parent);
+        }
+        
+        return element;
+    }
+    
+    template<class SectionT>
+    SectionT Document::section()
+    {
+        return getOrCreateElement<SectionT>(*root);
+    }
+    
+    // Implementation of Element::createNewElement, which depends on the 
+    // definition of Document.
+    template <class D>
+    template <class ParentD, class ElementD>
+    ElementD Element<D>::createElement(Element<ParentD> parent, const std::string& className)
+    {
+        return _document->createElement<ElementD, ParentD>(parent, className);
+    }
+    
+    template <class D>
+    void Element<D>::insertComment(const std::string& text, bool front)
+    {
+        tinyxml2::XMLComment* comment = _document->doc.NewComment(text.c_str());
+        if (front)
+        {
+            _element->InsertFirstChild(comment);
+        }
+        else
+        {
+            _element->InsertEndChild(comment);
+        }
+    }
+    
+}
diff --git a/VirtualRobot/MJCF/elements.h b/VirtualRobot/MJCF/elements.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f2ec6f949cb8dc5b0775033b5967be91abc2a21
--- /dev/null
+++ b/VirtualRobot/MJCF/elements.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "elements/core/AnyElement.h"
+#include "elements/types/actuator.h"
+#include "elements/types/asset.h"
+#include "elements/types/body.h"
+#include "elements/types/compiler.h"
+#include "elements/types/contact.h"
+#include "elements/types/default.h"
+#include "elements/types/equality.h"
+#include "elements/types/keyframe.h"
+#include "elements/types/meta.h"
+#include "elements/types/option.h"
+#include "elements/types/sensor.h"
+#include "elements/types/size.h"
+#include "elements/types/statistic.h"
+#include "elements/types/tendon.h"
+#include "elements/types/visual.h"
+
+
+#undef mjcf_AttributeFullNoDef
+#undef mjcf_AttributeFullDef
+
+#undef mjcf_AttributeReq
+#undef mjcf_AttributeOpt
+#undef mjcf_AttributeDef
+
+#undef mjcf_AttributeKwReq
+#undef mjcf_AttributeKwOpt
+#undef mjcf_AttributeKwDef
+
+#undef mjcf_BoolAttributeReq
+#undef mjcf_BoolAttributeOpt
+#undef mjcf_BoolAttributeDef
+    
+#undef mjcf_IntAttributeReq
+#undef mjcf_IntAttributeOpt
+#undef mjcf_IntAttributeDef
+    
+#undef mjcf_FloatAttributeReq
+#undef mjcf_FloatAttributeOpt
+#undef mjcf_FloatAttributeDef
+
+#undef mjcf_StringAttributeReq
+#undef mjcf_StringAttributeOpt
+#undef mjcf_StringAttributeDef
+#undef mjcf_StringAttributeDefEmpty
+
+#undef mjcf_Vector2fAttributeDef
+#undef mjcf_Vector3fAttributeReq
+#undef mjcf_Vector3fAttributeOpt
+#undef mjcf_Vector3fAttributeDef
+    
+#undef mjcf_NameAttribute
+#undef mjcf_ClassAttribute
+#undef mjcf_GroupAttribute
+
+#undef mjcf_RgbAttributeDef
+#undef mjcf_RgbaAttributeDef
+    
+#undef mjcf_PosAttribute
+#undef mjcf_QuatAttribute
+#undef mjcf_PoseAttributes
+
+#undef mjcf_SolimpAttribute
+#undef mjcf_SolrefAttribute
diff --git a/VirtualRobot/MJCF/elements/core/AnyElement.cpp b/VirtualRobot/MJCF/elements/core/AnyElement.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..22ee462c4585e9da9abf85cee6aafef28a58d437
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/AnyElement.cpp
@@ -0,0 +1,7 @@
+#include "AnyElement.h"
+
+namespace mjcf
+{
+    const std::string AnyElement::tag = "";
+}
+
diff --git a/VirtualRobot/MJCF/elements/core/AnyElement.h b/VirtualRobot/MJCF/elements/core/AnyElement.h
new file mode 100644
index 0000000000000000000000000000000000000000..a16af2cc7f50597116d4fb515dec7282186f6761
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/AnyElement.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "Element.h"
+
+
+namespace mjcf
+{
+
+    /**
+     * @brief An element that can hold any type.
+     */
+    class AnyElement : public Element<AnyElement>
+    {
+    public:
+        
+        static const std::string tag;
+        mjcf_ElementDerivedConstructors(AnyElement)
+        
+        /// Construct from any other element type.
+        template <class OtherDerived>
+        AnyElement(const Element<OtherDerived>& other) : 
+            AnyElement(other.template reinterpret<AnyElement>())
+        {}
+        
+        
+        /// Indicate whether *this is an element of type OtherDerived.
+        template <typename OtherDerived>
+        bool is() const { return isElement<OtherDerived>(); }
+        
+        /// Get *this as element of type OtherDerived.
+        /// Should only be called if `is()` is true.
+        template <typename OtherDerived>
+        OtherDerived as() { return { document(), element() }; }
+        
+        template <typename OtherDerived>
+        const OtherDerived as() const { return reinterpret<OtherDerived>(); }
+        
+        
+        /// Return the actual tag.
+        std::string actualTag() const { return element()->Value(); }
+        
+    };
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/Attribute.cpp b/VirtualRobot/MJCF/elements/core/Attribute.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cdab83817271e1f57cb0d0f54b79d33a1c3c5cd6
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/Attribute.cpp
@@ -0,0 +1,14 @@
+#include "Attribute.h"
+
+
+namespace mjcf
+{
+
+Eigen::Vector5f mjcf_solimpDefault()
+{
+    Eigen::Vector5f v;
+    v << 0.9f, 0.95f, 0.001f, 0.5, 2;
+    return v;
+}
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/Attribute.h b/VirtualRobot/MJCF/elements/core/Attribute.h
new file mode 100644
index 0000000000000000000000000000000000000000..df07ca70541f15945f6f9fea737480e57087f73a
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/Attribute.h
@@ -0,0 +1,346 @@
+#pragma once
+
+#include <VirtualRobot/math/Helpers.h>
+
+#include "Element.h"
+
+
+namespace mjcf
+{
+
+    /**
+     * @class Base class for an attribute of an Element<Derived>.
+     * Stores a pointer to the owning element.
+     */
+    template <class Derived>
+    class AttributeBase
+    {
+    public:
+        
+        AttributeBase() : _owner(nullptr) 
+        {}
+        
+        /// Constructor.
+        /// @param owner the owning element (Element instance of which this is a member).
+        AttributeBase(Element<Derived>& owner) : _owner(&owner) 
+        {}
+
+        
+        /* _owner must always point to the element this was constructed with.
+         * We therefore delete copy and move constructors (otherwise, the owner
+         * will be unavailable. In addition, _owner is constant, so it is not
+         * changed by copy or move operators. */
+        
+        /// Deleted copy constructor.
+        AttributeBase(const AttributeBase<Derived>& other) = delete;
+        /// Deleted move constructor.
+        AttributeBase(AttributeBase<Derived>&& other) = delete;
+        
+        
+    protected:
+        /// Get the owning element.
+        Element<Derived>& owner() { return *_owner; }
+        const Element<Derived>& owner() const { return *_owner; }
+        
+    private:
+        /// The owning element (Element instance of which this is a member).
+        /// It must not change after construction, and thus is const-qualified.
+        Element<Derived>* const _owner;
+        
+    };
+
+    
+    
+    /**
+     * @class An attribute of an Element<Derived> of type AttrT.
+     */
+    template <class Derived, typename AttrT>
+    class Attribute : public AttributeBase<Derived>
+    {
+    public:
+        
+        /// Constructor.
+        Attribute(Element<Derived>& element, const std::string& name)
+            : AttributeBase<Derived>(element), name(name)
+        {}
+        
+        /// Get the attribute value (or the default value if the attribute does not exist).
+        virtual AttrT get() const = 0;
+        /// Set the attribute value.
+        void set(const AttrT& value)
+        {
+            this->owner().template setAttribute<AttrT>(name, value);
+        }
+        
+        /// Conversion operator to AttrT for reading.
+        operator AttrT() const
+        {
+            return this->get();
+        }
+        
+        /// Copy assignment operator for writing an attribute value.
+        Attribute& operator=(const AttrT& value)
+        {
+            this->set(value);
+            return *this;
+        }
+        
+        /// Move assignment operator for writing an attribute value.
+        Attribute& operator=(AttrT&& value)
+        {
+            this->set(value);
+            return *this;
+        }
+        
+        /// Copy assignment operator for writing an attribute value.
+        template <class OtherDerived, class OtherAttrT>
+        Attribute& operator=(const Attribute<OtherDerived, OtherAttrT>& attribute)
+        {
+            this->set(attribute.get());
+            return *this;
+        }
+        
+        /// Copy assignment operator for writing an attribute value.
+        template <class OtherDerived, class OtherAttrT>
+        Attribute& operator=(Attribute<OtherDerived, OtherAttrT>&& attribute)
+        {
+            this->set(attribute.get());
+            return *this;
+        }
+        
+        /* Equivalent operators should be called implicitly due to conversion operators.
+        bool operator==(const AttrT& rhs) { return get() == rhs; }
+        bool operator!=(const AttrT& rhs) { return get() != rhs; }
+        */
+        template <class OtherDerived, class OtherAttrT>
+        bool operator==(const Attribute<OtherDerived, OtherAttrT>& rhs) { return get() == rhs.get(); }
+        template <class OtherDerived, class OtherAttrT>
+        bool operator!=(const Attribute<OtherDerived, OtherAttrT>& rhs) { return get() != rhs.get(); }
+        
+        /// Indicate whether the attribute is required (implies no default).
+        virtual bool isRequired() const = 0;
+        /// Indicate whether the attribute is optional or has a default.
+        bool isOptional() const { return !isRequired(); }
+        /// Indicate whether the attribute has a default (implies optional).
+        virtual bool hasDefault() const = 0;
+        
+        /// Indicate whether the attribute is set.
+        bool isSet() const { return this->owner().isAttributeSet(this->name); }
+        
+        
+    protected:
+        
+        std::string name;   ///< The attribute name.
+        
+    };
+
+    template <class Derived, typename AttrT>
+    std::ostream& operator<<(std::ostream& os, const Attribute<Derived, AttrT>& rhs)
+    {
+        os << rhs.get();
+        return os;
+    }
+    
+    
+    /**
+     * @class An attribute of an Element<Derived> of type AttrT
+     * that is required or optional and has no default value.
+     */
+    template <class Derived, typename AttrT>
+    class AttributeNoDef : public Attribute<Derived, AttrT>
+    {
+        using Base = Attribute<Derived, AttrT>;
+    public:
+        
+        /// Construct an required or optional attribute without a default.
+        AttributeNoDef(Element<Derived>& element, const std::string& name, bool required)
+            : Base(element, name), required(required)
+        {}
+        
+        AttrT get() const override
+        {
+            return this->owner().template getAttribute<AttrT>(this->name);
+        }
+        
+        bool isRequired() const override { return  required; }
+        bool hasDefault() const override { return  false; }
+        
+        using Base::operator=;
+        
+        
+    private:
+        
+        bool required;      ///< Whether the attribute is optional.
+    };
+    
+    
+    
+    /**
+     * @class An attribute of an Element<Derived> of type AttrT
+     * that is optional and has a default value.
+     */
+    template <class Derived, typename AttrT>
+    class AttributeDef : public Attribute<Derived, AttrT>
+    {
+        using Base = Attribute<Derived, AttrT>;
+        
+    public:
+        
+        /// Construct an optional attribute with a default.
+        AttributeDef(Element<Derived>& element, const std::string& name, const AttrT& defaultValue)
+            : Base(element, name), defaultValue(defaultValue)
+        {}
+        
+        AttrT get() const override
+        {
+            return this->owner().template getAttribute<AttrT>(this->name, this->defaultValue);
+        }
+        
+        bool isRequired() const override { return  false; }
+        bool hasDefault() const override { return  true; }
+        
+        using Base::operator=;
+        
+        
+    private:
+        
+        AttrT defaultValue; ///< The default value.
+        
+    };
+    
+
+// Macro for a requried or optional Attribute in an Element<Derived> of type AttrT
+// with potentially different memberName and attrName
+#define mjcf_AttributeFullNoDef(Derived, AttrT, memberName, attrName, required) \
+    ::mjcf::AttributeNoDef<Derived, AttrT> memberName {*this, attrName, required}
+    
+// Macro for an optional Attribute in an Element<Derived> of type AttrT
+// with potentially different memberName and attrName.
+#define mjcf_AttributeFullDef(Derived, AttrT, memberName, attrName, defaultValue) \
+    ::mjcf::AttributeDef<Derived, AttrT> memberName {*this, attrName, defaultValue}
+
+    
+// A requried Attribute in an Element<Derived> of type AttrT.
+#define mjcf_AttributeReq(Derived, AttrT, name) \
+    mjcf_AttributeFullNoDef(Derived, AttrT, name, #name, true)
+
+#define mjcf_AttributeOpt(Derived, AttrT, name) \
+    mjcf_AttributeFullNoDef(Derived, AttrT, name, #name, false)
+    
+// An optional Attribute in an Element<Derived> of type AttrT.
+#define mjcf_AttributeDef(Derived, AttrT, name, defaultValue) \
+    mjcf_AttributeFullDef(Derived, AttrT, name, #name, defaultValue)
+
+    
+// Attributes with a name that is a keyword (e.g. "class").
+#define mjcf_AttributeKwReq(Derived, AttrT, name) \
+    mjcf_AttributeFullNoDef(Derived, AttrT, name ## _, #name, true)
+
+#define mjcf_AttributeKwOpt(Derived, AttrT, name) \
+    mjcf_AttributeFullNoDef(Derived, AttrT, name ## _, #name, false)
+    
+#define mjcf_AttributeKwDef(Derived, AttrT, name, defaultValue) \
+    mjcf_AttributeFullDef(Derived, AttrT, name ## _, #name, defaultValue)
+
+
+// bool shorthands
+#define mjcf_BoolAttributeReq(Derived, name) \
+    mjcf_AttributeReq(Derived, bool, name)
+#define mjcf_BoolAttributeOpt(Derived, name) \
+    mjcf_AttributeOpt(Derived, bool, name)
+#define mjcf_BoolAttributeDef(Derived, name, defaultValue) \
+    mjcf_AttributeDef(Derived, bool, name, defaultValue)
+    
+// int shorthands
+#define mjcf_IntAttributeReq(Derived, name) \
+    mjcf_AttributeReq(Derived, int, name)
+#define mjcf_IntAttributeOpt(Derived, name) \
+    mjcf_AttributeOpt(Derived, int, name)
+#define mjcf_IntAttributeDef(Derived, name, defaultValue) \
+    mjcf_AttributeDef(Derived, int, name, defaultValue)
+    
+    
+// float shorthands
+#define mjcf_FloatAttributeReq(Derived, name) \
+    mjcf_AttributeReq(Derived, float, name)
+#define mjcf_FloatAttributeOpt(Derived, name) \
+    mjcf_AttributeOpt(Derived, float, name)
+#define mjcf_FloatAttributeDef(Derived, name, defaultValue) \
+    mjcf_AttributeDef(Derived, float, name, defaultValue)
+    
+// string shorthands
+#define mjcf_StringAttributeReq(Derived, memberName) \
+    mjcf_AttributeReq(Derived, std::string, memberName)
+#define mjcf_StringAttributeOpt(Derived, memberName) \
+    mjcf_AttributeOpt(Derived, std::string, memberName)
+#define mjcf_StringAttributeDef(Derived, memberName, defaultValue) \
+    mjcf_AttributeDef(Derived, std::string, memberName, defaultValue)
+    
+#define mjcf_StringAttributeDefEmpty(Derived, memberName, defaultValue) \
+    mjcf_StringAttributeDef(Derived, std::string, memberName, "")
+
+
+// vector shorthands
+    
+#define mjcf_Vector2fAttributeDef(Derived, name, defaultValue) \
+    mjcf_AttributeDef(Derived, Eigen::Vector2f, name, defaultValue)
+    
+#define mjcf_Vector3fAttributeReq(Derived, name) \
+    mjcf_AttributeReq(Derived, Eigen::Vector3f, name)
+#define mjcf_Vector3fAttributeOpt(Derived, name) \
+    mjcf_AttributeOpt(Derived, Eigen::Vector3f, name)
+#define mjcf_Vector3fAttributeDef(Derived, name, defaultValue) \
+    mjcf_AttributeDef(Derived, Eigen::Vector3f, name, defaultValue)
+    
+    
+// name
+#define mjcf_NameAttribute(Derived) \
+    mjcf_StringAttributeOpt(Derived, name)
+    
+// class
+#define mjcf_ClassAttribute(Derived) \
+    mjcf_AttributeKwReq(Derived, std::string, class)
+
+// group
+#define mjcf_GroupAttribute(Derived) \
+    mjcf_IntAttributeDef(Derived, group, 0)
+
+
+// RGB
+#define mjcf_RgbAttributeDef(Derived, name, defaultValue) \
+    mjcf_Vector3fAttributeDef(Derived, name, defaultValue)
+    
+#define mjcf_RgbaAttributeDef(Derived, name, defaultValue) \
+    mjcf_AttributeDef(Derived, Eigen::Vector4f, name, defaultValue)
+
+    
+// pos
+#define mjcf_PosAttribute(Derived) \
+    mjcf_Vector3fAttributeDef(Derived, pos, Eigen::Vector3f::Zero())
+
+// quat
+#define mjcf_QuatAttribute(Derived) \
+    mjcf_AttributeDef(Derived, Eigen::Quaternionf, quat, Eigen::Quaternionf::Identity())
+
+// pose = pos + quat
+#define mjcf_PoseAttributes(Derived) \
+    Eigen::Matrix4f getPose() const                                     \
+    { return math::Helpers::Pose(pos.get(), quat.get()); }              \
+    void setPose(const Eigen::Matrix4f& p)                              \
+    {   pos = math::Helpers::Position(p);                               \
+        quat = Eigen::Quaternionf(math::Helpers::Orientation(p));   }   \
+    mjcf_PosAttribute(Derived);                                         \
+    mjcf_QuatAttribute(Derived)
+
+
+Eigen::Vector5f mjcf_solimpDefault();
+
+// solref
+#define mjcf_SolrefAttribute(Derived) \
+    mjcf_AttributeDef(Derived, Eigen::Vector2f, solref, Eigen::Vector2f(0.02f, 1.f))
+// solimp
+#define mjcf_SolimpAttribute(Derived) \
+    mjcf_AttributeDef(Derived, Eigen::Vector5f, solimp, ::mjcf::mjcf_solimpDefault())
+    
+    
+} 
diff --git a/VirtualRobot/MJCF/elements/core/Element.cpp b/VirtualRobot/MJCF/elements/core/Element.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..114513eaf07a443165d2a50e46b9f8c62dd79040
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/Element.cpp
@@ -0,0 +1,2 @@
+#include "Element.h"
+
diff --git a/VirtualRobot/MJCF/elements/core/Element.h b/VirtualRobot/MJCF/elements/core/Element.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc7f94a7afa8648235e90c2e5686712835f814d0
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/Element.h
@@ -0,0 +1,514 @@
+#pragma once
+
+#include <VirtualRobot/Util/xml/tinyxml2.h>
+
+#include "const_aware_ptr.hpp"
+#include "exceptions.h"
+#include "mjcf_utils.h"
+#include "Visitor.h"
+
+
+namespace mjcf
+{
+
+    // Forward declaration.
+    class Document;
+    
+    template <class _Derived>
+    class Element
+    {
+    public:
+        
+        using Derived = _Derived;
+        
+        // Make all Element<*> friends of each other.
+        template <class OtherDerived> friend class Element;
+        
+        
+    public:
+
+        // CONSTRUCTORS
+        
+        /// Empty constructor.
+        Element() {}
+        
+        /**
+         * @brief Construct and element with given document and underlying (tinyxml2) element.
+         * @throws error::InvalidElementTag if `element`'s tag does not match `Derived::tag`.
+         */
+        Element(Document* document, tinyxml2::XMLElement* element);
+        
+    protected:
+        
+        /**
+         * Only allow inheriting classes to construct with a const pointers,
+         * since const-ness is effectively cast away on construction, and offering
+         * it publicly would create a false sense of security at this point.
+         */
+        Element(const Document* document, const tinyxml2::XMLElement* element);
+        
+        
+    public:
+        
+        // TYPE CHECKING
+        
+        /// Indicate whether this is an element of the given type.
+        template <class OtherT>
+        static bool isSame() { return std::is_same<Derived, typename OtherT::Derived>(); }
+
+        
+        /// Indicate whether the underlying element's tag is OtherT's tag.
+        /// This should be true at virtually all times.
+        template <class OtherT>
+        bool isElement() const { return OtherT::tag.empty() || std::string(_element->Value()) == OtherT::tag; }
+        
+        
+        // ATTRIBUTES
+        
+        /// Indicate whether this element has an attribute with the given name.
+        bool isAttributeSet(const std::string& attrName) const;
+
+        /// Get attribute value.
+        template <typename AttrT = std::string>
+        AttrT getAttribute(const std::string& name) const;
+        /// Get the attribute value, or the default value if it does not exist.
+        template <typename AttrT = std::string>
+        AttrT getAttribute(const std::string& name, const AttrT& defaultValue) const;
+        /// Set the attribute.
+        template <typename AttrT>
+        void setAttribute(const std::string& name, const AttrT& value);
+        
+        std::vector<std::string> getSetAttributeNames() const;
+        
+        
+        // CHILDREN
+        
+        /// Indicate whether this element has any children.
+        bool hasChildren() const;
+        
+        /// Indicate whether there is a child of the given type.
+        template <class OtherDerived>
+        bool hasChild() const;
+        /// Indicate whether there is a child for which the given predicate is true.
+        template <class OtherDerived>
+        bool hasChild(std::function<bool(OtherDerived)> predicate) const;
+        /// Indicate whether there is a child with the given attribute value.
+        template <class OtherDerived>
+        bool hasChild(const std::string& attrName, const std::string& attrValue) const;
+        
+        /// Get the first child of the given type.
+        template <class OtherDerived>
+        OtherDerived firstChild() const;
+        /// Get the first child of the given type for which the given predicate is true.
+        template <class OtherDerived>
+        OtherDerived firstChild(std::function<bool(OtherDerived)> predicate) const;
+        /// Get the first child of the given type with the given attribute value.
+        template <class OtherDerived>
+        OtherDerived firstChild(const std::string& attrName, const std::string& attrValue) const;
+        
+        
+        // SIBLINGS
+        
+        /// Get the next sibling element of the given type.
+        template <class OtherDerived>
+        OtherDerived nextSiblingElement() const;
+        /// Get the next sibling element of the given type for which the predicate is true.
+        template <class OtherDerived>
+        OtherDerived nextSiblingElement(std::function<bool(OtherDerived)> predicate) const;
+        /// Get the next sibling element of the given type with the given attribute value.
+        template <class OtherDerived>
+        OtherDerived nextSiblingElement(const std::string& attrName, const std::string& attrValue) const;
+
+        
+        // PARENT
+        
+        /// Get the parent element.
+        template <class ParentDerived>
+        ParentDerived parent();
+        template <class ParentDerived>
+        const ParentDerived parent() const;
+        
+        
+        // INSERTION & DELETION
+
+        /// Add a new child of this with of given type.
+        template <class OtherDerived>
+        OtherDerived addChild(const std::string& className = "");
+        
+        /// Get the first child of type OtherDerived. If there is none, add one.
+        template <class OtherDerived>
+        OtherDerived getOrCreateChild();
+        
+        
+        template <class OtherDerived>
+        void insertChild(Element<OtherDerived>& element, bool front = false);
+        
+        /// Insert an element at the front.
+        template <class OtherDerived>
+        void insertFirstChild(Element<OtherDerived>& element);
+        /// Insert an element at the end.
+        template <class OtherDerived>
+        void insertEndChild(Element<OtherDerived>& element);
+
+        /// Delete given child from this.
+        template <class OtherDerived>
+        void deleteChild(Element<OtherDerived>& element);
+        
+        
+        /// Insert a comment as child of *this.
+        void insertComment(const std::string& text, bool front = false);
+        
+        
+        // VISITING
+        
+        /// Accept a hierarchical visit of the elements in *this.
+        /// @see tinyxml2::XMLNode::Accept()
+        bool accept(Visitor& visitor);
+        
+        
+        // CLONING AND TRANSFORMATION
+        
+        /// Create a deep clone of this element.
+        Derived deepClone() const;
+        
+        /**
+         * @brief Transform this element to another type.
+         * 
+         * Change the underlying element's tag and return the element as the 
+         * new type. Using `*this` afterwards can result in unexpected 
+         * behaviour (and should in general be avoided), so use this method
+         * with caution!
+         */
+        template <class OtherDerived>
+        OtherDerived transform();
+        
+        
+        /**
+         * @brief Reinterpret this element as the given element type.
+         * This is only safe from and to `AnyElement`.
+         */
+        // (Ideally, this functionality would only be accessible from AnyElement.
+        //  However, giving AnyElement access to other types' document() and element() seems not
+        //  to work without making document() and element() public (friend declaration does not
+        //  seem to work). This seems to only effect the const methods.
+        template <class OtherDerived>
+        OtherDerived reinterpret() const { return Element<OtherDerived>(_document, _element); }
+        
+        
+        // OPERATORS
+        
+        /// Indicate whether this contains a valid element.
+        operator bool() const { return bool(_element); }
+        
+        template <typename Derived>
+        friend std::ostream& operator<<(std::ostream& os, const Element<Derived>& element);
+        
+        
+    protected:
+        
+        Document* document() { return _document; }
+        const Document* document() const  { return _document; }
+        
+        tinyxml2::XMLElement* element() { return _element; }
+        const tinyxml2::XMLElement* element() const { return _element; }
+
+        
+    private:
+
+        /// Get Derived::tag as c-string, or nullptr if Derived::tag is empty (AnyElement).
+        /// The result can be passed to tinyxml2 methods taking element values (tags) as filters.
+        static const char* tag_c_str() { return Derived::tag.empty() ? nullptr : Derived::tag.c_str(); }
+        
+        /// Use document to create a new element of type ElementD with given parent.
+        template <class ParentD, class ElementD>
+        ElementD createElement(Element<ParentD> parent, const std::string& className = "");
+        
+        void assertElemValueEqualsTag();
+        
+        template <class OtherDerived>
+        std::function<bool(OtherDerived)> predicateWithAttrib(
+                const std::string& attrName, const std::string& attrValue) const;
+        
+        Document* _document = nullptr;
+        detail::const_aware_ptr<tinyxml2::XMLElement> _element = nullptr;
+        
+    };
+    
+    
+    template <class D>
+    Element<D>::Element(Document* document, tinyxml2::XMLElement* element) : 
+        _document(document), _element(element)
+    {
+        assertElemValueEqualsTag();
+    }
+    
+    template <class D>
+    Element<D>::Element(const Document* document, const tinyxml2::XMLElement* element) :
+        Element(const_cast<Document*>(document), const_cast<tinyxml2::XMLElement*>(element))
+    {}
+    
+    template <class D>
+    bool Element<D>::isAttributeSet(const std::string& attrName) const
+    {
+        return _element->Attribute(attrName.c_str()) != nullptr;
+    }
+    
+    template <class D>
+    template <typename AttrT>    
+    AttrT Element<D>::getAttribute(const std::string& name) const
+    {
+        const char* attr = _element->Attribute(name.c_str());
+        if (!attr)
+        {
+            throw AttribNotSetError(name);
+        }
+        AttrT value;
+        fromAttr(attr, value);
+        return value;
+    }
+    
+    template <class D>
+    template <typename AttrT>
+    AttrT Element<D>::getAttribute(const std::string& name, const AttrT& defaultValue) const
+    {
+        return isAttributeSet(name) ? getAttribute<AttrT>(name) : defaultValue;
+    }
+    
+    template <class D>
+    template<typename AttrT>
+    void Element<D>::setAttribute(const std::string& name, const AttrT& value)
+    {
+        std::string attrStr = toAttr(value);
+        _element->SetAttribute(name.c_str(), attrStr.c_str());
+    }
+
+    template <class D>
+    std::vector<std::string> Element<D>::getSetAttributeNames() const
+    {
+        std::vector<std::string> names;
+        for (auto* attr = _element->FirstAttribute(); attr; attr = attr->Next())
+        {
+            names.emplace_back(attr->Name());
+        }
+        return names;
+    }
+    
+    template <class D>
+    bool Element<D>::hasChildren() const
+    {
+        return !_element->NoChildren();
+    }
+    
+    template <class D>
+    template <class OtherD>
+    bool Element<D>::hasChild() const
+    {
+        return firstChild<OtherD>();
+    }
+    
+    template <class D>
+    template <class OtherD>
+    bool Element<D>::hasChild(std::function<bool(OtherD)> predicate) const
+    {
+        return firstChild<OtherD>(predicate);
+    }
+    
+    template <class D>
+    template <class OtherD>
+    bool Element<D>::hasChild(const std::string& attrName, const std::string& attrValue) const
+    {
+        return firstChild<OtherD>(attrName, attrValue);
+    }
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::firstChild() const
+    {
+        return Element<OtherD>(_document, /*may be null*/ 
+                               _element->FirstChildElement(OtherD::tag_c_str()));
+    }
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::firstChild(std::function<bool(OtherD)> predicate) const
+    {
+        for (OtherD child = firstChild<OtherD>(); child;
+             child = child.template nextSiblingElement<OtherD>())
+        {
+            if (predicate(child))
+            {
+                return child;
+            }
+        }
+        return {};
+    }
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::firstChild(const std::string& attrName, const std::string& attrValue) const
+    {
+        return firstChild<OtherD>(predicateWithAttrib<OtherD>(attrName, attrValue));
+    }
+
+
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::nextSiblingElement() const
+    {
+        return Element<OtherD>(_document, _element->NextSiblingElement(OtherD::tag_c_str()));
+    }
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::nextSiblingElement(std::function<bool (OtherD)> predicate) const
+    {
+        for (OtherD sibling = nextSiblingElement<OtherD>(); sibling;
+             sibling = sibling.template nextSiblingElement<OtherD>())
+        {
+            if (predicate(sibling))
+            {
+                return sibling;
+            }
+        }
+        return {};
+    }
+    
+    template <class D>
+    template<class OtherD>
+    OtherD Element<D>::nextSiblingElement(const std::string& attrName, const std::string& attrValue) const
+    {
+        return nextSiblingElement<OtherD>(predicateWithAttrib<OtherD>(attrName, attrValue));
+    }
+    
+    
+    template <class D>
+    template <class ParentDerived>
+    ParentDerived Element<D>::parent()
+    {
+        return { _document, _element->Parent()->ToElement() };
+    }
+    
+    template <class D>
+    template <class ParentDerived>
+    const ParentDerived Element<D>::parent() const
+    {
+        return Element<ParentDerived>(_document, _element->Parent()->ToElement());
+    }
+    
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::addChild(const std::string& className)
+    {
+        return createElement<D, OtherD>(*this, className);
+    }
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::getOrCreateChild()
+    {
+        OtherD child = firstChild<OtherD>();
+        if (!child)
+        {
+            child = addChild<OtherD>();
+        }
+        return child;
+    }
+    
+    
+    template <class D>
+    template <class OtherD>
+    void Element<D>::insertChild(Element<OtherD>& element, bool front)
+    {
+        front ? insertFirstChild(element) : insertEndChild(element());
+    }
+    
+    template <class D>
+    template <class OtherD>
+    void Element<D>::insertFirstChild(Element<OtherD>& element)
+    {
+        _element->InsertFirstChild(element._element);
+    }
+    
+    template <class D>
+    template <class OtherD>
+    void Element<D>::insertEndChild(Element<OtherD>& element)
+    {
+        _element->InsertEndChild(element._element);
+    }
+    
+    template <class D>
+    template <class OtherD>
+    void Element<D>::deleteChild(Element<OtherD>& element)
+    {
+        _element->DeleteChild(element._element);
+    }
+    
+    template <class D>
+    bool Element<D>::accept(Visitor& visitor)
+    {
+        return _element->Accept(visitor.adapter());
+    }
+    
+    template <class D>
+    auto Element<D>::deepClone() const -> Derived
+    {
+        return { _document, _element->DeepClone(nullptr)->ToElement() };
+    }
+    
+    template <class D>
+    template <class OtherD>
+    OtherD Element<D>::transform()
+    {
+        _element->SetValue(OtherD::tag.c_str());
+        return { _document, _element };
+    }
+    
+    template <class D>
+    void Element<D>::assertElemValueEqualsTag()
+    {
+        if (_element && !isElement<D>())
+        {
+            throw error::InvalidElementTag(Derived::tag, _element->Value());
+        }
+    }
+    
+    template <class D>
+    template <class OtherDerived>
+    std::function<bool(OtherDerived)> Element<D>::predicateWithAttrib(
+            const std::string& attrName, const std::string& attrValue) const
+    {
+        return [&attrName, &attrValue](OtherDerived e)
+        { 
+            return e.isAttributeSet(attrName) && e.getAttribute(attrName) == attrValue;
+        };
+    }
+    
+    template <class D>
+    std::ostream& operator<<(std::ostream& os, const Element<D>& element)
+    {
+        os << "MJCF Element '" << D::tag << "' (-> " << element._element << ")";
+        return os;
+    }
+    
+
+#define mjcf_ElementDerivedConstructorsBase(Base, Derived)  \
+    Derived() : Base<Derived>() {}                   \
+    Derived(Document* document, ::tinyxml2::XMLElement* elem) : Base<Derived>(document, elem) {} \
+    Derived(const Base<Derived>& base) : Base<Derived>(base) {}      \
+    Derived(const Derived& other) : Base<Derived>(other) {} \
+    Derived(Derived&& other) : Base<Derived>(other) {}      \
+    Derived& operator=(const Base<Derived>& base)           \
+    { Base<Derived>::operator=(base);  return *this; }      \
+    Derived& operator=(const Derived& other)                \
+    { Base<Derived>::operator=(other); return *this; }      \
+    Derived& operator=(Derived&& other)                     \
+    { Base<Derived>::operator=(other); return *this; }
+    
+    
+#define mjcf_ElementDerivedConstructors(Derived)            \
+    mjcf_ElementDerivedConstructorsBase(Element, Derived)
+    
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/Visitor.cpp b/VirtualRobot/MJCF/elements/core/Visitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..668b442902ef62964c409dbae3dad9c4ce28d847
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/Visitor.cpp
@@ -0,0 +1,43 @@
+#include "Visitor.h"
+
+#include "AnyElement.h"
+
+namespace mjcf
+{
+
+Visitor::Adapter::Adapter(Visitor& owner) : 
+    owner(owner)
+{}
+
+bool Visitor::Adapter::VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute*)
+{
+    return owner.visitEnter(owner.cast(element));
+}
+
+bool Visitor::Adapter::VisitExit(const tinyxml2::XMLElement& element)
+{
+    return owner.visitExit(owner.cast(element));
+}
+
+Visitor::Visitor(Document& document) : document(document)
+{}
+
+Visitor::Adapter* Visitor::adapter()
+{
+    return &_adapter;
+}
+
+const Visitor::Adapter* Visitor::adapter() const
+{
+    return &_adapter;
+}
+
+const AnyElement Visitor::cast(const tinyxml2::XMLElement& element)
+{
+    // The constructor of Element requires a non-const element pointer.
+    // As AnyElement is passed as const& to the user-provided visit method,
+    // this const cast should be sufficiently safe.
+    return { &document, const_cast<tinyxml2::XMLElement*>(&element) };
+}
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/Visitor.h b/VirtualRobot/MJCF/elements/core/Visitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa50051feb03ad7fa75a6e0a7588cd59c6936809
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/Visitor.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <VirtualRobot/Util/xml/tinyxml2.h>
+
+
+namespace mjcf
+{
+    class AnyElement;
+    class Document;
+    class Visitor;
+
+    
+    class Visitor
+    {
+    public:
+        class Adapter : public tinyxml2::XMLVisitor
+        {
+        public:
+            Adapter(Visitor& owner);
+            
+            virtual bool VisitEnter(const tinyxml2::XMLElement& element,
+                                    const tinyxml2::XMLAttribute*) override;
+            virtual bool VisitExit(const tinyxml2::XMLElement& element) override;
+            
+        private:
+            Visitor& owner;
+        };
+        
+        friend class Adapter;
+        
+        
+    public:
+        
+        Visitor(Document& document);
+        virtual ~Visitor() = default;
+        
+        virtual bool visitEnter(const AnyElement&) { return true; }
+        virtual bool visitExit(const AnyElement&) { return true; }
+        
+        
+        Adapter* adapter();
+        const Adapter* adapter() const;
+
+        
+    private:
+        
+        const AnyElement cast(const tinyxml2::XMLElement& element);
+
+        Document& document;
+        Adapter _adapter { *this };
+        
+    };
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/const_aware_ptr.hpp b/VirtualRobot/MJCF/elements/core/const_aware_ptr.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..de0088d4b64f955890107d46428d7f010c8149d6
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/const_aware_ptr.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+namespace mjcf { namespace detail
+{
+
+    template <typename T>
+    class const_aware_ptr
+    {
+    public:
+      const_aware_ptr(T* p = nullptr) : _p(p) {}
+    
+      //void operator=(T* p) { this->_p = p; }
+      
+      operator T*() { return _p; }
+      operator const T*() const { return _p; }
+      
+      operator bool() const { return _p; }
+      
+      T* operator->() { return _p; }
+      const T* operator->() const { return _p; }
+
+    private:
+      T* _p;
+      
+    };
+    
+}}
diff --git a/VirtualRobot/MJCF/elements/core/exceptions.cpp b/VirtualRobot/MJCF/elements/core/exceptions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3d0784c38c959b1f8b603938cb5860834c70dc85
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/exceptions.cpp
@@ -0,0 +1,37 @@
+#include "exceptions.h"
+
+#include <typeinfo>
+
+
+namespace mjcf
+{
+
+MjcfError::MjcfError(const std::string& message) : std::runtime_error(message)
+{}
+
+MjcfIOError::MjcfIOError(const std::string& message) : MjcfError (message)
+{}
+
+AttribNotSetError::AttribNotSetError(const std::string& name) : 
+    MjcfError("Attrib '" + name + "' (without default) not set.")
+{}
+
+ParseAttributeError::ParseAttributeError(
+        const std::string& source, 
+        const std::type_info& targetType, 
+        const std::string& reason) :
+    MjcfError("Could not parse attribute string '" + source + "' to " + targetType.name() + ".\n"
+              "Reason: " + reason)
+{}
+
+namespace error
+{
+
+InvalidElementTag::InvalidElementTag(const std::string& expected, const std::string& actual) :
+    MjcfError ("Expected tag '" + expected + "', but received '" + actual + "'.")
+{}
+
+}
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/exceptions.h b/VirtualRobot/MJCF/elements/core/exceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..34fa96bb1ab8ff8200fa75428f78560c5b2de4a1
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/exceptions.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <stdexcept>
+
+namespace mjcf
+{
+
+    class MjcfError : public std::runtime_error
+    {
+    public:
+        MjcfError(const std::string& message);
+    };
+
+
+    /// Indicates an error in load/saveFile.
+    class MjcfIOError : public MjcfError
+    {
+    public:
+        MjcfIOError(const std::string& message);
+    };
+
+    
+    /// Indicates that an attribute without default was not set when it was 
+    /// attempted to read.
+    class AttribNotSetError : public MjcfError
+    {
+    public:
+        AttribNotSetError(const std::string& name);
+    };
+    
+    /// Indicates that an attribute without default was not set when it was 
+    /// attempted to read.
+    class ParseAttributeError : public MjcfError
+    {
+    public:
+        ParseAttributeError(const std::string& source, const std::type_info& targetType,
+                            const std::string& reason);
+    };
+    
+namespace error
+{
+
+    class InvalidElementTag : public MjcfError
+    {
+    public:
+        InvalidElementTag(const std::string& expected, const std::string& actual);
+    };
+    
+}
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/core/mjcf_utils.cpp b/VirtualRobot/MJCF/elements/core/mjcf_utils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..993ab7e1e8f98c55846a6690898a57ad38c4fb40
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/mjcf_utils.cpp
@@ -0,0 +1,80 @@
+#include "mjcf_utils.h"
+
+#include <algorithm>
+#include <map>
+
+
+namespace mjcf
+{
+
+    std::size_t commonPrefixLength(const std::string& a, const std::string& b)
+    {
+        const std::string* smaller = &a;
+        const std::string* bigger = &b;
+        if (b.size() < a.size())
+        {
+            std::swap(smaller, bigger);
+        }
+
+        auto mismatch = std::mismatch(smaller->begin(), smaller->end(),
+                                      bigger->begin()).first;
+        return std::size_t(std::distance(smaller->begin(), mismatch));
+    }
+    
+    template <>
+    std::string toAttr<bool>(const bool& b)
+    {
+        static const std::string strings[] = { "false", "true" };
+        return strings[int(b)];
+    }
+    
+    void fromAttr(const std::string& valueStr, bool& value)
+    {
+        static const std::map<std::string, bool> map = {
+            { "true", true },
+            { "false", false },
+            { "1", true },
+            { "0", false },
+        };
+        value = map.at(valueStr);
+    }
+
+    Eigen::Vector2f strToVec2(const char* string)
+    {
+        Eigen::Vector2f v;
+        sscanf(string, "%f %f", &v(0), &v(1));
+        return v;
+    }
+
+    Eigen::Vector3f strToVec3(const char* string)
+    {
+        Eigen::Vector3f v;
+        sscanf(string, "%f %f %f", &v(0), &v(1), &v(2));
+        return v;
+    }
+
+    Eigen::Quaternionf strToQuat(const char* string)
+    {
+        Eigen::Quaternionf q;
+        sscanf(string, "%f %f %f %f", &q.w(), &q.x(), &q.y(), &q.z());
+        return q;
+    }
+
+
+    
+    bool equals(const char* lhs, const char* rhs)
+    {
+        return strcmp(lhs, rhs) == 0;
+    }
+    
+}
+
+bool std::operator==(const char* lhs, const std::string& rhs)
+{
+    return mjcf::equals(lhs, rhs.c_str());
+}
+
+bool std::operator==(const std::string& lhs, const char* rhs)
+{
+    return mjcf::equals(lhs.c_str(), rhs);
+}
diff --git a/VirtualRobot/MJCF/elements/core/mjcf_utils.h b/VirtualRobot/MJCF/elements/core/mjcf_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdc534e6742f9216e371ee7e92f586e426bff00d
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/core/mjcf_utils.h
@@ -0,0 +1,210 @@
+#pragma once
+
+#include <string>
+#include <type_traits>
+
+#include <Eigen/Eigen>
+#include <boost/lexical_cast.hpp>
+
+#include "exceptions.h"
+
+
+namespace std
+{
+    bool operator==(const char* lhs, const string& rhs);
+    bool operator==(const string& lhs, const char* rhs);
+}
+
+namespace Eigen
+{
+    using Vector5f = Eigen::Matrix<float, 5, 1>;
+    using Vector6f = Eigen::Matrix<float, 6, 1>;
+    using Vector7f = Eigen::Matrix<float, 7, 1>;
+
+    template<typename Derived>
+    struct is_matrix_expression : 
+            std::is_base_of<Eigen::MatrixBase<typename std::decay<Derived>::type>, typename std::decay<Derived>::type>
+    {};
+    
+    template<typename Derived>
+    struct is_quaternion_expression : 
+            std::is_base_of<Eigen::QuaternionBase<typename std::decay<Derived>::type>, typename std::decay<Derived>::type>
+    {};
+    
+    template<typename Derived>
+    struct is_eigen_expression : 
+            is_matrix_expression<Derived>, is_quaternion_expression<Derived>
+    {};
+} 
+
+
+namespace mjcf
+{
+
+    // Get lenght of common prefix of two strings (was used for mergin body names).
+    std::size_t commonPrefixLength(const std::string& a, const std::string& b);
+
+    bool equals(const char* lhs, const char* rhs);
+    
+    
+    // VALUE -> ATTRIBUTE
+    
+    // Convert to MJCF XML attribute format.
+    
+    template <typename AttrT,
+              typename std::enable_if<!Eigen::is_eigen_expression<AttrT>::value, AttrT>::type* = nullptr>
+    std::string toAttr(const AttrT& b);
+    template <>
+    std::string toAttr<bool>(const bool& b);
+    template <typename Derived>
+    std::string toAttr(const Eigen::MatrixBase<Derived>& mat);
+    template <typename Derived>
+    std::string toAttr(const Eigen::QuaternionBase<Derived>& quat);
+
+
+    // ATTRIBUTE -> VALUE
+    
+    // Convert from MJCF XML attribute.
+    Eigen::Vector2f strToVec2(const char* string);
+    Eigen::Vector3f strToVec3(const char* string);
+    Eigen::Quaternionf strToQuat(const char* string);
+    
+    
+    
+    /// Single values via boost::lexical cast. Only enabled for non-Eigen types.
+    template <typename AttrT,
+              typename std::enable_if<!Eigen::is_eigen_expression<AttrT>::value, AttrT>::type* = nullptr>
+    void fromAttr(const std::string& valueStr, AttrT& value);
+    
+    /// Bool
+    void fromAttr(const std::string& valueStr, bool& value);
+    
+    /// Eigen Matrix and vectors
+    template <typename Derived> 
+    void fromAttr(const std::string& valueStr, Eigen::MatrixBase<Derived>& value);
+    /// Eigen Quaternions
+    template <typename Derived> 
+    void fromAttr(const std::string& valueStr, Eigen::QuaternionBase<Derived>& value);
+
+    
+    
+    template <typename Scalar>
+    std::vector<Scalar> parseCoeffs(const std::string& string, char delim = ' ');
+    
+    
+    // DEFINITIONS of templated methods
+
+    template <typename AttrT,
+              typename std::enable_if<!Eigen::is_eigen_expression<AttrT>::value, AttrT>::type*>
+    std::string toAttr(const AttrT& b)
+    {
+        static_assert (!Eigen::is_eigen_expression<AttrT>::value, "Resolved an Eigen type.");
+        static_assert (!std::is_same<bool, AttrT>::value, "Resolved bool.");
+        return boost::lexical_cast<std::string>(b);
+    }
+    
+    template<typename Derived>
+    std::string toAttr(const Eigen::MatrixBase<Derived>& mat)
+    {
+        static const Eigen::IOFormat iof 
+        {
+            Eigen::FullPrecision, Eigen::DontAlignCols, " ", " ", "", "", "", ""
+        };
+    
+        std::stringstream ss;
+        ss << mat.format(iof);
+        return ss.str();
+    }
+    
+    template<typename Derived>
+    std::string toAttr(const Eigen::QuaternionBase<Derived>& quat)
+    {
+        std::stringstream ss;
+        ss << quat.w() << " " << quat.x() << " " << quat.y() << " " << quat.z();
+        return ss.str();
+    }
+
+    
+    template <typename AttrT,
+              typename std::enable_if<!Eigen::is_eigen_expression<AttrT>::value, AttrT>::type*>
+    void fromAttr(const std::string& valueStr, AttrT& value)
+    {
+        static_assert (!Eigen::is_eigen_expression<AttrT>::value, "Resolved an Eigen type.");
+        value = boost::lexical_cast<AttrT>(valueStr);
+    }
+    
+    template <typename Derived> 
+    void fromAttr(const std::string& valueStr, Eigen::MatrixBase<Derived>& value)
+    {
+        using Matrix = Eigen::MatrixBase<Derived>;
+        using Scalar = typename Matrix::Scalar;
+        
+        std::vector<Scalar> coeffs;
+        try 
+        {
+            coeffs = parseCoeffs<Scalar>(valueStr);
+        }
+        catch (const std::bad_cast& e) 
+        {
+            throw mjcf::ParseAttributeError(valueStr, typeid(Matrix), e.what());
+        }
+        
+        if (value.size() >= 0 && static_cast<long>(coeffs.size()) != value.size())
+        {
+            throw mjcf::ParseAttributeError(valueStr, typeid(Matrix), "Number of coefficients does not match.");
+        }
+        
+        long i = 0;
+        for (const auto& coeff : coeffs)
+        {
+            value(i++) = coeff;
+        }
+    }
+    
+    template <typename Derived> 
+    void fromAttr(const std::string& valueStr, Eigen::QuaternionBase<Derived>& value)
+    {
+        using Quaternion = Eigen::QuaternionBase<Derived>;
+        using Scalar = typename Quaternion::Scalar;
+        std::vector<Scalar> coeffs;
+        
+        try 
+        {
+            coeffs = parseCoeffs<Scalar>(valueStr);
+        }
+        catch (const std::bad_cast& e) 
+        {
+            throw mjcf::ParseAttributeError(valueStr, typeid(Quaternion), e.what());
+        }
+        
+        
+        if (coeffs.size() != 4)
+        {
+            throw mjcf::ParseAttributeError(valueStr, typeid(Quaternion),
+                                            "Number of coefficients does not match.");
+        }
+        
+        value.w() = coeffs[0];
+        value.x() = coeffs[1];
+        value.y() = coeffs[2];
+        value.z() = coeffs[3];
+    }
+    
+    
+    template <typename Scalar>
+    std::vector<Scalar> parseCoeffs(const std::string& string, char delim)
+    {
+        std::vector<Scalar> coeffs;
+
+        std::stringstream ss(string);
+        for (std::string valueStr; std::getline(ss, valueStr, delim);)
+        {
+            // may throw boost::bad_lexical_cast (derives from std::bad_cast)
+            Scalar value = boost::lexical_cast<Scalar>(valueStr);
+            coeffs.push_back(value);
+        }
+
+        return coeffs;
+    }
+}
+
diff --git a/VirtualRobot/MJCF/elements/has_member.hpp b/VirtualRobot/MJCF/elements/has_member.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1f4f2239ad6e6b5a7f682308421152e43048f229
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/has_member.hpp
@@ -0,0 +1,34 @@
+// from: https://gist.github.com/maddouri/0da889b331d910f35e05ba3b7b9d869b
+
+// A compile-time method for checking the existence of a class member
+// @see https://general-purpose.io/2017/03/10/checking-the-existence-of-a-cpp-class-member-at-compile-time/
+
+// This code uses "decltype" which, according to http://en.cppreference.com/w/cpp/compiler_support
+// should be supported by Clang 2.9+, GCC 4.3+ and MSVC 2010+ (if you have an older compiler, please upgrade :)
+// As of "constexpr", if not supported by your compiler, you could try "const"
+// or use the value as an inner enum value e.g. enum { value = ... }
+
+// check "test_has_member.cpp" for a usage example
+
+/// Defines a "has_member_member_name" class template
+///
+/// This template can be used to check if its "T" argument
+/// has a data or function member called "member_name"
+#define define_has_member(member_name)                                         \
+    template <typename T>                                                      \
+    class has_member_##member_name                                             \
+    {                                                                          \
+        typedef char yes_type;                                                 \
+        typedef long no_type;                                                  \
+        template <typename U> static yes_type test(decltype(&U::member_name)); \
+        template <typename U> static no_type  test(...);                       \
+    public:                                                                    \
+        static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes_type);  \
+    }
+
+/// Shorthand for testing if "class_" has a member called "member_name"
+///
+/// @note "define_has_member(member_name)" must be used
+///       before calling "has_member(class_, member_name)"
+#define has_member(class_, member_name)  has_member_##member_name<class_>::value
+
diff --git a/VirtualRobot/MJCF/elements/types/actuator.cpp b/VirtualRobot/MJCF/elements/types/actuator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..31df438f4e08cac13909cd52a95f6ecbc4b5bf01
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/actuator.cpp
@@ -0,0 +1,84 @@
+#include "actuator.h"
+
+#include "../../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string ActuatorGeneral::tag  = "general";
+const std::string ActuatorMotor::tag    = "motor";
+const std::string ActuatorPosition::tag = "position";
+const std::string ActuatorVelocity::tag = "velocity";
+const std::string ActuatorCylinder::tag = "cylinder";
+const std::string ActuatorMuscle::tag   = "muscle";
+
+const std::string ActuatorSection::tag  = "actuator";
+
+
+Eigen::VectorXf ActuatorGeneral::dynprmDefault()
+{
+    Eigen::VectorXf v(10);
+    v.setZero();
+    v(0) = 1;
+    return v;
+}
+
+Eigen::VectorXf ActuatorGeneral::gainprmDefault()
+{
+    Eigen::VectorXf v(10);
+    v.setZero();
+    v(0) = 1;
+    return v;
+}
+
+Eigen::VectorXf ActuatorGeneral::biasprmDefault()
+{
+    Eigen::VectorXf v(10);
+    v.setZero();
+    return v;
+}
+
+Eigen::Vector2f ActuatorMuscle::timeconstDefault()
+{
+    return Eigen::Vector2f(0.01, 0.04);
+}
+
+Eigen::Vector2f ActuatorMuscle::rangeDefault()
+{
+    return Eigen::Vector2f(0.75, 1.05);
+}
+
+
+template <class ElementD>
+ElementD addActuator(ActuatorSection& as, const std::string& joint)
+{
+    ElementD motor = as.addChild<ElementD>();
+    motor.joint = joint;
+    return motor;
+}
+
+ActuatorMotor ActuatorSection::addMotor(const std::string& joint)
+{
+    return addActuator<ActuatorMotor>(*this, joint);
+}
+
+ActuatorPosition ActuatorSection::addPosition(const std::string& joint, float kp)
+{
+    ActuatorPosition position = addActuator<ActuatorPosition>(*this, joint);
+    if (kp >= 0)
+    {
+        position.kp = kp;
+    }
+    return position;
+}
+
+ActuatorVelocity ActuatorSection::addVelocity(const std::string& joint, float kv)
+{
+    ActuatorVelocity velocity = addActuator<ActuatorVelocity>(*this, joint);
+    if (kv >= 0)
+    {
+        velocity.kv = kv;
+    }
+    return velocity;
+}
diff --git a/VirtualRobot/MJCF/elements/types/actuator.h b/VirtualRobot/MJCF/elements/types/actuator.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f7399d1c9465b41b2706b0ce011e9b14955fef7
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/actuator.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+
+namespace mjcf
+{
+
+static Eigen::Vector6f gearDefault()
+{
+    Eigen::Vector6f v;
+    v << 1, 0, 0, 0, 0, 0;
+    return v;
+}
+
+
+#define mjcf_ActuatorAttributes(Derived)    \
+    mjcf_NameAttribute(Derived);    \
+    mjcf_ClassAttribute(Derived);   \
+    \
+    mjcf_GroupAttribute(Derived);   \
+    \
+    mjcf_BoolAttributeDef(Derived, ctrllimited, false);     \
+    mjcf_BoolAttributeDef(Derived, forcelimited, false);    \
+    \
+    mjcf_Vector2fAttributeDef(Derived, ctrlrange, Eigen::Vector2f::Zero());     \
+    mjcf_Vector2fAttributeDef(Derived, forcerange, Eigen::Vector2f::Zero());    \
+    mjcf_Vector2fAttributeDef(Derived, lengthrange, Eigen::Vector2f::Zero());   \
+    \
+    mjcf_AttributeDef(Derived, Eigen::Vector6f, gear, gearDefault());   \
+    mjcf_FloatAttributeDef(Derived, cranklength, 0);    \
+    \
+    mjcf_StringAttributeOpt(Derived, joint);            \
+    mjcf_StringAttributeOpt(Derived, jointinparent);    \
+    mjcf_StringAttributeOpt(Derived, site);             \
+    mjcf_StringAttributeOpt(Derived, tendon);           \
+    mjcf_StringAttributeOpt(Derived, cranksite);        \
+    mjcf_StringAttributeOpt(Derived, slidersite)
+
+
+struct ActuatorGeneral : public Element<ActuatorGeneral>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorGeneral)
+    
+    mjcf_ActuatorAttributes(ActuatorGeneral);
+    
+    // dyntype : [none, integrator, filter, muscle, user], 
+    mjcf_StringAttributeDef(ActuatorGeneral, dyntype, "none");
+    // gaintype : [fixed, muscle, user], "fixed"
+    mjcf_StringAttributeDef(ActuatorGeneral, gaintype, "fixed");
+    // biastype : [none, affine, muscle, user], "none"
+    mjcf_StringAttributeDef(ActuatorGeneral, biastype, "none");
+    
+    // dynprm : real(10), "1 0 ... 0"
+    mjcf_AttributeDef(ActuatorGeneral, Eigen::VectorXf, dynprm, dynprmDefault());
+    // gainprm : real(10), "1 0 ... 0"
+    mjcf_AttributeDef(ActuatorGeneral, Eigen::VectorXf, gainprm, gainprmDefault());
+    // biasprm : real(10), "1 0 ... 0"
+    mjcf_AttributeDef(ActuatorGeneral, Eigen::VectorXf, biasprm, biasprmDefault());
+    
+    
+private:
+    static Eigen::VectorXf dynprmDefault();
+    static Eigen::VectorXf gainprmDefault();
+    static Eigen::VectorXf biasprmDefault();
+    
+};
+
+struct ActuatorMotor : public Element<ActuatorMotor>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorMotor)
+    
+    mjcf_ActuatorAttributes(ActuatorMotor);
+};
+
+struct ActuatorPosition : public Element<ActuatorPosition>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorPosition)
+    
+    mjcf_ActuatorAttributes(ActuatorPosition);
+    mjcf_FloatAttributeDef(ActuatorPosition, kp, 1);
+};
+
+struct ActuatorVelocity : public Element<ActuatorVelocity>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorVelocity)
+    
+    mjcf_ActuatorAttributes(ActuatorVelocity);
+    mjcf_FloatAttributeDef(ActuatorVelocity, kv, 1);
+};
+
+struct ActuatorCylinder : public Element<ActuatorCylinder>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorCylinder)
+    
+    mjcf_ActuatorAttributes(ActuatorCylinder);
+    mjcf_FloatAttributeDef(ActuatorCylinder, timeconst, 1);
+    mjcf_FloatAttributeDef(ActuatorCylinder, area, 1);
+    mjcf_FloatAttributeOpt(ActuatorCylinder, diameter);
+    mjcf_Vector3fAttributeDef(ActuatorCylinder, bias, Eigen::Vector3f::Zero());
+};
+
+struct ActuatorMuscle : public Element<ActuatorMuscle>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorMuscle)
+    
+    mjcf_ActuatorAttributes(ActuatorMuscle);
+    
+    mjcf_Vector2fAttributeDef(ActuatorMuscle, timeconst, timeconstDefault());
+    mjcf_Vector2fAttributeDef(ActuatorMuscle, range, rangeDefault());
+    
+    mjcf_FloatAttributeDef(ActuatorMuscle, force, -1);
+    mjcf_FloatAttributeDef(ActuatorMuscle, scale, 200);
+    mjcf_FloatAttributeDef(ActuatorMuscle, lmin, 0.5);
+    mjcf_FloatAttributeDef(ActuatorMuscle, lmax, 1.6f);
+    mjcf_FloatAttributeDef(ActuatorMuscle, vmax, 1.5);
+    mjcf_FloatAttributeDef(ActuatorMuscle, fpmax, 1.3f);
+    mjcf_FloatAttributeDef(ActuatorMuscle, vvmax, 1.2f);
+    
+private:
+    static Eigen::Vector2f timeconstDefault();
+    static Eigen::Vector2f rangeDefault();
+};
+
+
+struct ActuatorSection : public Element<ActuatorSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ActuatorSection)
+    
+    ActuatorMotor addMotor(const std::string& jointName);
+    ActuatorPosition addPosition(const std::string& joint, float kp = -1);
+    ActuatorVelocity addVelocity(const std::string& joint, float kv = -1);
+    
+};
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/asset.cpp b/VirtualRobot/MJCF/elements/types/asset.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..916feb621c9d0a99ed7950e1e718065741d5b5ee
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/asset.cpp
@@ -0,0 +1,55 @@
+#include "asset.h"
+
+#include "../../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string Texture::tag      = "texture";
+const std::string Material::tag     = "material";
+const std::string Mesh::tag         = "mesh";
+const std::string AssetSection::tag = "asset";
+
+
+Texture AssetSection::addSkyboxTexture(const Eigen::Vector3f& rgb1, const Eigen::Vector3f& rgb2)
+{
+    Texture texSkybox = addChild<Texture>();
+
+    texSkybox.type = "skybox";
+    texSkybox.builtin = "gradient";
+    texSkybox.width = 128;
+    texSkybox.height = 128;
+    texSkybox.rgb1 = rgb1;
+    texSkybox.rgb2 = rgb2;
+
+    return texSkybox;
+}
+
+Texture AssetSection::addTextureFile(const std::string& name, const std::string& file, 
+                                     bool vflip, bool hflip)
+{
+    Texture texture = addChild<Texture>();
+    texture.name = name;
+    texture.file = file;
+    texture.type = "2d";
+    texture.vflip = vflip;
+    texture.hflip = hflip;
+    return texture;
+}
+
+Mesh AssetSection::addMesh(const std::string& name, const std::string& file)
+{
+    Mesh mesh = addChild<Mesh>();
+    mesh.name = name;
+    mesh.file = file;
+    return mesh;
+}
+
+Material AssetSection::addMaterial(const std::string& name, const std::string& textureName)
+{
+    Material material = addChild<Material>();
+    material.name = name;
+    material.texture = textureName;
+    return material;
+}
diff --git a/VirtualRobot/MJCF/elements/types/asset.h b/VirtualRobot/MJCF/elements/types/asset.h
new file mode 100644
index 0000000000000000000000000000000000000000..33f718384cfe92b48211d906307f5d564362f273
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/asset.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+
+namespace mjcf
+{
+
+struct Texture : public Element<Texture>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Texture)
+    
+    mjcf_NameAttribute(Texture);
+    mjcf_StringAttributeDef(Texture, type, "cube");
+    mjcf_StringAttributeOpt(Texture, file);
+    
+    mjcf_AttributeDef(Texture, Eigen::Vector2i, gridsize, Eigen::Vector2i::Ones());
+    mjcf_StringAttributeDef(Texture, gridlayout, "............");
+  
+    mjcf_StringAttributeDef(Texture, builtin, "none");
+    mjcf_StringAttributeDef(Texture, mark, "none");
+    mjcf_RgbAttributeDef(Texture, markrgb, Eigen::Vector3f::Zero());
+    mjcf_FloatAttributeDef(Texture, random, 0.01f);
+    
+    mjcf_IntAttributeDef(Texture, width, 0);
+    mjcf_IntAttributeDef(Texture, height, 0);
+  
+    mjcf_RgbAttributeDef(Texture, rgb1, 0.8f * Eigen::Vector3f::Ones());
+    mjcf_RgbAttributeDef(Texture, rgb2, 0.5f * Eigen::Vector3f::Ones());
+    
+    mjcf_BoolAttributeDef(Texture, hflip, false);
+    mjcf_BoolAttributeDef(Texture, vflip, true);
+};
+
+
+struct Mesh : public Element<Mesh>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Mesh)
+    
+    mjcf_NameAttribute(Mesh);
+    mjcf_ClassAttribute(Mesh);
+    
+    mjcf_StringAttributeOpt(Mesh, file);
+    
+    mjcf_Vector3fAttributeDef(Mesh, scale,  Eigen::Vector3f::Ones());
+    mjcf_BoolAttributeDef(Mesh, smoothnormal, false);
+    
+    mjcf_Vector3fAttributeDef(Mesh, refpos,  Eigen::Vector3f::Ones());
+    mjcf_AttributeDef(Mesh, Eigen::Quaternionf, refquat, Eigen::Quaternionf::Identity());
+};
+
+
+struct Material : public Element<Material>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Material)
+    
+    mjcf_NameAttribute(Material);
+    mjcf_ClassAttribute(Material);
+    
+    mjcf_StringAttributeOpt(Material, texture);
+    
+    mjcf_AttributeDef(Material, Eigen::Vector2f, texrepeat, Eigen::Vector2f::Ones());
+    mjcf_BoolAttributeDef(Material, texuniform, false);
+    
+    mjcf_FloatAttributeDef(Material, emission, 0);
+    mjcf_FloatAttributeDef(Material, specular, 0);
+    mjcf_FloatAttributeDef(Material, shininess, 0);
+    mjcf_FloatAttributeDef(Material, reflectance, 0);
+    mjcf_RgbaAttributeDef(Material, rgba, Eigen::Vector4f::Ones());
+};
+
+
+
+struct AssetSection : public Element<AssetSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(AssetSection)
+    
+    Texture addSkyboxTexture(const Eigen::Vector3f& rgb1, const Eigen::Vector3f& rgb2);    
+    
+    Texture addTextureFile(const std::string& name, const std::string& file,
+                           bool vflip = false, bool hflip = false);
+    
+    /// Add a mesh asset with a name and a file.
+    Mesh addMesh(const std::string& name, const std::string& file);
+    
+    Material addMaterial(const std::string& name, const std::string& textureName);
+};
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/body.cpp b/VirtualRobot/MJCF/elements/types/body.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..de08ed5983437056f93a9761a561fdab8fb844f0
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/body.cpp
@@ -0,0 +1,162 @@
+#include "body.h"
+
+#include "../../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string Inertial::tag     = "inertial";
+const std::string Joint::tag        = "joint";
+const std::string FreeJoint::tag    = "freejoint";
+const std::string Geom::tag         = "geom";
+const std::string Site::tag         = "site";
+const std::string Camera::tag       = "camera";
+const std::string Light::tag        = "light";
+const std::string Body::tag         = "body";
+const std::string Worldbody::tag        = "worldbody";
+
+
+void Inertial::inertiaFromMatrix(const Eigen::Matrix3f& matrix)
+{
+    if (matrix.isDiagonal(1e-9f))
+    {
+        this->diaginertia = matrix.diagonal();
+    }
+    else
+    {
+        /* Full inertia matrix M. Since M is 3-by-3 and symmetric, 
+         * it is specified using only 6 numbers in the following order: 
+         * M(1,1), M(2,2), M(3,3), M(1,2), M(1,3), M(2,3).
+         * -- http://www.mujoco.org/book/XMLreference.html#inertial 
+         */
+        
+        Eigen::Vector6f inertia;
+        inertia << matrix(0, 0), matrix(1, 1), matrix(2, 2), 
+                matrix(0, 1), matrix(0, 2), matrix(1, 2);
+        this->fullinertia = inertia;
+    }
+}
+
+bool Body::hasMass() const
+{
+    return hasChild<Geom>() || hasChild<Inertial>();
+}
+
+Body Body::addBody(const std::string& name)
+{
+    Body body = addChild<Body>();
+
+    if (!name.empty())
+    {
+        body.name = name;
+    }
+
+    return body;
+}
+
+Inertial Body::addInertial()
+{
+    return addChild<Inertial>();
+}
+
+Inertial Body::addInertial(const Eigen::Vector3f& pos, float mass, const Eigen::Matrix3f& matrix)
+{
+    Inertial inertial = addInertial();
+    
+    inertial.pos = pos;
+    inertial.mass = mass;
+
+    if (matrix.isDiagonal(document()->getFloatCompPrecision()))
+    {
+        inertial.diaginertia = matrix.diagonal();
+    }
+    else
+    {
+        /* from mujoco xml reference:
+         * "Full inertia matrix M. Since M is 3-by-3 and symmetric, it is
+         * specified using only 6 numbers in the following order:
+         * M(1,1), M(2,2), M(3,3), M(1,2), M(1,3), M(2,3)."*/
+        Eigen::Vector6f inertia;
+        inertia << matrix(0, 0), matrix(1, 1), matrix(2, 2),
+                matrix(0, 1), matrix(0, 2), matrix(1, 2);
+        inertial.fullinertia = inertia;
+    }
+    
+    return inertial;
+}
+
+Inertial Body::addDummyInertial()
+{
+    Inertial inertial = addInertial();
+
+    inertial.pos = Eigen::Vector3f(0, 0, 0);
+    inertial.mass = document()->getDummyMass();
+    inertial.diaginertia = Eigen::Vector3f::Ones();
+
+    return inertial;
+}
+
+Joint Body::addJoint()
+{
+    return addChild<Joint>();
+}
+
+FreeJoint Body::addFreeJoint()
+{
+    return addChild<FreeJoint>();
+    
+}
+
+Geom Body::addGeom(const std::string& type)
+{
+    Geom geom = addChild<Geom>();
+    
+    geom.type = type;
+    
+    return geom;
+}
+
+Geom Body::addGeomMesh(const std::string& meshName, const std::string& materialName)
+{
+    Geom geom = addGeom("mesh");
+    
+    geom.mesh = meshName;
+    if (!materialName.empty())
+    {
+        geom.material = materialName;
+    }
+    
+    return geom;
+}
+
+
+Body Worldbody::addMocapBody(const std::string& name, float geomSize)
+{
+    Body mocap = addChild<Body>();
+    mocap.name = name;
+    mocap.mocap = true;
+    // add geom for visualization
+
+    Geom geom = mocap.addChild<Geom>();
+    geom.type = "box";
+    geom.size = geomSize * Eigen::Vector3f::Ones();
+
+    return mocap;
+}
+
+Body Worldbody::addBody(const std::string& name, const std::string& childClass)
+{
+    Body body = addChild<Body>();
+
+    if (!name.empty())
+    {
+        body.name = name;
+    }
+    if (!childClass.empty())
+    {
+        body.childclass = childClass;
+    }
+
+    return body;
+}
diff --git a/VirtualRobot/MJCF/elements/types/body.h b/VirtualRobot/MJCF/elements/types/body.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bacb6b8ef9f49e4b7c4b7927c10700eebaa94bb
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/body.h
@@ -0,0 +1,232 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+
+namespace mjcf
+{
+
+
+struct Inertial : public Element<Inertial>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Inertial)
+    
+    mjcf_PoseAttributes(Inertial);
+    
+    mjcf_AttributeReq(Inertial, float, mass);
+    
+    mjcf_AttributeOpt(Inertial, Eigen::Vector3f, diaginertia);
+    mjcf_AttributeOpt(Inertial, Eigen::Vector6f, fullinertia);
+    
+    /// Sets diaginertia or fullinertia (as adequate) from the given matrix.
+    void inertiaFromMatrix(const Eigen::Matrix3f& matrix);
+};
+
+
+struct Joint : public Element<Joint>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Joint)
+    
+    void setAxis(const Eigen::Vector3f& axis);
+    
+    mjcf_NameAttribute(Joint);
+    mjcf_ClassAttribute(Joint);
+    
+    // free, ball, slide, hinge
+    mjcf_StringAttributeDef(Joint, type, "hinge");
+    mjcf_IntAttributeDef(Joint, group, 0);
+    
+    mjcf_PosAttribute(Joint);
+    mjcf_Vector3fAttributeDef(Joint, axis, Eigen::Vector3f(0, 0, 1));
+    
+    mjcf_AttributeDef(Joint, Eigen::Vector2f, springdamper, Eigen::Vector2f::Zero());
+    mjcf_FloatAttributeDef(Joint, stiffness, 0);
+    
+    mjcf_BoolAttributeDef(Joint, limited, false);
+    mjcf_AttributeDef(Joint, Eigen::Vector2f, range, Eigen::Vector2f::Zero());
+    
+    mjcf_FloatAttributeDef(Joint, margin, 0);
+    
+    mjcf_FloatAttributeDef(Joint, ref, 0);
+    mjcf_FloatAttributeDef(Joint, springref, 0);
+    
+    mjcf_FloatAttributeDef(Joint, armature, 0);
+    mjcf_FloatAttributeDef(Joint, damping, 0);
+    mjcf_FloatAttributeDef(Joint, frictionloss, 0);
+};
+
+
+struct FreeJoint : public Element<FreeJoint>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(FreeJoint)
+    
+    mjcf_NameAttribute(FreeJoint);
+    mjcf_IntAttributeDef(FreeJoint, group, 0);
+};
+
+
+struct Geom : public Element<Geom>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Geom)
+    
+    mjcf_NameAttribute(Geom);
+    mjcf_ClassAttribute(Geom);
+    
+    // plane, hfield, sphere, capsule, ellipsoid, cylinder, box, mesh
+    mjcf_StringAttributeDef(Geom, type, "sphere");
+    
+    mjcf_IntAttributeDef(Geom, contype, 1);
+    mjcf_IntAttributeDef(Geom, conaffinity, 1);
+    mjcf_IntAttributeDef(Geom, condim, 3);
+    
+    mjcf_IntAttributeDef(Geom, group, 0);
+    
+    mjcf_Vector3fAttributeDef(Geom, size, Eigen::Vector3f::Zero());
+    mjcf_StringAttributeOpt(Geom, material);
+    mjcf_RgbaAttributeDef(Geom, rgba, Eigen::Vector4f(.5, .5, .5, 1));
+    
+    mjcf_Vector3fAttributeDef(Geom, friction, Eigen::Vector3f(1, 0.005f, 0.0001f));
+    
+    mjcf_FloatAttributeOpt(Geom, mass);
+    mjcf_FloatAttributeDef(Geom, density, 1000);
+    
+    mjcf_FloatAttributeDef(Geom, solmix, 1);
+    
+    mjcf_FloatAttributeDef(Geom, marin, 0);
+    mjcf_FloatAttributeDef(Geom, gap, 0);
+    
+    mjcf_AttributeOpt(Geom, Eigen::Vector6f, fromto);
+    
+    mjcf_PoseAttributes(Geom);
+    
+    mjcf_StringAttributeOpt(Geom, hfield);
+    mjcf_StringAttributeOpt(Geom, mesh);
+    
+    mjcf_FloatAttributeDef(Geom, fitscale, 1);
+};
+
+struct Site : public Element<Site>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Site)
+    
+    mjcf_NameAttribute(Site);
+    mjcf_ClassAttribute(Site);
+    
+    // sphere, capsule, ellipsoid, cylinder, box
+    mjcf_StringAttributeDef(Site, type, "sphere");
+    mjcf_IntAttributeDef(Site, group, 0);
+
+    mjcf_StringAttributeOpt(Site, material);
+    mjcf_RgbaAttributeDef(Site, rgba, Eigen::Vector4f(.5, .5, .5, 1));
+    
+    mjcf_Vector3fAttributeDef(Site, size, Eigen::Vector3f::Constant(0.005f));
+    mjcf_AttributeOpt(Site, Eigen::Vector6f, fromto);
+    
+    mjcf_PoseAttributes(Site);
+};
+
+struct Camera : public Element<Camera>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Camera)
+    
+    mjcf_NameAttribute(Camera);
+    mjcf_ClassAttribute(Camera);
+    
+    // fixed, track, trackcom, targetbody, targetbodycom
+    mjcf_StringAttributeDef(Camera, mode, "fixed");
+    mjcf_StringAttributeOpt(Camera, target); // required if targetbody or targetbodycom
+
+    /// Vertical field of view of the camera, expressed in degrees regardless 
+    /// of the global angle setting. 
+    mjcf_FloatAttributeDef(Camera, fovy, 45);
+    /// Inter-pupilary distance.
+    mjcf_FloatAttributeDef(Camera, ipd, 0.068f);
+    
+    mjcf_PoseAttributes(Camera);
+};
+
+struct Light : public Element<Light>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Light)
+    
+    mjcf_NameAttribute(Light);
+    mjcf_ClassAttribute(Light);
+    
+    // fixed, track, trackcom, targetbody, targetbodycom
+    mjcf_StringAttributeDef(Light, mode, "fixed");
+    mjcf_StringAttributeOpt(Light, target); // required if targetbody or targetbodycom
+
+    mjcf_BoolAttributeDef(Light, directional, false);
+    mjcf_BoolAttributeDef(Light, castshadow, false);
+    mjcf_BoolAttributeDef(Light, active, false);
+    
+    mjcf_PosAttribute(Light);
+    mjcf_Vector3fAttributeDef(Light, dir, - Eigen::Vector3f::UnitZ());
+    
+    mjcf_Vector3fAttributeDef(Light, attenuation, Eigen::Vector3f::UnitX());
+    mjcf_FloatAttributeDef(Light, cutoff, 45);
+    mjcf_FloatAttributeDef(Light, exponent, 10);
+    
+    mjcf_Vector3fAttributeDef(Light, ambient, Eigen::Vector3f::Zero());
+    mjcf_Vector3fAttributeDef(Light, diffuse, Eigen::Vector3f::Constant(0.7f));
+    mjcf_Vector3fAttributeDef(Light, specular, Eigen::Vector3f::Constant(0.3f));
+};
+
+struct Body : public Element<Body>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Body)
+    
+    bool hasMass() const;
+    
+    /// Add a child body element.
+    Body addBody(const std::string& name = "");
+    
+    /// Add an inertial element.
+    Inertial addInertial();
+    /// Add an inertial element with given settings.
+    Inertial addInertial(const Eigen::Vector3f& pos, float mass, const Eigen::Matrix3f& matrix);
+    /// Add a dummy inertial element with small mass and identity inertia matrix.
+    Inertial addDummyInertial();
+    
+    
+    /// Add a joint element to a body.
+    Joint addJoint();
+    /// Add a free joint element to a body.
+    FreeJoint addFreeJoint();
+
+    /// Add a geom to a body, referencing a mesh.
+    Geom addGeom(const std::string& type);
+    /// Add a mesh geom with optional material (for texture).
+    Geom addGeomMesh(const std::string& meshName, const std::string& materialName = "");
+    
+    
+    mjcf_NameAttribute(Body);
+    mjcf_StringAttributeOpt(Body, childclass);
+    
+    mjcf_BoolAttributeDef(Body, mocap, false);
+    
+    mjcf_PoseAttributes(Body);
+};
+
+struct Worldbody : public Element<Worldbody>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Worldbody)
+    
+    /// Add a body element.
+    Body addBody(const std::string& name = "", const std::string& childClass = "");
+    
+    /// Add a mocap body with the given name to the worldbody.
+    Body addMocapBody(const std::string& name, float geomSize);
+    
+};
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/compiler.cpp b/VirtualRobot/MJCF/elements/types/compiler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5619b7e67503ec6ce6fffdc12c0ef52865127e44
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/compiler.cpp
@@ -0,0 +1,11 @@
+#include "compiler.h"
+
+//#include "../Document.h"
+
+
+namespace mjcf
+{
+    const std::string CompilerSection::tag  = "compiler";
+}
+
+
diff --git a/VirtualRobot/MJCF/elements/types/compiler.h b/VirtualRobot/MJCF/elements/types/compiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..f63347b56ded633051f4095e1ec9838cecbaa6eb
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/compiler.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+struct CompilerSection : public Element<CompilerSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(CompilerSection)
+    
+    mjcf_FloatAttributeDef(CompilerSection, boundmass, 0);
+    mjcf_FloatAttributeDef(CompilerSection, boundinertia, 0);
+    mjcf_FloatAttributeDef(CompilerSection, settotalmass, -1);
+    
+    mjcf_BoolAttributeDef(CompilerSection, balanceinertia, false);
+    mjcf_BoolAttributeDef(CompilerSection, strippath, false);
+    
+    // local, global
+    mjcf_StringAttributeDef(CompilerSection, coordinate, "local");
+    // degree, radian (default "degree" for MJCF, always "radian" for URDF)
+    mjcf_StringAttributeDef(CompilerSection, angle, "degree");
+    mjcf_BoolAttributeDef(CompilerSection, fitaabb, false);
+    mjcf_StringAttributeDef(CompilerSection, eulerseq, "xyz");
+
+    mjcf_StringAttributeOpt(CompilerSection, meshdir);
+    mjcf_StringAttributeOpt(CompilerSection, texturedir);
+    // Default: false for MJCF, true for URDF
+    mjcf_BoolAttributeDef(CompilerSection, discardvisual, false);
+
+    mjcf_BoolAttributeDef(CompilerSection, convexhull, true);
+    mjcf_BoolAttributeDef(CompilerSection, userthread, true);
+    
+    // Default: false for MJCF, true for URDF
+    mjcf_BoolAttributeDef(CompilerSection, fusestatic, false);
+
+    // false, true, auto
+    mjcf_StringAttributeDef(CompilerSection, inertiafromgeom, "auto");
+    mjcf_AttributeDef(CompilerSection, Eigen::Vector2i, inertiagrouprange, Eigen::Vector2i(0, 5));
+};
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/contact.cpp b/VirtualRobot/MJCF/elements/types/contact.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..27b412e864709535247272b36fd2947ad8946a6b
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/contact.cpp
@@ -0,0 +1,49 @@
+#include "contact.h"
+
+#include "../../Document.h"
+
+using namespace mjcf;
+
+
+const std::string ContactPair::tag    = "pair";
+const std::string ContactExclude::tag = "exclude";
+const std::string ContactSection::tag = "contact";
+
+
+Eigen::Vector5f ContactPair::condimDefault() 
+{
+    Eigen::Vector5f v;
+    v << 1, 1, 0.005f, 0.0001f, 0.0001f;
+    return v;
+}
+
+ContactPair ContactSection::addPair(const Geom& geom1, const Geom& geom2)
+{
+    return addPair(geom1.name.get(), geom2.name.get());
+}
+
+ContactPair ContactSection::addPair(const std::string& geom1Name, const std::string& geom2Name)
+{
+    ContactPair pair = addChild<ContactPair>();
+
+    pair.geom1 = geom1Name;
+    pair.geom2 = geom2Name;
+
+    return pair;
+}
+
+
+ContactExclude ContactSection::addExclude(const Body& body1, const Body& body2)
+{
+    return addExclude(body1.name.get(), body2.name.get());
+}
+
+ContactExclude ContactSection::addExclude(const std::string& body1Name, const std::string& body2Name)
+{
+    ContactExclude exclude = addChild<ContactExclude>();
+
+    exclude.body1 = body1Name;
+    exclude.body2 = body2Name;
+
+    return exclude;
+}
diff --git a/VirtualRobot/MJCF/elements/types/contact.h b/VirtualRobot/MJCF/elements/types/contact.h
new file mode 100644
index 0000000000000000000000000000000000000000..dff53f638c5e0513baed734a42747383a554f57f
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/contact.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "../core/Attribute.h"
+#include "body.h"
+
+
+namespace mjcf
+{
+
+
+struct ContactPair : public Element<ContactPair>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ContactPair)
+    
+    mjcf_NameAttribute(ContactPair);
+    mjcf_ClassAttribute(ContactPair);
+    
+    mjcf_StringAttributeReq(ContactPair, geom1);
+    mjcf_StringAttributeReq(ContactPair, geom2);
+    
+    mjcf_IntAttributeDef(ContactPair, condim, 3);
+    
+    mjcf_AttributeDef(ContactPair, Eigen::Vector5f, friction, condimDefault());
+    
+    mjcf_FloatAttributeDef(ContactPair, margin, 0);
+    mjcf_FloatAttributeDef(ContactPair, gap, 0);
+    
+private:
+    static Eigen::Vector5f condimDefault();
+};
+
+
+struct ContactExclude : public Element<ContactExclude>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ContactExclude)
+    
+    mjcf_NameAttribute(ContactExclude);
+    mjcf_StringAttributeReq(ContactExclude, body1);
+    mjcf_StringAttributeReq(ContactExclude, body2);
+};
+
+
+struct ContactSection : public Element<ContactSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(ContactSection)
+    
+    /// Add a conact/pair element between the given geoms.
+    ContactPair addPair(const Geom& geom1, const Geom& geom2);
+    /// Add a conact/pair element between the given geoms.
+    ContactPair addPair(const std::string& geom1Name, const std::string& geom2Name);
+    
+    /// Add a conact/exclude element between the given bodies.
+    ContactExclude addExclude(const Body& body1, const Body& body2);
+    /// Add a conact/exclude element between the given bodies.
+    ContactExclude addExclude(const std::string& body1Name, const std::string& body2Name);
+};
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/custom.cpp b/VirtualRobot/MJCF/elements/types/custom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f2655738d04500a6d053d35b1aee4538c999db7
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/custom.cpp
@@ -0,0 +1,6 @@
+#include "compiler.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
diff --git a/VirtualRobot/MJCF/elements/types/custom.h b/VirtualRobot/MJCF/elements/types/custom.h
new file mode 100644
index 0000000000000000000000000000000000000000..64fef95b4d0f24e68d5071817f3d0285a9e223dc
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/custom.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/default.cpp b/VirtualRobot/MJCF/elements/types/default.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa50b0cdf42aba96c63803bf4a804f06dc9c4480
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/default.cpp
@@ -0,0 +1,31 @@
+#include "default.h"
+
+#include "../../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string DefaultClass::tag   = "default";
+const std::string DefaultSection::tag = "default";
+
+
+bool DefaultSection::hasClass(const std::string& className)
+{
+    return !hasChild<mjcf::DefaultClass>("class", className);
+}
+
+DefaultClass DefaultSection::getClass(const std::string& className)
+{
+    DefaultClass def = firstChild<DefaultClass>("class", className);
+    if (!def)
+    {
+        def = addClass(className);
+    }
+    return def ;
+}
+
+DefaultClass DefaultSection::addClass(const std::string& className)
+{
+    return addChild<DefaultClass>(className);
+}
diff --git a/VirtualRobot/MJCF/elements/types/default.h b/VirtualRobot/MJCF/elements/types/default.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c22f0cf2aceb8b79b8261a81e5a6197f2da451d
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/default.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+
+namespace mjcf
+{
+
+
+struct DefaultClass : public Element<DefaultClass>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(DefaultClass)
+    
+    mjcf_ClassAttribute(DefaultClass);
+    
+    /// Get the element of the specified type (create it if it does not exist).
+    template <class ElementD>
+    ElementD getElement();
+    
+    template <class ElementD, typename AttrT>
+    ElementD setElementAttr(const std::string& attrName, const AttrT& attrValue);
+};
+
+
+struct DefaultSection : public Element<DefaultSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(DefaultSection)
+    
+    /// Indicate whether there is a default class with the given name.
+    bool hasClass(const std::string& className);
+    
+    /// Get the default class for given class name. If it does not exist, add it.
+    DefaultClass getClass(const std::string& className);
+    
+    /// Add a new default class with given class name.
+    DefaultClass addClass(const std::string& className);
+};
+
+
+
+template<class ElementD>
+ElementD DefaultClass::getElement()
+{
+    return getOrCreateChild<ElementD>();
+}
+
+template<class ElementD, typename AttrT>
+ElementD DefaultClass::setElementAttr(const std::string& attrName, const AttrT& attrValue)
+{
+    ElementD element = getElement<ElementD>();
+    element.setAttribute(attrName, attrValue);
+    return element;
+}
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/equality.cpp b/VirtualRobot/MJCF/elements/types/equality.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2732d939bbecff717d11fe448750c5d92097f014
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/equality.cpp
@@ -0,0 +1,49 @@
+#include "equality.h"
+
+#include "../../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string EqualityDefaults::tag = "equality";
+const std::string EqualityConnect::tag = "connect";
+const std::string EqualityWeld::tag = "weld";
+const std::string EqualityJoint::tag = "joint";
+const std::string EqualityTendon::tag = "tendon";
+const std::string EqualityDistance::tag = "distance";
+const std::string EqualitySection::tag  = "equality";
+
+
+Eigen::Vector7f EqualityWeld::relposeDefault()
+{
+    Eigen::Vector7f v;
+    v << 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f;
+    return v;
+}
+
+
+Eigen::Vector5f EqualityJoint::polycoefDefault()
+{
+    Eigen::Vector5f v;
+    v << 0, 1, 0, 0, 0;
+    return v;
+}
+
+Eigen::Vector5f EqualityTendon::polycoefDefault()
+{
+    Eigen::Vector5f v;
+    v << 0, 1, 0, 0, 0;
+    return v;
+}
+
+EqualityWeld EqualitySection::addWeld(const std::string& name, const std::string& body1, const std::string& body2)
+{
+    EqualityWeld weld = addChild<EqualityWeld>();
+
+    weld.name = name;
+    weld.body1 = body1;
+    weld.body2 = body2;
+
+    return weld;
+}
diff --git a/VirtualRobot/MJCF/elements/types/equality.h b/VirtualRobot/MJCF/elements/types/equality.h
new file mode 100644
index 0000000000000000000000000000000000000000..d31253e85e27cedd8534b572056e56c41d2d8d63
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/equality.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+
+namespace mjcf
+{
+
+#define mjcf_EqualityAttribs(Derived, entityName) \
+    mjcf_NameAttribute(Derived);    \
+    mjcf_ClassAttribute(Derived);   \
+    mjcf_BoolAttributeDef(Derived, active, true);   \
+    mjcf_StringAttributeReq(Derived, entityName ## 1);    \
+    mjcf_StringAttributeOpt(Derived, entityName ## 2)
+
+/**
+ * @brief Element of a defaults class for equality constraints.
+ * Should only be used as a child of mjcf::DefaultsClass.
+ */
+struct EqualityDefaults : public Element<EqualityDefaults>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualityDefaults)
+    
+    mjcf_BoolAttributeOpt(EqualityDefaults, active);
+    mjcf_SolrefAttribute(EqualityDefaults);
+    mjcf_SolimpAttribute(EqualityDefaults);
+};
+
+
+struct EqualityConnect : public Element<EqualityConnect>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualityConnect)
+    
+    mjcf_EqualityAttribs(EqualityConnect, body);
+    
+    mjcf_Vector3fAttributeReq(EqualityConnect, anchor);
+};
+
+
+struct EqualityWeld : public Element<EqualityWeld>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualityWeld)
+
+    mjcf_EqualityAttribs(EqualityWeld, body);
+    
+    mjcf_AttributeDef(EqualityWeld, Eigen::Vector7f, relpose, relposeDefault());
+    
+private:
+    static Eigen::Vector7f relposeDefault();
+    
+};
+
+
+struct EqualityJoint : public Element<EqualityJoint>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualityJoint)
+
+    mjcf_EqualityAttribs(EqualityJoint, joint);
+    
+    mjcf_AttributeDef(EqualityJoint, Eigen::Vector5f, polycoef, polycoefDefault());
+    
+private:
+    static Eigen::Vector5f polycoefDefault();
+    
+};
+
+
+struct EqualityTendon : public Element<EqualityTendon>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualityTendon)
+
+    mjcf_EqualityAttribs(EqualityTendon, tendon);
+    
+    mjcf_AttributeDef(EqualityTendon, Eigen::Vector5f, polycoef, polycoefDefault());
+    
+private:
+    static Eigen::Vector5f polycoefDefault();
+    
+};
+
+struct EqualityDistance : public Element<EqualityDistance>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualityDistance)
+
+    mjcf_EqualityAttribs(EqualityDistance, geom);
+    
+    mjcf_FloatAttributeDef(EqualityDistance, distance, 0);
+};
+
+
+struct EqualitySection : public Element<EqualitySection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(EqualitySection)
+    
+    EqualityWeld addWeld(const std::string& name, const std::string& body1, 
+                         const std::string& body2);
+    
+};
+
+
+#undef mjcf_EqualityAttribs
+}
diff --git a/VirtualRobot/MJCF/elements/types/keyframe.cpp b/VirtualRobot/MJCF/elements/types/keyframe.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ba1e0678b6860d084f656133d99f7e9bd340da1
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/keyframe.cpp
@@ -0,0 +1,9 @@
+#include "keyframe.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string KeyframeSection::tag  = "keyframe";
diff --git a/VirtualRobot/MJCF/elements/types/keyframe.h b/VirtualRobot/MJCF/elements/types/keyframe.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ca8c42315ddb31645e3ded2d90c6d74a46ff7bf
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/keyframe.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+struct KeyframeSection : public Element<KeyframeSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(KeyframeSection)
+};
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/meta.cpp b/VirtualRobot/MJCF/elements/types/meta.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e53f9b94da36c61b74044643c92290a3c00bcd17
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/meta.cpp
@@ -0,0 +1,10 @@
+#include "meta.h"
+
+namespace mjcf
+{
+
+const std::string MujocoRoot::tag = "mujoco";
+const std::string Include::tag = "include";
+
+}
+
diff --git a/VirtualRobot/MJCF/elements/types/meta.h b/VirtualRobot/MJCF/elements/types/meta.h
new file mode 100644
index 0000000000000000000000000000000000000000..082b272db5ed21e849151a328e06c31c2fd41273
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/meta.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+
+namespace mjcf
+{
+
+/// @see http://www.mujoco.org/book/XMLreference.html#mujoco
+struct MujocoRoot : public Element<MujocoRoot>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(MujocoRoot)
+    
+    mjcf_StringAttributeDef(MujocoRoot, model, "MuJoCo Model");
+};
+
+
+/// @see http://www.mujoco.org/book/XMLreference.html#include
+struct Include : public Element<Include>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(Include)
+    
+    mjcf_StringAttributeReq(Include, file);
+};
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/option.cpp b/VirtualRobot/MJCF/elements/types/option.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..53d4730a1631fe13b32062ab5762e62f80088117
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/option.cpp
@@ -0,0 +1,16 @@
+#include "option.h"
+
+#include "../../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string OptionFlag::tag    = "flag";
+const std::string OptionSection::tag = "option";
+
+
+OptionFlag OptionSection::flag()
+{
+    return getOrCreateChild<OptionFlag>();
+}
diff --git a/VirtualRobot/MJCF/elements/types/option.h b/VirtualRobot/MJCF/elements/types/option.h
new file mode 100644
index 0000000000000000000000000000000000000000..2dc4e1a2a33f8e626f2f60595c3fa4d50a43a60c
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/option.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "../core/Attribute.h"
+#include "../core/mjcf_utils.h"
+
+namespace mjcf
+{
+
+
+struct OptionFlag : public Element<OptionFlag>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(OptionFlag)
+};
+
+struct OptionSection : public Element<OptionSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(OptionSection)
+    
+    
+    /// Get (or create) the option/flag child.
+    OptionFlag flag();
+    
+    
+    mjcf_FloatAttributeDef(OptionSection, timestep, 0.002f);
+    mjcf_FloatAttributeDef(OptionSection, impratio, 1);
+    
+    mjcf_Vector3fAttributeDef(OptionSection, gravity, Eigen::Vector3f(0, 0, -9.81f));
+    
+    mjcf_Vector3fAttributeDef(OptionSection, wind, Eigen::Vector3f::Zero());
+    mjcf_Vector3fAttributeDef(OptionSection, magnetic, Eigen::Vector3f(0, -0.5, 0));
+    
+    mjcf_FloatAttributeDef(OptionSection, density, 0);
+    mjcf_FloatAttributeDef(OptionSection, viscosity, 0);
+    
+    mjcf_FloatAttributeDef(OptionSection,             o_margin, 0);
+    mjcf_Vector2fAttributeDef(OptionSection,          o_solref, Eigen::Vector2f(0.02, 1));
+    mjcf_AttributeDef(OptionSection, Eigen::Vector5f, o_solimp, o_solimp_default());
+    
+    // [Euler, RK4]
+    mjcf_StringAttributeDef(OptionSection, integrator, "Euler");
+    // [all, predefined, dynamic]
+    mjcf_StringAttributeDef(OptionSection, collision, "all");
+    // [pyramidal, elliptic]
+    mjcf_StringAttributeDef(OptionSection, cone, "pyramidal");
+    // [dense, sparse, auto]
+    mjcf_StringAttributeDef(OptionSection, jacobian, "auto");
+    // [PGS, CG, Newton]
+    mjcf_StringAttributeDef(OptionSection, solver, "Newton");
+    
+    mjcf_IntAttributeDef(OptionSection,   iterations, 100);
+    mjcf_FloatAttributeDef(OptionSection, tolerance,  1e-8f);
+    mjcf_IntAttributeDef(OptionSection,   noslip_iterations, 0);
+    mjcf_FloatAttributeDef(OptionSection, noslip_tolerance,  1e-6f);
+    mjcf_IntAttributeDef(OptionSection,   mpr_iterations, 50);
+    mjcf_FloatAttributeDef(OptionSection, mpr_tolerance,  1e-6f);
+    
+private:
+    
+    static Eigen::Vector5f o_solimp_default()
+    {
+        Eigen::Vector5f v;
+        v << 0.9f, 0.95f, 0.001f, 0.5, 2;
+        return v;
+    }
+};
+
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/sensor.cpp b/VirtualRobot/MJCF/elements/types/sensor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4d9a02cef8baf45ace6846bb891cb723c0cb0094
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/sensor.cpp
@@ -0,0 +1,9 @@
+#include "sensor.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string SensorSection::tag    = "sensor";
diff --git a/VirtualRobot/MJCF/elements/types/sensor.h b/VirtualRobot/MJCF/elements/types/sensor.h
new file mode 100644
index 0000000000000000000000000000000000000000..fbeda6e4ec75e2f04212457e5732096a42685bd8
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/sensor.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+struct SensorSection : public Element<SensorSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(SensorSection)
+};
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/size.cpp b/VirtualRobot/MJCF/elements/types/size.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79e6a61c5a7fbef1606ca7afb2d2629e3de2ba0a
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/size.cpp
@@ -0,0 +1,8 @@
+#include "size.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
+
+const std::string SizeSection::tag      = "size";
diff --git a/VirtualRobot/MJCF/elements/types/size.h b/VirtualRobot/MJCF/elements/types/size.h
new file mode 100644
index 0000000000000000000000000000000000000000..4800f4e007100cb13a0d9b00ac1a5a130b3afb00
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/size.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+struct SizeSection : public Element<SizeSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(SizeSection)
+};
+
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/statistic.cpp b/VirtualRobot/MJCF/elements/types/statistic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5dfd99ff8f6431fd2fea32a76b7df71d01091250
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/statistic.cpp
@@ -0,0 +1,9 @@
+#include "statistic.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string StatisticSection::tag = "statistic";
diff --git a/VirtualRobot/MJCF/elements/types/statistic.h b/VirtualRobot/MJCF/elements/types/statistic.h
new file mode 100644
index 0000000000000000000000000000000000000000..be439e89f62f7bdc9a5d86265ec267fa700beafe
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/statistic.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+struct StatisticSection : public Element<StatisticSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(StatisticSection)
+};
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/tendon.cpp b/VirtualRobot/MJCF/elements/types/tendon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9148a1bb58f3546ebd03d0f2cfe89763e59f9a4
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/tendon.cpp
@@ -0,0 +1,10 @@
+#include "tendon.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string TendonSection::tag    = "tendon";
+
diff --git a/VirtualRobot/MJCF/elements/types/tendon.h b/VirtualRobot/MJCF/elements/types/tendon.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fc81e5c2975767c8e87cd36f84c4e078403cb40
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/tendon.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+
+struct TendonSection : public Element<TendonSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(TendonSection)
+};
+
+
+}
diff --git a/VirtualRobot/MJCF/elements/types/visual.cpp b/VirtualRobot/MJCF/elements/types/visual.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..72dd1bb81cb2b1728400f5e8329cef0106ff4986
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/visual.cpp
@@ -0,0 +1,9 @@
+#include "visual.h"
+
+//#include "../Document.h"
+
+
+using namespace mjcf;
+
+
+const std::string VisualSection::tag    = "visual";
diff --git a/VirtualRobot/MJCF/elements/types/visual.h b/VirtualRobot/MJCF/elements/types/visual.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c9233cbb44594ff3f4775397d756e2a6d9172fa
--- /dev/null
+++ b/VirtualRobot/MJCF/elements/types/visual.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "../core/Attribute.h"
+
+namespace mjcf
+{
+
+struct VisualSection : public Element<VisualSection>
+{
+    static const std::string tag;
+    mjcf_ElementDerivedConstructors(VisualSection)
+};
+
+}
diff --git a/VirtualRobot/MJCF/visitors.h b/VirtualRobot/MJCF/visitors.h
new file mode 100644
index 0000000000000000000000000000000000000000..f2cec55304656772d1fcdfddcef23870ac4deb99
--- /dev/null
+++ b/VirtualRobot/MJCF/visitors.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "visitors/Collector.h"
diff --git a/VirtualRobot/MJCF/visitors/Collector.cpp b/VirtualRobot/MJCF/visitors/Collector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f838bce55a8fe3bdd79dc2948abc2cdb042c234
--- /dev/null
+++ b/VirtualRobot/MJCF/visitors/Collector.cpp
@@ -0,0 +1,7 @@
+#include "Collector.h"
+
+
+namespace mjcf
+{
+
+}
diff --git a/VirtualRobot/MJCF/visitors/Collector.h b/VirtualRobot/MJCF/visitors/Collector.h
new file mode 100644
index 0000000000000000000000000000000000000000..bb8ed7e45f3c50c5ea7177b91103c7371d14f2a5
--- /dev/null
+++ b/VirtualRobot/MJCF/visitors/Collector.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "../elements.h"
+
+
+namespace mjcf
+{
+    
+    /**
+     * @brief A visitor that collects all elements of the specified type.
+     */
+    template <class ElementT>
+    class Collector : public Visitor
+    {
+    public:
+        
+        static std::vector<ElementT> collect(Document& document, AnyElement root);
+        
+        Collector(Document& document) : Visitor(document) {}
+        
+        // Visitor interface
+        virtual bool visitEnter(const AnyElement& element) override
+        {
+            if (element.is<ElementT>())
+            {
+                collected.push_back(element.as<ElementT>());
+            }
+            return true;
+        }
+        
+        std::vector<ElementT>& getCollected() { return collected; }
+        const std::vector<ElementT>& getCollected() const  { return collected; }
+        
+        
+    private:
+        
+        std::vector<ElementT> collected;
+        
+    };
+    
+    template <class ElementT>
+    std::vector<ElementT> Collector<ElementT>::collect(Document& document, AnyElement root)
+    {
+        mjcf::Collector<ElementT> collector(document);
+        root.accept(collector);
+        return collector.getCollected();
+    }
+}
+
diff --git a/VirtualRobot/RuntimeEnvironment.cpp b/VirtualRobot/RuntimeEnvironment.cpp
index f732247d4186fbd41ec41f58f4d66f6c282fd46f..ddf09253616b702d2d2ab715f2bea58bd291a561 100644
--- a/VirtualRobot/RuntimeEnvironment.cpp
+++ b/VirtualRobot/RuntimeEnvironment.cpp
@@ -11,11 +11,18 @@
 
 namespace VirtualRobot
 {
-    std::vector< std::string > RuntimeEnvironment::processKeys;
-    std::vector< std::string > RuntimeEnvironment::unrecognizedOptions;
+    bool RuntimeEnvironment::pathInitialized = false;
+    
+    std::string RuntimeEnvironment::caption = "Simox runtime options";
+    
+    std::vector< std::pair<std::string, std::string> > RuntimeEnvironment::processKeys;
+    std::vector< std::pair<std::string, std::string> > RuntimeEnvironment::processFlags;
+    
     std::vector< std::string > RuntimeEnvironment::dataPaths;
+    std::vector< std::string > RuntimeEnvironment::unrecognizedOptions;
     std::map< std::string, std::string > RuntimeEnvironment::keyValues;
-    bool RuntimeEnvironment::pathInitialized = false;
+    std::set< std::string > RuntimeEnvironment::flags;
+    bool RuntimeEnvironment::helpFlag = false;
 
     void RuntimeEnvironment::init()
     {
@@ -100,7 +107,7 @@ namespace VirtualRobot
             }
         }
     }
-
+    
     bool RuntimeEnvironment::getDataFileAbsolute(std::string& fileName)
     {
         if (!pathInitialized)
@@ -153,39 +160,60 @@ namespace VirtualRobot
         return false;
     }
 
-
     void RuntimeEnvironment::processCommandLine(int argc, char* argv[])
     {
         if (!pathInitialized)
         {
             init();
         }
+        
+        const boost::program_options::options_description description = makeOptionsDescription();
+        
+        const boost::program_options::parsed_options parsed =
+            boost::program_options::command_line_parser(argc, argv).options(description).allow_unregistered().run();
 
+        processParsedOptions(parsed);
+    }
+    
+    boost::program_options::options_description RuntimeEnvironment::makeOptionsDescription()
+    {
         // Declare the supported options.
-        boost::program_options::options_description desc("Simox runtime options");
+        
+        boost::program_options::options_description desc(caption);
         desc.add_options()
-        ("help", "Simox command line parser: Set options with '--key value'\n")
-        ("data-path", boost::program_options::value< std::vector< std::string > >()->composing(), "Set data path. Multiple data paths are allowed.")
+            ("help", "Simox command line parser: Set options with '--key value'\n")
+            ("data-path", boost::program_options::value<std::vector<std::string>>()->composing(), 
+             "Set data path. Multiple data paths are allowed.")
         ;
 
-        for (auto& processKey : processKeys)
+        for (const auto& item : processKeys)
+        {
             desc.add_options()
-            (processKey.c_str(), boost::program_options::value< std::vector< std::string > >(), processKey.c_str())
+            (item.first.c_str(), boost::program_options::value<std::vector<std::string>>(), item.second.c_str())
             ;
+        }
 
-        boost::program_options::parsed_options parsed =
-            boost::program_options::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
-
+        for (const auto& item : processFlags)
+        {
+            desc.add_options()
+            (item.first.c_str(), item.second.c_str())
+            ;
+        }
+        return desc;
+    }
+    
+    void RuntimeEnvironment::processParsedOptions(const boost::program_options::parsed_options& parsed)
+    {
         boost::program_options::variables_map vm;
         //boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
         boost::program_options::store(parsed, vm);
         boost::program_options::notify(vm);
-
+        
         // process data-path entries
         if (vm.count("data-path"))
         {
             //VR_INFO << "Data paths are: " << endl;
-            std::vector< std::string > dp = vm["data-path"].as< std::vector< std::string > >();
+            std::vector<std::string> dp = vm["data-path"].as< std::vector< std::string > >();
 
             for (const auto& i : dp)
             {
@@ -195,36 +223,45 @@ namespace VirtualRobot
         }
 
         // process generic keys
-        for (auto& processKey : processKeys)
+        for (const auto& processKey : processKeys)
         {
-            if (vm.count(processKey.c_str()))
+            const std::string& key = processKey.first;
+            if (vm.count(key.c_str()) > 0)
             {
-                std::vector< std::string > dp = vm[processKey.c_str()].as< std::vector< std::string > >();
+                std::vector<std::string> dp = vm[key.c_str()].as<std::vector<std::string>>();
 
                 if (dp.size() > 1)
                 {
-                    VR_WARNING << "More than one parameter for key " << processKey << ". taking the first one..." << endl;
+                    VR_WARNING << "More than one parameter for key '" << key << "'. Using only first one..." << endl;
                 }
 
                 if (dp.size() > 0)
                 {
-                    addKeyValuePair(processKey, dp[0]);    // take the first one...
+                    addKeyValuePair(key, dp[0]);    // take the first one...
                 }
             }
 
         }
+        
+        for (const auto& flag : processFlags)
+        {
+            if (vm.count(flag.first.c_str()) > 0)
+            {
+                flags.insert(flag.first);
+            }
+        }
+        helpFlag = vm.count("help") > 0;
 
         // collect unrecognized arguments
-        std::vector<std::string> options = boost::program_options::collect_unrecognized(parsed.options, boost::program_options::include_positional);
+        std::vector<std::string> options = boost::program_options::collect_unrecognized(
+                    parsed.options, boost::program_options::include_positional);
 
         for (const auto& option : options)
         {
             unrecognizedOptions.push_back(option);
         }
-
-
     }
-
+    
     void RuntimeEnvironment::addKeyValuePair(const std::string& key, const std::string& value)
     {
         keyValues[key] = value;
@@ -260,6 +297,11 @@ namespace VirtualRobot
 
         return dataPaths;
     }
+    
+    void RuntimeEnvironment::setCaption(const std::string& caption)
+    {
+        RuntimeEnvironment::caption = caption;
+    }
 
     bool RuntimeEnvironment::addDataPath(const std::string& path, bool quiet)
     {
@@ -285,6 +327,26 @@ namespace VirtualRobot
         return false;
     }
 
+    static std::size_t getMaxLength(const std::vector<std::pair<std::string, std::string>>& items)
+    {
+        std::size_t max = 0;
+        for (const auto& key : items)
+        {
+            max = std::max(max, key.first.size());
+        }
+        return max;
+    }
+    
+    static std::string padding(std::size_t current, std::size_t target, char c = ' ')
+    {
+        std::stringstream ss;
+        while (target --> current)
+        {
+            ss << c;
+        }
+        return ss.str();
+    }
+    
     void RuntimeEnvironment::print()
     {
         if (!pathInitialized)
@@ -300,25 +362,45 @@ namespace VirtualRobot
             cout << " * " << dataPath << endl;
         }
 
-        if (processKeys.size() > 0)
+        const std::size_t descriptionOffset = std::max(
+                    getMaxLength(processKeys), getMaxLength(processFlags)) + 4;
+        
+        auto printDescriptions = [&descriptionOffset](
+                const std::vector<std::pair<std::string, std::string>>& items,
+                const std::string& name)
         {
-            cout << "Known keys:" << endl;
-
-            for (const auto& processKey : processKeys)
+            if (items.size() > 0)
             {
-                cout << " * " << processKey << endl;
+                cout << "Known " << name << ":" << endl;
+    
+                for (const auto& item : items)
+                {
+                    cout << " * " << item.first
+                         << padding(item.first.size(), descriptionOffset)
+                         << item.second << endl;
+                }
             }
-        }
+        };
+        
+        printDescriptions(processKeys, "keys");
+        printDescriptions(processFlags, "flags");
+        
 
         if (keyValues.size() > 0)
         {
             cout << "Parsed options:"  << endl;
-            std::map< std::string, std::string >::iterator it = keyValues.begin();
-
-            while (it != keyValues.end())
+            for (const auto& item : keyValues)
             {
-                cout << " * " << it->first << ": " << it->second << endl;
-                it++;
+                cout << " * " << item.first << ": " << item.second << endl;
+            }
+        }
+        
+        if (flags.size() > 0)
+        {
+            cout << "Parsed flags:"  << endl;
+            for (const auto& flag : flags)
+            {
+                cout << " * " << flag << endl;
             }
         }
 
@@ -331,84 +413,98 @@ namespace VirtualRobot
                 cout << " * <" << unrecognizedOption << ">" << endl;
             }
         }
-
+    }
+    
+    void RuntimeEnvironment::printOptions(std::ostream& os)
+    {
+        os << makeOptionsDescription() << std::endl;
     }
 
-    void RuntimeEnvironment::considerKey(const std::string& key)
+    void RuntimeEnvironment::considerKey(const std::string& key, const std::string& description)
     {
-        processKeys.push_back(key);
+        processKeys.emplace_back(key, description);
+    }
+    
+    void RuntimeEnvironment::considerFlag(const std::string& flag, const std::string& description)
+    {
+        processFlags.emplace_back(flag, description);
     }
 
     bool RuntimeEnvironment::hasValue(const std::string& key)
     {
-        return (keyValues.find(key) != keyValues.end());
+        return keyValues.find(key) != keyValues.end();
+    }
+    
+    bool RuntimeEnvironment::hasFlag(const std::string& flag)
+    {
+        return flags.find(flag) != flags.end();
+    }
+    
+    bool RuntimeEnvironment::hasHelpFlag()
+    {
+        return helpFlag;
     }
 
 
     float RuntimeEnvironment::toFloat(const std::string& s)
     {
-        float a = (float)atof(s.c_str());
-        return a;
+        return std::stof(s);
     }
 
     int RuntimeEnvironment::toInt(const std::string& s)
     {
-        int a = (int)atoi(s.c_str());
-        return a;
+        return std::stoi(s);
     }
 
-    bool RuntimeEnvironment::toVector3f(const std::string& s, Eigen::Vector3f& storeResult)
+    bool RuntimeEnvironment::toVector3f(const std::string& string, Eigen::Vector3f& storeResult)
     {
-        if (s.length() < 3)
+        if (string.length() < 3)
         {
             return false;
         }
 
-        if (s[0] != '(' || s[s.length() - 1] != ')')
+        if (string[0] != '(' || string[string.length() - 1] != ')')
         {
-            VR_WARNING << "Expecting string to start and end with brackets (): " << s << endl;
+            VR_WARNING << "Expecting string to start and end with brackets (): " << string << endl;
             return false;
         }
 
-        std::string s2 = s;
-        s2.erase(s2.begin(), s2.begin() + 1);
-        s2.erase(s2.end() - 1, s2.end());
-        std::vector<std::string> strs;
-        std::string del(",");
+        const std::string stringTrimmed = string.substr(1, string.size() - 1);
+        const std::string delimiter = ",";
 
-        boost::split(strs, s2, boost::is_any_of(del));
+        std::vector<std::string> stringSplit;
+        boost::split(stringSplit, stringTrimmed, boost::is_any_of(delimiter));
 
-        if (strs.size() != 3)
+        if (stringSplit.size() != 3)
         {
-            VR_WARNING << "Expecting values of string to be separated with a ',': " << s << endl;
+            VR_WARNING << "Expecting values of string to be separated with a ',': " << string << endl;
             return false;
         }
 
-        float a = (float)atof(strs[0].c_str());
-        float b = (float)atof(strs[1].c_str());
-        float c = (float)atof(strs[2].c_str());
-
-        if (boost::math::isinf(a) || boost::math::isinf(-a) || boost::math::isnan(a))
+        Eigen::Vector3f result;
+        
+        for (int i = 0; i < result.SizeAtCompileTime; ++i)
         {
-            VR_WARNING << "Could not convert " << strs[0] << " to a number" << endl;
-            return false;
-        }
-
-        if (boost::math::isinf(b) || boost::math::isinf(-b) || boost::math::isnan(b))
-        {
-            VR_WARNING << "Could not convert " << strs[1] << " to a number" << endl;
-            return false;
-        }
-
-        if (boost::math::isinf(c) || boost::math::isinf(-c) || boost::math::isnan(c))
-        {
-            VR_WARNING << "Could not convert " << strs[2] << " to a number" << endl;
-            return false;
+            const std::string& string = stringSplit[static_cast<std::size_t>(i)];
+            bool error = false;
+            float a;
+            try
+            {
+                a = std::stof(string);
+            }
+            catch (const std::invalid_argument&)
+            {
+                error = true;
+            }
+            if (error || boost::math::isinf(a) || boost::math::isinf(-a) || boost::math::isnan(a))
+            {
+                VR_WARNING << "Could not convert '" << string << "' to a number." << endl;
+                return false;
+            }
+            result(i) = a;
         }
-
-        storeResult(0) = a;
-        storeResult(1) = b;
-        storeResult(2) = c;
+        
+        storeResult = result;
         return true;
     }
 
@@ -453,7 +549,7 @@ namespace VirtualRobot
 
     void RuntimeEnvironment::cleanup()
     {
-        VisualizationFactoryPtr visualizationFactory = VisualizationFactory::first(NULL);
+        VisualizationFactoryPtr visualizationFactory = VisualizationFactory::first(nullptr);
 
         if (visualizationFactory)
         {
diff --git a/VirtualRobot/RuntimeEnvironment.h b/VirtualRobot/RuntimeEnvironment.h
index d333e6aef7e81ef416ae2f7925afd8e6c97224e5..a38c2f1392ccb6d3ec6f9b958e09604f066b428c 100644
--- a/VirtualRobot/RuntimeEnvironment.h
+++ b/VirtualRobot/RuntimeEnvironment.h
@@ -24,66 +24,73 @@
 
 #include "VirtualRobot.h"
 
+#include <map>
+#include <set>
 #include <string>
 #include <vector>
-#include <map>
+
 #include <Eigen/Core>
 
+
 namespace VirtualRobot
 {
     /*!
-        The runtime environment holds data paths and program arguments.
-        Data files can be located by the getDataFileAbsolute method.
-        Here, the environment variable SIMOX_DATA_PATH and VIRTUAL_ROBOT_DATA_PATH are considered.
-        In addition, the install data directory is added at the end of the list of data paths for convenient access.
+     * The runtime environment holds data paths and program arguments.
+     * Data files can be located by the getDataFileAbsolute method.
+     * Here, the environment variable SIMOX_DATA_PATH and VIRTUAL_ROBOT_DATA_PATH are considered.
+     * In addition, the install data directory is added at the end of the list of data paths for convenient access.
     */
     class VIRTUAL_ROBOT_IMPORT_EXPORT RuntimeEnvironment
     {
     public:
         EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 
-        /*!
-            Return vector of all data paths.
-        */
+        //! Return vector of all data paths.
         static std::vector< std::string > getDataPaths();
 
+        /// Set the runtime environment caption.
+        static void setCaption(const std::string& caption);
+        
         /*!
-            Add a path to global data path vector. These paths are searched within the getDataFileAbsolute() method.
-            Only valid paths are processed.
-            \param path The path to add.
-            \param quiet If set, invalid paths are quietly ignored. Otherwise an error is printed.
-            \return true on success (path has to be a directory or a symlink).
-        */
+         * Add a path to global data path vector. 
+         * These paths are searched within the getDataFileAbsolute() method.
+         * Only valid paths are processed.
+         * \param path The path to add.
+         * \param quiet If set, invalid paths are quietly ignored. Otherwise an error is printed.
+         * \return true on success (path has to be a directory or a symlink).
+         */
         static bool addDataPath(const std::string& path, bool quiet = false);
 
         /*!
-            Enable the command line search for given key. Only keys that are enabled can later be accessed with the getValue() method.
-        */
-        static void considerKey(const std::string& key);
+         * \brief Enable the command line search for given key. 
+         * Only keys that are enabled can later be accessed with the getValue() method.
+         */
+        static void considerKey(const std::string& key, const std::string& description = "");
+        /*!
+         * \brief Enable the command line search for given flag.
+         * A flag does not take an argument but is either present or not.
+         */
+        static void considerFlag(const std::string& flag, const std::string& description = "");
 
         /*!
-            Tries to find a file with name fileName. Therefore the working directory followed by all data paths are checked if the file can be found.
-            \param fileName Could be a filename or a relative path. In case the file could be located, the absolute path is stored in place.
-            \return True when the file could be located (the result will be stored in fileName).
-        */
+         * Tries to find a file with name fileName. Therefore the working directory followed by all data paths are checked if the file can be found.
+         * \param fileName Could be a filename or a relative path. In case the file could be located, the absolute path is stored in place.
+         * \return True when the file could be located (the result will be stored in fileName).
+         */
         static bool getDataFileAbsolute(std::string& fileName);
 
         /*!
-            The command line parameters can be passed in order to generate a map of key/value pairs.
-            All "--key value" pairs for which the key was enabled with the allowCommandLineOption() method are processed and stored as std::strings in a std::map.
-            In addition, all "--data-path <path>" entries are extracted and the according data paths are stored.
-            All unrecognized options are also stored.
-        */
+         * The command line parameters can be passed in order to generate a map of key/value pairs.
+         * All "--key value" pairs for which the key was enabled with the allowCommandLineOption() method are processed and stored as std::strings in a std::map.
+         * In addition, all "--data-path <path>" entries are extracted and the according data paths are stored.
+         * All unrecognized options are also stored.
+         */
         static void processCommandLine(int argc, char* argv[]);
 
-        /*!
-            Manually add a key/value pair.
-        */
+        //! Manually add a key/value pair.
         static void addKeyValuePair(const std::string& key, const std::string& value);
 
-        /*!
-            Return the corresponding vale to key. If key cannot be found, defaultValue is returned.
-        */
+        //! Return the corresponding vale to key. If key cannot be found, defaultValue is returned.
         static std::string getValue(const std::string& key, const std::string& defaultValue = "");
         template<class T>
         static T getValue(const std::string& key, const T& defaultValue)
@@ -92,66 +99,85 @@ namespace VirtualRobot
         }
         static bool hasValue(const std::string& key);
 
-        //! return all key value pairs
-        static std::map< std::string, std::string > getKeyValuePairs();
+        /// Indicate whether the given flag was specified.
+        static bool hasFlag(const std::string& flag);
+        /// Indicate whether the 'help' flag was specified.
+        static bool hasHelpFlag();
+        
+        //! Return all key value pairs
+        static std::map<std::string, std::string> getKeyValuePairs();
 
-        //! return all unrecognized options
-        static std::vector< std::string > getUnrecognizedOptions();
+        //! Return all unrecognized options
+        static std::vector<std::string> getUnrecognizedOptions();
 
-        /*!
-            Converts strings as '(a,b,c)' to 3dim Vectors.
-        */
+        //! Convert strings as '(a,b,c)' to a 3 dimensional vector.
         static bool toVector3f(const std::string& s, Eigen::Vector3f& storeResult);
 
-        /*!
-         * \brief toFloat Get command line parameter as float
-         * \param s
-         * \return
-         */
+        //! Get the given string as float.
         static float toFloat(const std::string& s);
+        //! Get the given string as int.
         static int toInt(const std::string& s);
 
 
         /*!
-            Check if command line parameters specify a valid filename and
-            in case the key is not present in the command line arguments or the file was not found, the standardFilename is used.
-            Additionally the absolute filenames are considered by calling getDataFileAbsolute().
-            \param key  The key which is checked for a filename. It is checked if the key is present and if so, it is tried to
-                        construct a valid filename with getDataFileAbsolute().
-            \param standardFilename In case a valid file could not be determined, this file will be returned
-                                    (additionally it is made absolute by calling getDataFileAbsolute().
-                                    Hence, a filename with a relative path can be passed
-                                    and all datapaths are searched for it.
-            \return A valid filename if it can be found, otherwise the standardFilename is returned.
+         * Check if command line parameters specify a valid filename and
+         * in case the key is not present in the command line arguments or the file was not found, the standardFilename is used.
+         * Additionally the absolute filenames are considered by calling getDataFileAbsolute().
+         * \param key  The key which is checked for a filename. It is checked if the key is present and if so, it is tried to
+         *             construct a valid filename with getDataFileAbsolute().
+         * \param standardFilename In case a valid file could not be determined, this file will be returned
+         *                         (additionally it is made absolute by calling getDataFileAbsolute().
+         *                         Hence, a filename with a relative path can be passed
+         *                         and all datapaths are searched for it.
+         * \return A valid filename if it can be found, otherwise the standardFilename is returned.
         */
         static std::string checkValidFileParameter(const std::string& key, const std::string& standardFilename);
 
         /*!
-            Checks command line arguments for parameter key. iF present the corresponding value is returned,
-            otherwise standardValue will be returned.
-        */
+         * Checks command line arguments for parameter key.
+         * If present the corresponding value is returned, otherwise standardValue will be returned.
+         */
         static std::string checkParameter(const std::string& key, const std::string& standardValue = "");
 
-        //! Print status
+        //! Print status.
         static void print();
+        
+        //! Print the command line options (as printed by boost::program_options) to os.
+        static void printOptions(std::ostream& os = std::cout);
+        
 
         /*!
-            Free all resources. Usually not not needed, since on application exit all resources are freed automatically.
-        */
+         * \brief Free all resources. 
+         * Usually not not needed, since on application exit all resources are freed automatically.
+         */
         static void cleanup();
+        
+        
     protected:
 
         RuntimeEnvironment() {}
         virtual ~RuntimeEnvironment() {}
+        
         static bool pathInitialized;
+        
         static void init();
-
-
-        static std::vector< std::string > processKeys;
+        /// Make the options description based on the added keys and flags.
+        static boost::program_options::options_description makeOptionsDescription();
+        static void processParsedOptions(const boost::program_options::parsed_options& parsed);
+
+        static std::string caption;
+        
+        /// Pairs of (key, description). If not given, description is empty.
+        static std::vector< std::pair<std::string, std::string> > processKeys;
+        /// Pairs of (flag, description). If not given, description is empty.
+        static std::vector< std::pair<std::string, std::string> > processFlags;
+        
         static std::vector< std::string > dataPaths;
         static std::vector< std::string > unrecognizedOptions;
 
         static std::map< std::string, std::string > keyValues;
+        static std::set< std::string > flags;
+        static bool helpFlag;
     };
 
 } // namespace
diff --git a/VirtualRobot/XML/RobotIO.cpp b/VirtualRobot/XML/RobotIO.cpp
index 4ee8782c5a8f9bb5c5af5fe06fed34dd25cc9e52..23e3ee8c67e9e00f05d6ca2806eaab6b97b6ce87 100644
--- a/VirtualRobot/XML/RobotIO.cpp
+++ b/VirtualRobot/XML/RobotIO.cpp
@@ -15,7 +15,7 @@
 #include "../RobotConfig.h"
 #include "../RuntimeEnvironment.h"
 #include "rapidxml.hpp"
-#include "mjcf/MujocoIO.h"
+#include "mujoco/MujocoIO.h"
 
 
 #include <vector>
@@ -291,7 +291,7 @@ namespace VirtualRobot
         float maxVelocity = -1.0f; // m/s
         float maxAcceleration = -1.0f; // m/s^2
         float maxTorque = -1.0f; // Nm
-        float scaleVisu = false;
+        bool scaleVisu = false;
         Eigen::Vector3f scaleVisuFactor = Eigen::Vector3f::Zero();
 
         while (node)
@@ -1526,8 +1526,8 @@ namespace VirtualRobot
     void RobotIO::saveMJCF(RobotPtr robot, const std::string& filename,
                            const std::string& basePath, const std::string& meshDir)
     {
-        mjcf::MujocoIO mujocoIO(robot);
-        mujocoIO.setActuatorType(mjcf::ActuatorType::MOTOR);
+        mujoco::MujocoIO mujocoIO(robot);
+        mujocoIO.setActuatorType(mujoco::ActuatorType::MOTOR);
         mujocoIO.saveMJCF(filename, basePath, meshDir);
     }
 
diff --git a/VirtualRobot/XML/mjcf/MasslessBodySanitizer.cpp b/VirtualRobot/XML/mjcf/MasslessBodySanitizer.cpp
deleted file mode 100644
index e04389f540d4d08a5e3019ba8b96a57d8e5e0926..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/MasslessBodySanitizer.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-#include "MasslessBodySanitizer.h"
-#include "utils.h"
-
-#include <boost/algorithm/string/join.hpp>
-
-
-using namespace VirtualRobot;
-using namespace mjcf;
-namespace tx = tinyxml2;
-
-
-MasslessBodySanitizer::MasslessBodySanitizer(DocumentPtr& document, RobotPtr& robot) :
-    document(document), robot(robot)
-{
-    
-}
-
-void MasslessBodySanitizer::sanitize()
-{
-    // merge body leaf nodes with parent if they do not have a mass (inertial or geom)
-    
-    XMLElement* root = document->robotRootBody();
-    
-    for (XMLElement* body = root->FirstChildElement("body");
-         body;
-         body = body->NextSiblingElement("body"))
-    {
-        sanitizeRecursion(body);
-    }
-}
-
-
-void MasslessBodySanitizer::sanitizeRecursion(XMLElement* body)
-{
-    assertElementIsBody(body);
-
-    std::string bodyName = body->Attribute("name");
-    RobotNodePtr bodyNode = robot->getRobotNode(bodyName);
-    Eigen::Matrix4f accChildPose = Eigen::Matrix4f::Identity();
-    
-    while (!hasMass(body))
-    {
-        std::cout << t << bodyName << ": \t";
-        
-        if (!hasElementChild(body, "body"))
-        {
-            // leaf => end of recursion
-            sanitizeLeafBody(body);
-            return;
-        }
-        
-        // non-leaf body
-        // check whether there is only one child body
-        XMLElement* childBody = body->FirstChildElement("body");
-        if (!childBody->NextSiblingElement("body"))
-        {
-            mergeBodies(body, childBody, accChildPose);
-        }
-        else
-        {
-            std::cout << "Adding dummy inertial to massless body with >1 child bodies." << std::endl;
-            // add a small mass
-            document->addDummyInertial(body, true);
-            break;
-        }
-    }
-    
-    
-    // recursive descend
-    
-    for (XMLElement* child = body->FirstChildElement("body");
-         child;
-         child = child->NextSiblingElement("body"))
-    {
-        sanitizeRecursion(child);
-    }
-    
-}
-
-void MasslessBodySanitizer::mergeBodies(XMLElement* body, XMLElement* childBody, 
-                                            Eigen::Matrix4f& accChildPose)
-{
-    std::string childBodyName = childBody->Attribute("name");
-    
-    std::cout << "Merging with '" << childBodyName << "' ";
-
-    RobotNodePtr childNode = robot->getRobotNode(childBodyName);
-    Eigen::Matrix4f childPose = childNode->getTransformationFrom(childNode->getParent());
-    
-    // update accumulated child pose
-    // merged child's frame w.r.t. body's frame
-    accChildPose = childPose * accChildPose;
-    Eigen::Matrix3f accChildOri = accChildPose.block<3,3>(0, 0);
-    
-    // merge childBody into body => move all its elements here
-    // while doing this, apply accChildPose to elements
-    for (tx::XMLNode* grandChild = childBody->FirstChild(); grandChild;
-         grandChild = grandChild->NextSibling())
-    {
-        // clone grandchild
-        tx::XMLNode* grandChildClone = grandChild->DeepClone(nullptr);
-        
-        XMLElement* elem = grandChildClone->ToElement();
-        if (elem)
-        {
-            /* Adapt pose/axis elements in child. Their poses/axes will be
-                 * relative to body's frame, so the transformation from body
-                 * to child will be lost. Therefore, apply accChildPose to
-                 * their poses/axes. */
-            
-            if (isElement(elem, "joint"))
-            {
-                // update pos and axis
-                updateChildPos(elem, accChildPose);
-                updateChildAxis(elem, accChildOri);
-            }
-            else if (isElement(elem, "body") 
-                     || isElement(elem, "inertial")
-                     || isElement(elem, "geom") 
-                     || isElement(elem, "site")
-                     || isElement(elem, "camera"))
-            {
-                updateChildPos(elem, accChildPose);
-                updateChildQuat(elem, accChildOri);
-            }
-            else if (isElement(elem, "light"))
-            {
-                updateChildPos(elem, accChildPose);
-                updateChildAxis(elem, accChildOri, "dir");
-            }
-        }
-        
-        // insert to body
-        body->InsertEndChild(grandChildClone);
-    }
-    
-    // update body name
-    MergedBodySet& bodySet = getMergedBodySetWith(body->Attribute("name"));
-    bodySet.addBody(childBodyName);
-    body->SetAttribute("name", bodySet.getMergedBodyName().c_str());
-    
-    std::cout << "\t(new name: " << bodySet.getMergedBodyName() << ")" << std::endl;
-    
-    // delete child
-    body->DeleteChild(childBody);
-}
-
-void MasslessBodySanitizer::updateChildPos(XMLElement* elem, const Eigen::Matrix4f& accChildPose)
-{
-    const char* posStr = elem->Attribute("pos");
-    Eigen::Vector3f pos = posStr ? strToVec(posStr) : 
-                                   Eigen::Vector3f::Zero();
-    
-    Eigen::Vector4f posHom;
-    posHom << pos, 1;
-    posHom = accChildPose * posHom;
-    pos = posHom.head<3>();
-    
-    document->setElementPos(elem, pos);
-}
-
-void MasslessBodySanitizer::updateChildQuat(XMLElement* elem, const Eigen::Matrix3f& accChildOri)
-{
-    const char* quatStr = elem->Attribute("quat");
-    Eigen::Quaternionf quat = quatStr ? strToQuat(quatStr) : 
-                                        Eigen::Quaternionf::Identity();
-    
-    quat = accChildOri * quat;
-    document->setElementQuat(elem, quat);
-}
-
-void MasslessBodySanitizer::updateChildAxis(XMLElement* elem, const Eigen::Matrix3f& accChildOri, 
-                                                const char* attrName)
-{
-    Eigen::Vector3f axis = strToVec(elem->Attribute(attrName));
-    axis = accChildOri * axis;
-    elem->SetAttribute(attrName, toAttr(axis).c_str());
-    
-    if (strcmp(attrName, "axis") == 0)
-    {
-        document->setJointAxis(elem, axis);
-    }
-    else
-    {
-        elem->SetAttribute(attrName, toAttr(axis).c_str());
-    }
-}
-
-void MasslessBodySanitizer::sanitizeLeafBody(XMLElement* body)
-{
-    assert(!hasElementChild(body, "body"));
-    assert(!hasMass(body));
-    
-    if (body->NoChildren()) // is completely empty?
-    {
-        // leaf without geom: make it a site
-        std::cout << "Changing to site." << std::endl;
-        body->SetValue("site");
-    }
-    else
-    {
-        // add a small mass
-        std::cout << "Adding dummy inertial to massless leaf body with children." << std::endl;
-        document->addDummyInertial(body);
-    }
-}
-
-const std::vector<MergedBodySet>& MasslessBodySanitizer::getMergedBodySets() const
-{
-    return mergedBodySets;
-}
-
-const std::string& MasslessBodySanitizer::getMergedBodyName(const std::string& originalBodyName)
-{
-    return getMergedBodySetWith(originalBodyName).getMergedBodyName();
-}
-
-MergedBodySet&MasslessBodySanitizer::getMergedBodySetWith(const std::string& bodyName)
-{
-    for (auto& set : mergedBodySets)
-    {
-        if (set.containsBody(bodyName))
-        {
-           return set;
-        }
-    }
-    
-    // not found => add
-    mergedBodySets.push_back(MergedBodySet(bodyName));
-    
-    return mergedBodySets.back();
-}
-
-
-MergedBodySet::MergedBodySet()
-= default;
-
-MergedBodySet::MergedBodySet(const std::string& bodyName)
-{
-    addBody(bodyName);
-}
-
-void MergedBodySet::addBody(const std::string& bodyName)
-{
-    originalBodyNames.push_back(bodyName);
-    updateMergedBodyName();
-}
-
-bool MergedBodySet::containsBody(const std::string& bodyName) const
-{
-    return std::find(originalBodyNames.begin(), originalBodyNames.end(),
-                     bodyName) != originalBodyNames.end();
-}
-
-const std::string& MergedBodySet::getMergedBodyName() const
-{
-    return mergedBodyName;
-}
-
-void MergedBodySet::updateMergedBodyName()
-{
-    mergedBodyName = boost::algorithm::join(originalBodyNames, "~");
-}
diff --git a/VirtualRobot/XML/mjcf/MjcfDocument.cpp b/VirtualRobot/XML/mjcf/MjcfDocument.cpp
deleted file mode 100644
index 0224841e54cda8a1c3c464a1d0d36c0dc1027a54..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/MjcfDocument.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-#include "MjcfDocument.h"
-
-#include <VirtualRobot/Nodes/RobotNodePrismatic.h>
-#include <VirtualRobot/Nodes/RobotNodeRevolute.h>
-
-
-using namespace VirtualRobot;
-using namespace mjcf;
-
-
-Document::Document()
-{
-    // create root element
-    root = NewElement("mujoco");
-    this->InsertEndChild(root);
-}
-
-void Document::setModelName(const std::string& name)
-{
-    root->SetAttribute("model", name.c_str());
-}
-
-void Document::setNewElementClass(const std::string& className, bool excludeBody)
-{
-    this->newElementClass = className;
-    this->newElementClassExcludeBody = excludeBody;
-}
-
-XMLElement* Document::addSkyboxTexture(const Eigen::Vector3f& rgb1, const Eigen::Vector3f& rgb2)
-{
-    XMLElement* texSkybox = addNewElement(asset(), "texture");
-    
-    texSkybox->SetAttribute("type", "skybox");
-    texSkybox->SetAttribute("builtin", "gradient");
-    texSkybox->SetAttribute("width", 128);
-    texSkybox->SetAttribute("height", 128);
-    texSkybox->SetAttribute("rgb1", toAttr(rgb1).c_str());
-    texSkybox->SetAttribute("rgb2", toAttr(rgb2).c_str());   
-    
-    return texSkybox;
-}
-
-XMLElement* Document::addMocapBody(const std::string& name, float geomSize)
-{
-    /*
-        <body name="hand-ctrl" mocap="true" >
-            <geom type="box" size="0.01 0.01 0.01" contype="0" conaffinity="0" rgba="0.9 0.5 0.5 0.5" />
-        </body>
-      */
-    XMLElement* mocap = addNewElement(worldbody(), "body");
-    mocap->SetAttribute("name", name.c_str());
-    mocap->SetAttribute("mocap", "true");
-    
-    // add geom for visualization
-    
-    XMLElement* geom = addNewElement(mocap, "geom");
-    geom->SetAttribute("type", "box");
-    setAttr(geom, "size", Eigen::Vector3f{geomSize, geomSize, geomSize});
-    
-    return mocap;
-}
-
-
-
-XMLElement* Document::addDefaultsClass(const std::string& className)
-{
-    XMLElement* def = addNewElement(default_(), "default", className);
-    
-    return def;
-}
-
-XMLElement* Document::addRobotRootBodyElement(const std::string& robotName)
-{
-    this->robotRootBody_ = addNewElement(worldbody(), "body");
-    
-    robotRootBody_->SetAttribute("name", robotName.c_str());
-    robotRootBody_->SetAttribute("childclass", robotName.c_str());
-    
-    return robotRootBody_;
-}
-
-XMLElement* Document::addBodyElement(XMLElement* parent, RobotNodePtr node)
-{
-    XMLElement* body = addNewElement(parent, "body");
-    body->SetAttribute("name", node->getName().c_str());
-
-    if (node->hasParent())
-    {
-        Eigen::Matrix4f tf = node->getTransformationFrom(node->getParent());
-        setElementPose(body, tf);
-    }
-    
-    if (node->isRotationalJoint() || node->isTranslationalJoint())
-    {
-        addJointElement(body, node);
-    }
-    
-    addInertialElement(body, node);
-    
-    return body;
-}
-
-
-XMLElement* Document::addGeomElement(XMLElement* body, const std::string& meshName)
-{
-    assertElementIsBody(body);
-    
-    XMLElement* geom = addNewElement(body, "geom", "", true);
-    
-    geom->SetAttribute("type", "mesh");
-    geom->SetAttribute("mesh", meshName.c_str());
-    
-    return geom;
-}
-
-XMLElement* Document::addInertialElement(XMLElement* body, RobotNodePtr node)
-{
-    assertElementIsBody(body);
-    
-    Eigen::Matrix3f matrix = node->getInertiaMatrix();
-    if (matrix.isIdentity(floatCompPrecision) && node->getMass() < floatCompPrecision)
-    {
-        // dont set an inertial element and let it be derived automatically
-        return nullptr;
-    }
-    
-    XMLElement* inertial = addNewElement(body, "inertial");
-    
-    Eigen::Vector3f pos = node->getCoMLocal();
-    inertial->SetAttribute("pos", toAttr(pos).c_str());
-    inertial->SetAttribute("mass", double(node->getMass()));
-    
-    if (matrix.isDiagonal(floatCompPrecision))
-    {
-        Eigen::Vector3f diag = matrix.diagonal();
-        inertial->SetAttribute("diaginertia", toAttr(diag).c_str());
-    }
-    else
-    {
-        /* from mujoco xml reference:
-         * "Full inertia matrix M. Since M is 3-by-3 and symmetric, it is 
-         * specified using only 6 numbers in the following order: 
-         * M(1,1), M(2,2), M(3,3), M(1,2), M(1,3), M(2,3)." */
-        Eigen::Matrix<float, 6, 1> inertia;
-        inertia << matrix(0, 0), matrix(1, 1), matrix(2, 2),
-                matrix(0, 1), matrix(0, 2), matrix(1, 2);
-        inertial->SetAttribute("fullinertia", toAttr(inertia).c_str());
-    }
-    
-    return inertial;
-}
-
-XMLElement*Document::addDummyInertial(XMLElement* body, bool first)
-{
-    assertElementIsBody(body);
-    
-    XMLElement* inertial = addNewElement(body, "inertial", "", first);
-    
-    inertial->SetAttribute("pos", toAttr(Eigen::Vector3f(0, 0, 0)).c_str());
-    inertial->SetAttribute("mass", dummyMass);
-    inertial->SetAttribute("diaginertia", toAttr(Eigen::Vector3f(1, 1, 1)).c_str());
-    
-    return inertial;
-}
-
-
-XMLElement* Document::addJointElement(XMLElement* body, RobotNodePtr node)
-{
-    assert(node->isRotationalJoint() xor node->isTranslationalJoint());
-    
-    XMLElement* joint = addNewElement(body, "joint");
-    
-    joint->SetAttribute("name", node->getName().c_str());
-    
-    // get the axis
-    Eigen::Vector3f axis;
-    if (node->isRotationalJoint())
-    {
-        RobotNodeRevolutePtr revolute = boost::dynamic_pointer_cast<RobotNodeRevolute>(node);
-        assert(revolute);
-        axis = revolute->getJointRotationAxisInJointCoordSystem();
-    }
-    else if (node->isTranslationalJoint())
-    {
-        RobotNodePrismaticPtr prismatic = boost::dynamic_pointer_cast<RobotNodePrismatic>(node);
-        assert(prismatic);
-        axis = prismatic->getJointTranslationDirectionJointCoordSystem();
-    }
-    
-    joint->SetAttribute("type", node->isRotationalJoint() ? "hinge" : "slide");
-    setJointAxis(joint, axis);
-    joint->SetAttribute("limited", toAttr(!node->isLimitless()).c_str());
-    
-    if (!node->isLimitless())
-    {
-        Eigen::Vector2f range(node->getJointLimitLow(), node->getJointLimitHigh());
-        joint->SetAttribute("range", toAttr(range).c_str());
-    }
-    
-    return joint;
-}
-
-XMLElement* Document::addFreeJointElement(XMLElement* body)
-{
-    assertElementIsBody(body);
-    return addNewElement(body, "freejoint");
-}
-
-XMLElement* Document::addMeshElement(const std::string& name, const std::string& file, const std::string& className)
-{
-    XMLElement* mesh = addNewElement(asset(), "mesh", className);
-    
-    mesh->SetAttribute("name", name.c_str());
-    mesh->SetAttribute("file", file.c_str());
-    
-    return mesh;
-}
-
-XMLElement* Document::addActuatorMotorElement(const std::string& jointName)
-{
-    return addActuatorShortcut("motor", jointName, jointName);
-}
-
-XMLElement*Document::addActuatorPositionElement(const std::string& jointName, float kp)
-{
-    return addActuatorShortcut("position", jointName, jointName, "kp", kp);
-}
-
-XMLElement*Document::addActuatorPositionElement(const std::string& jointName, bool ctrlLimited, 
-                                                const Eigen::Vector2f& ctrlRange, float kp)
-{
-    XMLElement* act = addActuatorPositionElement(jointName, kp);
-    act->SetAttribute("ctrllimited", toAttr(ctrlLimited).c_str());
-    act->SetAttribute("ctrlrange", toAttr(ctrlRange).c_str());
-    return act;
-}
-
-XMLElement*Document::addActuatorVelocityElement(const std::string& jointName, float kv)
-{
-    return addActuatorShortcut("velocity", jointName, jointName, "kv", kv);
-}
-
-XMLElement* Document::addEqualityWeld(const std::string& name, const std::string& body1, const std::string& body2, const std::string& className)
-{
-    XMLElement* weld = addNewElement(equality(), "weld", className);
-    
-    weld->SetAttribute("name", name.c_str());
-    weld->SetAttribute("body1", body1.c_str());
-    weld->SetAttribute("body2", body2.c_str());
-    
-    return weld;
-}
-
-
-XMLElement* Document::addActuatorShortcut(
-        const std::string& type, const std::string& name, const std::string& jointName, 
-        const std::string& paramName, float paramValue)
-{
-    XMLElement* motor = addNewElement(actuator(), type.c_str());
-    
-    motor->SetAttribute("name",  name.c_str());
-    motor->SetAttribute("joint", jointName.c_str());
-    
-    if (!paramName.empty() && paramValue > floatCompPrecision)
-    {
-        motor->SetAttribute(paramName.c_str(), paramValue);
-    }
-    
-    return motor;
-}
-
-
-void Document::setElementPose(XMLElement* elem, const Eigen::Matrix4f& pose)
-{
-    Eigen::Vector3f pos = pose.block<3,1>(0, 3);
-    Eigen::Matrix3f oriMat = pose.block<3,3>(0, 0);
-    
-    Eigen::Quaternionf quat(oriMat);
-    
-    setElementPos(elem, pos);
-    setElementQuat(elem, quat);
-}
-
-void Document::setElementPos(XMLElement* elem, Eigen::Vector3f pos)
-{
-    if (!pos.isZero(floatCompPrecision))
-    {
-        elem->SetAttribute("pos", toAttr(pos).c_str());
-    }
-    else
-    {
-        elem->DeleteAttribute("pos");
-    }
-}
-
-void Document::setElementQuat(XMLElement* elem, const Eigen::Quaternionf& quat)
-{
-    if (!quat.isApprox(Eigen::Quaternionf::Identity(), floatCompPrecision))
-    {
-        elem->SetAttribute("quat", toAttr(quat).c_str());
-    }
-    else
-    {
-        elem->DeleteAttribute("quat");
-    }
-}
-
-void Document::setJointAxis(XMLElement* joint, const Eigen::Vector3f& axis)
-{
-    assertElementIs(joint, "joint");
-    joint->SetAttribute("axis", toAttr(axis).c_str());
-}
-
-
-XMLElement* Document::addContactExclude(const XMLElement& body1, const XMLElement& body2)
-{
-    return addContactExclude(body1.Attribute("name"), body2.Attribute("name"));
-}
-
-XMLElement* Document::addContactExclude(const std::string& body1Name, const std::string& body2Name)
-{
-    XMLElement* exclude = addNewElement(contact(), "exclude");
-    
-    exclude->SetAttribute("body1", body1Name.c_str());
-    exclude->SetAttribute("body2", body2Name.c_str());
-    
-    return exclude;
-}
-
-
-XMLElement* Document::addNewElement(XMLElement* parent, const std::string& elemName, 
-                                 const std::string& className, bool first)
-{
-    XMLElement* elem = NewElement(elemName.c_str());
-    
-    if (!className.empty())
-    {
-        elem->SetAttribute("class", className.c_str());
-    }
-    else if (!newElementClass.empty()
-             && !(newElementClassExcludeBody && (isElement(parent, "body") || isElement(elem, "body")))
-             && allowsClassAttr({parent->Value(), elemName}))
-    {
-        elem->SetAttribute("class", newElementClass.c_str());
-    }
-    
-    if (first)
-    {
-        parent->InsertFirstChild(elem);
-    }
-    else
-    {
-        parent->InsertEndChild(elem);
-    }
-    return elem;
-}
-
-XMLElement* Document::getOrCreateElement(XMLElement* parent, const std::string& elemName)
-{
-    XMLElement* elem = parent->FirstChildElement(elemName.c_str());
-    if (!elem)
-    {
-        elem = addNewElement(parent, elemName);
-    }
-    return elem;
-}
-
-XMLElement* Document::section(const std::string& name)
-{
-    return getOrCreateElement(root, name);
-}
-
-void Document::setDummyMass(float value)
-{
-    dummyMass = value;
-}
-
-void Document::setFloatCompPrecision(float value)
-{
-    floatCompPrecision = value;
-}
-
-
-XMLElement* Document::robotRootBody() const
-{
-    return robotRootBody_;
-}
-
-
-const std::set<Document::ElementType> Document::ELEM_NAMES_WITH_ATTR_CLASS = 
-{
-    {"asset", "mesh"    },
-    {"asset", "material"},
-    
-    {"body", "joint"    },
-    {"body", "geom"     },
-    {"body", "site"     },
-    {"body", "camera"   },
-    {"body", "light"    },
-    
-    {"contact", "pair"  },
-    
-    {"equality", "connect"  },
-    {"equality", "weld"     },
-    {"equality", "joint"    },
-    {"equality", "tendon"   },
-    {"equality", "distance" },
-    
-    {"tendon", "spatial" },
-    {"tendon", "fixed"   },
-    
-    {"actuator", "general"  },
-    {"actuator", "motor"    },
-    {"actuator", "position" },
-    {"actuator", "velocity" },
-    {"actuator", "cylinder" },
-    {"actuator", "muscle"   },
-};
-
-bool Document::allowsClassAttr(const Document::ElementType& type)
-{
-    return ELEM_NAMES_WITH_ATTR_CLASS.find(type) != ELEM_NAMES_WITH_ATTR_CLASS.end();
-}
-
-
diff --git a/VirtualRobot/XML/mjcf/MjcfDocument.h b/VirtualRobot/XML/mjcf/MjcfDocument.h
deleted file mode 100644
index 6f89d5c7c98c7737c2b6b64d27d0dc015612e86f..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/MjcfDocument.h
+++ /dev/null
@@ -1,204 +0,0 @@
-#pragma once
-
-#include <memory>
-
-#include <Eigen/Eigen>
-
-#include <VirtualRobot/Robot.h>
-#include <VirtualRobot/Util/xml/tinyxml2.h>
-
-#include "utils.h"
-
-
-namespace VirtualRobot
-{
-namespace mjcf
-{
-
-    using XMLElement = tinyxml2::XMLElement;
-
-    /**
-     * @brief A MJCF (Mujoco XML) document.
-     */
-    class Document : public tinyxml2::XMLDocument
-    {
-        
-    public:
-        
-        /// Constructor.
-        Document();
-        
-        
-        /// Set the precision for float comparison (used e.g. when comparing 
-        /// to zero or identity).
-        void setFloatCompPrecision(float value);
-        /// Set the mass set in dummy inertial elements.
-        void setDummyMass(float value);
-        
-        
-        /// Set the name of the Mujoco model.
-        void setModelName(const std::string& name);
-        
-        /**
-         * @brief Set the class attribute of all new applicable elements 
-         * (after calling this method). Pass an empty string to disable class attributes.
-         * @param excludeBody If true (default), the class will not be set on
-         *  new body elements and its children (inertial, joint, ...). 
-         *  They should be the childclass attribute of the robot root body.
-         */
-        void setNewElementClass(const std::string& className, bool excludeBody = true);
-        
-        
-        // Section elements (children of top-level 'mujoco' element).
-        XMLElement* compiler()  { return section("compiler");  }
-        XMLElement* option()    { return section("option");    }
-        XMLElement* size()      { return section("size");      }
-        XMLElement* visual()    { return section("visual");    }
-        XMLElement* statistic() { return section("statistic"); }
-        XMLElement* default_()  { return section("default");   }
-        XMLElement* asset()     { return section("asset");     }
-        XMLElement* worldbody() { return section("worldbody"); }
-        XMLElement* contact()   { return section("contact");   }
-        XMLElement* equality()  { return section("equality");  }
-        XMLElement* tendon()    { return section("tendon");    }
-        XMLElement* actuator()  { return section("actuator");  }
-        XMLElement* sensor()    { return section("sensor");    }
-        XMLElement* keyframe()  { return section("keyframe");  }
-
-        
-        /// Adds a body element to the worldbody with the robot's name as name and childclass.
-        XMLElement* addRobotRootBodyElement(const std::string& robotName);
-        /// Get the (least recently added) robot root body.
-        XMLElement* robotRootBody() const;
-        
-        /// Add a new defaults class with a class name.
-        XMLElement* addDefaultsClass(const std::string& className);
-
-        template <typename AttrT>
-        XMLElement* addDefaultAttr(XMLElement* defaultsClass, const std::string& elementName, 
-                                      const std::string& attrName, const AttrT& attrValue);
-        
-        
-        /// Add a skybox texture asset (only one allowed).
-        XMLElement* addSkyboxTexture(const Eigen::Vector3f& rgb1, const Eigen::Vector3f& rgb2);        
-        
-        /// Add a mocap body with the given name to the worldbody.
-        XMLElement* addMocapBody(const std::string& name, float geomSize);
-        
-        /// Add a body element to a parent from a RobotNode.
-        /// Adds inertial and joint element, if necessary.
-        XMLElement* addBodyElement(XMLElement* parent, RobotNodePtr node);
-        
-        /// Add an inertial element to a body from a RobotNode.
-        XMLElement* addInertialElement(XMLElement* body, RobotNodePtr node);
-        /// Add a dummy inertial element with small mass and identity inertia matrix.
-        XMLElement* addDummyInertial(XMLElement* body, bool first=false);
-        /// Add a joint element to a body from a RobotNode.
-        XMLElement* addJointElement(XMLElement* body, RobotNodePtr node);
-        /// Add a free joint element to a body.
-        XMLElement* addFreeJointElement(XMLElement* body);
-        
-        /// Add a geom to a body, referencing a mesh.
-        XMLElement* addGeomElement(XMLElement* body, const std::string& meshName);
-        /// Add a mesh asset with a name and a file.
-        XMLElement* addMeshElement(const std::string& name, const std::string& file,
-                                const std::string& className = "");
-
-        /// Add a conact/exclude element between the given bodies.
-        XMLElement* addContactExclude(const XMLElement& body1, const XMLElement& body2);
-        /// Add a conact/exclude element between the given bodies.
-        XMLElement* addContactExclude(const std::string& body1Name, const std::string& body2Name);
-        
-        XMLElement* addActuatorMotorElement(const std::string& jointName);
-        XMLElement* addActuatorPositionElement(const std::string& jointName, float kp = 0);
-        XMLElement* addActuatorPositionElement(
-                const std::string& jointName, bool ctrlLimited, const Eigen::Vector2f& ctrlRange, float kp = 0);
-        XMLElement* addActuatorVelocityElement(const std::string& jointName, float kv = 0);
-        
-        XMLElement* addEqualityWeld(const std::string& name, const std::string& body1, const std::string& body2,
-                                    const std::string& className="");
-        
-        /// Set the pos and quat attribute of an element.
-        void setElementPose(XMLElement* elem, const Eigen::Matrix4f& pose);
-        void setElementPos(XMLElement* elem, Eigen::Vector3f pos);
-        void setElementQuat(XMLElement* elem, const Eigen::Quaternionf& quat);
-        
-        /// Set the axis attribute of a joint.
-        void setJointAxis(XMLElement* joint, const Eigen::Vector3f& axis);
-
-        
-        
-    private:
-        
-        /// (ParentTag, ElementTag)
-        using ElementType = std::pair<std::string, std::string>;
-        
-        /// Element types allowing a class attribute.
-        static const std::set<ElementType> ELEM_NAMES_WITH_ATTR_CLASS;
-        
-        /// Return true if the given ElementType allows for a class attribute.
-        static bool allowsClassAttr(const ElementType& type);
-        
-        
-    private:
-        
-        
-        
-        /// Add a new element with a name (tag) to a parent.
-        /// @param className If not empty, set the class attribute of the new element.
-        /// @param first If true, will be inserted as first, otherweise at end (default)
-        XMLElement* addNewElement(XMLElement* parent, const std::string& elemName, 
-                                  const std::string& className = "", bool first = false);
-        
-        /// Return the first child element of parent with the given element name.
-        /// If it does not exist, create it.
-        XMLElement* getOrCreateElement(XMLElement* parent, const std::string& elemName);
-        
-        /// Gets the section element (child of root element) with a name.
-        /// If it does not exist, it is created.
-        XMLElement* section(const std::string& name);
-        
-        XMLElement* addActuatorShortcut(
-                const std::string& type, const std::string& name, const std::string& jointName, 
-                const std::string& paramName = "", float paramValue = 0);
-        
-        
-        /// Precision when comparing floats (e.g. with zero).
-        float floatCompPrecision = 1e-6f;
-        /// Mass used for dummy inertial elements.
-        float dummyMass = 0.0001f;
-        
-        
-        /// The "mujoco" root element.
-        XMLElement* root;
-        
-        /// The wrapper element of the robot.
-        XMLElement* robotRootBody_;
-        
-        
-        /// The class added to new elements, if applicable.
-        std::string newElementClass = "";
-        /// Indicate whether body elements and their children shall be 
-        /// exluded from setting the class attribute.
-        bool newElementClassExcludeBody = true;
-        
-        
-    };
-    
-    template<typename AttrT>
-    XMLElement* Document::addDefaultAttr(
-            XMLElement* defaultsClass, const std::string& elementName, 
-            const std::string& attrName, const AttrT& attrValue)
-    {
-        assertElementIs(defaultsClass, "default");
-        
-        XMLElement* element = getOrCreateElement(defaultsClass, elementName);
-        element->SetAttribute(attrName.c_str(), attrValue);
-        
-        return element;
-    }
-
-    using DocumentPtr = std::unique_ptr<Document>;
-    
-}
-}
diff --git a/VirtualRobot/XML/mjcf/MujocoIO.cpp b/VirtualRobot/XML/mjcf/MujocoIO.cpp
deleted file mode 100644
index 36655017333a07dba7546e84eff09ff9acfd16de..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/MujocoIO.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-#include "MujocoIO.h"
-#include "utils.h"
-
-#include <VirtualRobot/RobotNodeSet.h>
-#include <VirtualRobot/XML/RobotIO.h>
-#include <VirtualRobot/VirtualRobotException.h>
-#include <VirtualRobot/Visualization/TriMeshModel.h>
-
-
-using namespace VirtualRobot;
-using namespace mjcf;
-namespace tx = tinyxml2;
-namespace fs = std::filesystem;
-
-namespace
-{
-    namespace fs = std::filesystem;
-    inline fs::path remove_trailing_separator(fs::path p)
-    {
-        p /= "dummy";
-        return p.parent_path();
-    }
-}
-
-
-MujocoIO::MujocoIO(RobotPtr robot) : robot(robot)
-{
-    THROW_VR_EXCEPTION_IF(!robot, "Given RobotPtr robot is null.");
-}
-
-void MujocoIO::saveMJCF(const std::string& filename, const std::string& basePath,
-                        const std::string& meshRelDir)
-{
-    THROW_VR_EXCEPTION_IF(filename.empty(), "Given filename is empty.");
-
-    setPaths(filename, basePath, meshRelDir);
-
-    document.reset(new mjcf::Document());
-    document->setModelName(robot->getName());
-
-    makeCompiler();
-
-    makeDefaultsGroup();
-    document->setNewElementClass(robot->getName(), true);
-
-    addSkybox();
-
-    if (withMocapBody)
-    {
-        std::cout << "Adding mocap body ..." << std::endl;
-        addMocapBody();
-    }
-
-    std::cout << "Creating bodies structure ..." << std::endl;
-    makeNodeBodies();
-
-    std::cout << "Adding meshes and geoms ..." << std::endl;
-    addNodeBodyMeshes();
-
-    bool print = false;
-    if (print)
-    {
-        std::cout << "===========================" << std::endl
-                  << "Current model: "             << std::endl
-                  << "--------------"              << std::endl;
-        document->Print();
-        std::cout << "===========================" << std::endl;
-    }
-
-    std::cout << "Merging massless bodies ..." << std::endl;
-    masslessBodySanitizer.sanitize();
-
-    std::cout << "Adding contact excludes ..." << std::endl;
-    addContactExcludes();
-
-    std::cout << "Adding actuators ..." << std::endl;
-    addActuators();
-
-    std::cout << "Scaling lengths by " << lengthScaling << " ..." << std::endl;
-    scaleLengths(document->robotRootBody());
-
-    std::cout << "Done." << std::endl;
-
-    if (print)
-    {
-        std::cout << std::endl;
-        std::cout << "===========================" << std::endl
-                  << "Output file: "             << std::endl
-                  << "------------"              << std::endl;
-        document->Print();
-        std::cout << "===========================" << std::endl;
-    }
-
-    assert(!outputFileName.empty());
-    std::cout << "Writing to " << (outputDirectory / outputFileName) << std::endl;
-    document->SaveFile((outputDirectory / outputFileName).c_str());
-}
-
-void MujocoIO::setPaths(const std::string& filename, const std::string& basePath, const std::string& meshRelDir)
-{
-    outputDirectory = basePath;
-    outputFileName = filename;
-    outputMeshRelDirectory = meshRelDir;
-
-    ensureDirectoriesExist();
-}
-
-void MujocoIO::ensureDirectoriesExist()
-{
-    auto ensureDirExists = [](const fs::path & dir, const std::string & errMsgName)
-    {
-        if (!fs::is_directory(dir))
-        {
-            std::cout << "Creating directory: " << dir << std::endl;
-            bool success = fs::create_directories(remove_trailing_separator(dir));
-            THROW_VR_EXCEPTION_IF(!success, "Could not create " << errMsgName << ": " << dir);
-        }
-    };
-
-    ensureDirExists(outputDirectory, "output directory");
-    ensureDirExists(outputMeshDirectory(), "output mesh directory");
-}
-
-void MujocoIO::makeCompiler()
-{
-    document->compiler()->SetAttribute("angle", "radian");
-    document->compiler()->SetAttribute("balanceinertia", "true");
-}
-
-void MujocoIO::makeDefaultsGroup()
-{
-    XMLElement* defaultsClass = document->addDefaultsClass(robot->getName());
-
-    std::stringstream comment;
-    comment << "Add default values for " << robot->getName() << " here.";
-    defaultsClass->InsertFirstChild(document->NewComment(comment.str().c_str()));
-
-    document->addDefaultAttr(defaultsClass, "joint", "frictionloss", 1);
-    document->addDefaultAttr(defaultsClass, "joint", "damping", 0);
-    document->addDefaultAttr(defaultsClass, "geom", "condim", 4);
-    document->addDefaultAttr(defaultsClass, "position", "kp", 1);
-    document->addDefaultAttr(defaultsClass, "velocity", "kv", 1);
-}
-
-
-void MujocoIO::addSkybox()
-{
-    document->addSkyboxTexture(Eigen::Vector3f(.8f, .9f, .95f),
-                               Eigen::Vector3f(.4f, .6f, .8f));
-}
-
-
-void MujocoIO::addMocapBody()
-{
-    std::string className = "mocap";
-    float geomSize = 0.01f;
-
-    std::string bodyName;
-    {
-        std::stringstream ss;
-        ss << robot->getName() << "_Mocap";
-        bodyName = ss.str();
-    }
-
-    // add defaults class
-    XMLElement* defClass = document->addDefaultsClass(className);
-
-    document->addDefaultAttr(defClass, "geom", "rgba",
-                             toAttr(Eigen::Vector4f(.9f, .5f, .5f, .5f)).c_str());
-
-    document->addDefaultAttr(defClass, "equality", "solimp",
-                             toAttr(Eigen::Vector3f{.95f, .99f, .001f}).c_str());
-    document->addDefaultAttr(defClass, "equality", "solref",
-                             toAttr(Eigen::Vector2f{ .02f, 1.f}).c_str());
-
-    // add body
-    XMLElement* mocap = document->addMocapBody(bodyName, geomSize);
-    mocap->SetAttribute("childclass", className.c_str());
-
-    // add equality weld constraint
-    document->addEqualityWeld(bodyName, robot->getName(), bodyName, className);
-}
-
-
-void MujocoIO::makeNodeBodies()
-{
-    nodeBodies.clear();
-
-    RobotNodePtr rootNode = robot->getRootNode();
-    assert(rootNode);
-
-    // add root
-    XMLElement* robotRootBody = document->addRobotRootBodyElement(robot->getName());
-
-    if (withMocapBody)
-    {
-        document->addDummyInertial(robotRootBody);
-        XMLElement* joint = document->addFreeJointElement(robotRootBody);
-        joint->SetAttribute("name", robot->getName().c_str());
-    }
-
-    XMLElement* root = document->addBodyElement(robotRootBody, rootNode);
-    nodeBodies[rootNode->getName()] = root;
-    assert(root);
-
-    for (RobotNodePtr node : robot->getRobotNodes())
-    {
-        addNodeBody(node);
-    }
-}
-
-void MujocoIO::addNodeBodyMeshes()
-{
-    bool meshlabserverAviable = system("which meshlabserver > /dev/null 2>&1") == 0;
-    bool notAvailableReported = false;
-
-    for (RobotNodePtr node : robot->getRobotNodes())
-    {
-        VisualizationNodePtr visualization = node->getVisualization(SceneObject::VisualizationType::Full);
-
-        if (!visualization)
-        {
-            continue;
-        }
-
-        std::cout << t << "Node " << node->getName() << ":\t";
-
-        fs::path srcMeshPath = visualization->getFilename();
-
-        fs::path dstMeshFileName = srcMeshPath.filename();
-        dstMeshFileName.replace_extension("stl");
-        fs::path dstMeshPath = outputMeshDirectory() / dstMeshFileName;
-
-        if (!fs::exists(dstMeshPath))
-        {
-            if (srcMeshPath.extension().string() != "stl")
-            {
-                std::cout << "Converting to .stl: " << srcMeshPath;
-
-                if (!meshlabserverAviable)
-                {
-                    if (!notAvailableReported)
-                    {
-                        std::cout << std::endl
-                                  << "Command 'meshlabserver' not available, "
-                                  "cannot convert meshes." << std::endl;
-                        notAvailableReported = true;
-                    }
-                    continue;
-                }
-
-                // meshlabserver available
-                std::stringstream convertCommand;
-                convertCommand << "meshlabserver"
-                               << " -i " << srcMeshPath
-                               << " -o " << dstMeshPath;
-
-                // run command
-                std::cout << "----------------------------------------------------------" << std::endl;
-                int r = system(convertCommand.str().c_str());
-                std::cout << "----------------------------------------------------------" << std::endl;
-                if (r != 0)
-                {
-                    std::cout << "Command returned with error: " << r << "\n"
-                              << "Command was: " << convertCommand.str() << std::endl;
-                }
-            }
-            else
-            {
-                std::cout << "Copying: " << srcMeshPath << "\n"
-                          << "     to: " << dstMeshPath;
-                fs::copy_file(srcMeshPath, dstMeshPath);
-            }
-        }
-        else
-        {
-            std::cout << "skipping (" << outputMeshRelDirectory / dstMeshFileName
-                      << " already exists)";
-        }
-        std::cout << std::endl;
-
-
-
-        // add asset
-        std::string meshName = node->getName();
-        document->addMeshElement(meshName, fs::absolute(dstMeshPath).string());
-
-        // add geom to body
-        XMLElement* body = nodeBodies[node->getName()];
-        document->addGeomElement(body, meshName);
-    }
-}
-
-
-
-XMLElement* MujocoIO::addNodeBody(RobotNodePtr node)
-{
-    XMLElement* element = nodeBodies[node->getName()];
-    if (element)
-    {
-        // break recursion
-        return element;
-    }
-
-    XMLElement* parent = nodeBodies[node->getParent()->getName()];
-    if (!parent)
-    {
-        parent = addNodeBody(robot->getRobotNode(node->getParent()->getName()));
-    }
-
-    element = document->addBodyElement(parent, node);
-    nodeBodies[node->getName()] = element;
-
-    return element;
-}
-
-struct ParentChildContactExcludeVisitor : public tinyxml2::XMLVisitor
-{
-
-    ParentChildContactExcludeVisitor(Document& document) : document(document) {}
-    ~ParentChildContactExcludeVisitor() override = default;
-
-    bool VisitEnter(const tinyxml2::XMLElement&, const tinyxml2::XMLAttribute*) override;
-
-    Document& document;  ///< The document.
-    bool firstSkipped = false;  ///< Used to skip the root element.
-};
-
-bool ParentChildContactExcludeVisitor::VisitEnter(const tinyxml2::XMLElement& body, const tinyxml2::XMLAttribute*)
-{
-    if (!isElement(body, "body"))
-    {
-        return true;
-    }
-
-    if (!firstSkipped)
-    {
-        firstSkipped = true;
-        return true;
-    }
-
-    const XMLElement* parent = body.Parent()->ToElement();
-    assert(parent);
-
-    document.addContactExclude(*parent, body);
-
-    return true;
-}
-
-
-void MujocoIO::addContactExcludes()
-{
-    RobotNodePtr rootNode = robot->getRootNode();
-
-    std::vector<std::pair<std::string, std::string>> excludePairs;
-
-    for (RobotNodePtr node : robot->getRobotNodes())
-    {
-        for (std::string& ignore : node->getPhysics().ignoreCollisions)
-        {
-            // I found an <IgnoreCollision> element referring to a non-existing node.
-            // => check node existence here
-            if (robot->hasRobotNode(ignore))
-            {
-                excludePairs.push_back({node->getName(), ignore});
-            }
-        }
-    }
-
-    // resolve body names and add exludes
-    for (auto& excludePair : excludePairs)
-    {
-        std::string body1 = masslessBodySanitizer.getMergedBodyName(excludePair.first);
-        std::string body2 = masslessBodySanitizer.getMergedBodyName(excludePair.second);
-        document->addContactExclude(body1, body2);
-    }
-
-    ParentChildContactExcludeVisitor visitor(*document);
-    document->robotRootBody()->Accept(&visitor);
-}
-
-void MujocoIO::addActuators()
-{
-    std::vector<const mjcf::XMLElement*> jointElements = getAllElements("joint");
-
-    for (auto joint : jointElements)
-    {
-        std::string name = joint->Attribute("name");
-        switch (actuatorType)
-        {
-            case ActuatorType::MOTOR:
-                document->addActuatorMotorElement(name);
-                break;
-
-            case ActuatorType::POSITION:
-            {
-                XMLElement* act = document->addActuatorPositionElement(name);
-
-                const char* limited = joint->Attribute("limited");
-                if (limited)
-                {
-                    act->SetAttribute("ctrllimited", limited);
-
-                    const char* range = joint->Attribute("range");
-                    if (range)
-                    {
-                        act->SetAttribute("ctrlrange", range);
-                    }
-                }
-            }
-            break;
-
-            case ActuatorType::VELOCITY:
-                document->addActuatorVelocityElement(name);
-                break;
-        }
-    }
-}
-
-void MujocoIO::scaleLengths(XMLElement* elem)
-{
-    assert(elem);
-
-    if (isElement(elem, "joint"))
-    {
-        if (isAttr(elem, "type", "slide") && hasAttr(elem, "range"))
-        {
-            std::cout << t << "Scaling range of slide joint "
-                      << elem->Attribute("name") << std::endl;
-
-            Eigen::Vector2f range = strToVec2(elem->Attribute("range"));
-            range *= lengthScaling;
-            setAttr(elem, "range", range);
-        }
-    }
-    else if (isElement(elem, "position")
-             //&& isElement(elem.Parent()->ToElement(), "actuator")
-             && hasAttr(elem, "ctrlrange"))
-    {
-        std::cout << t << "Scaling ctrlrange of position actuator "
-                  << elem->Attribute("name") << std::endl;
-
-        Eigen::Vector2f ctrlrange = strToVec2(elem->Attribute("ctrlrange"));
-        ctrlrange *= lengthScaling;
-        setAttr(elem, "ctrlrange", ctrlrange);
-    }
-    else if (hasAttr(elem, "pos"))
-    {
-        std::cout << t << "Scaling pos of " << elem->Value() << " ";
-        if (hasAttr(elem, "name"))
-        {
-            std::cout << "'" << elem->Attribute("name") << "'";
-        }
-        else
-        {
-            std::cout << "element";
-        }
-        std::cout << std::endl;
-
-        Eigen::Vector3f pos = strToVec(elem->Attribute("pos"));
-        pos *= lengthScaling;
-        setAttr(elem, "pos", pos);
-    }
-
-
-    for (XMLElement* child = elem->FirstChildElement();
-         child;
-         child = child->NextSiblingElement())
-    {
-        scaleLengths(child);
-    }
-}
-
-
-struct ListElementsVisitor : public tinyxml2::XMLVisitor
-{
-
-    ListElementsVisitor(const std::string& elementName) : elementName(elementName) {}
-    ~ListElementsVisitor() override = default;
-
-    // XMLVisitor interface
-    bool VisitEnter(const tinyxml2::XMLElement&, const tinyxml2::XMLAttribute*) override;
-
-    const std::vector<const tinyxml2::XMLElement*>& getFoundElements() const;
-
-    std::string elementName;
-    std::vector<const tinyxml2::XMLElement*> foundElements;
-};
-
-bool ListElementsVisitor::VisitEnter(const tinyxml2::XMLElement& elem, const tinyxml2::XMLAttribute*)
-{
-    if (isElement(elem, elementName))
-    {
-        foundElements.push_back(&elem);
-    }
-    return true;
-}
-
-std::vector<const mjcf::XMLElement*> MujocoIO::getAllElements(const std::string& elemName)
-{
-    ListElementsVisitor visitor(elemName);
-    document->worldbody()->Accept(&visitor);
-    return visitor.foundElements;
-}
-
-void MujocoIO::setLengthScaling(float value)
-{
-    lengthScaling = value;
-}
-
-void MujocoIO::setActuatorType(ActuatorType value)
-{
-    actuatorType = value;
-}
-
-void MujocoIO::setWithMocapBody(bool enabled)
-{
-    withMocapBody = enabled;
-}
-
diff --git a/VirtualRobot/XML/mjcf/MujocoIO.h b/VirtualRobot/XML/mjcf/MujocoIO.h
deleted file mode 100644
index 91a83d701c4655204b6aa3eba2b335a40ac44651..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/MujocoIO.h
+++ /dev/null
@@ -1,139 +0,0 @@
-#pragma once
-
-#include <filesystem>
-
-#include <VirtualRobot/Robot.h>
-
-#include "MjcfDocument.h"
-#include "MasslessBodySanitizer.h"
-#include "utils.h"
-
-
-namespace VirtualRobot
-{
-    namespace mjcf
-    {
-
-        class MujocoIO
-        {
-        public:
-
-            /// Constructor.
-            /// @throws VirtualRobotException if robot is null
-            MujocoIO(RobotPtr robot);
-
-            /**
-             * @brief Create a Mujoco XML (MJCF) document for the given robot.
-             * @param filename   the output filename (without directory)
-             * @param basePath   the output directory
-             * @param meshRelDir the directory relative to basePath where meshes shall be placed
-             */
-            void saveMJCF(const std::string& filename, const std::string& basePath,
-                          const std::string& meshRelDir);
-
-
-            /// Set the scaling for lenghts.
-            void setLengthScaling(float value);
-
-            /// Set the actuator type.
-            void setActuatorType(ActuatorType value);
-
-            /**
-             * @brief Enable or disable adding of a mocap body controlling the robot pose.
-             *
-             * @param enabled If true:
-             * - Add a free joint to the robot root body mocap body
-             * - Add a mocap body in the world body (called <RobotName>_Mocap)
-             * - Add a weld constraint welding them together.
-             */
-            void setWithMocapBody(bool enabled);
-
-
-        private:
-
-            /// Set the output path members.
-            void setPaths(const std::string& filename, const std::string& basePath,
-                          const std::string& meshRelDir);
-            /// Create output directories if the do not exist.
-            void ensureDirectoriesExist();
-
-            /// Make the compiler section.
-            void makeCompiler();
-            /// Add a defaults group for the robot.
-            void makeDefaultsGroup();
-            /// Add a skybox texture asset.
-            void addSkybox();
-
-            /// Add a mocap body with defaults group.
-            void addMocapBody();
-
-            /// Construct the body structure corresponding to the robot nodes.
-            void makeNodeBodies();
-            /// Add a body element for a robot node. If its parent does not exist,
-            /// create the parent body first.
-            mjcf::XMLElement* addNodeBody(RobotNodePtr node);
-
-            /// Convert meshes and add mesh assets for robot nodes with visualization.
-            void addNodeBodyMeshes();
-
-            /// Add contact exclude elements for IgnoreCollision elements.
-            void addContactExcludes();
-
-            /// Add actuators for all joints.
-            void addActuators();
-
-            /// Scale all lengths by lengthScaling.
-            void scaleLengths(XMLElement* elem);
-
-            std::vector<const mjcf::XMLElement*> getAllElements(const std::string& elemName);
-
-
-            // Paremeters
-
-            /// Scaling for lengths, such as positions and translations.
-            float lengthScaling = 0.001f;
-            /// The actuator type.
-            ActuatorType actuatorType = ActuatorType::MOTOR;
-
-            /// Add a mocap
-            bool withMocapBody = false;
-
-
-            // Paths
-
-            std::filesystem::path outputDirectory;
-            std::filesystem::path outputFileName;
-            std::filesystem::path outputMeshRelDirectory;
-            std::filesystem::path outputMeshDirectory()
-            {
-                return outputDirectory / outputMeshRelDirectory;
-            }
-
-
-            // Input
-
-            /// The input robot.
-            RobotPtr robot;
-
-
-            // Output
-
-            /// The built MJCF document.
-            DocumentPtr document = nullptr;
-
-
-            // Processing
-
-            /// Sanitizes massless bodies.
-            mjcf::MasslessBodySanitizer masslessBodySanitizer {document, robot};
-
-            /// Map of robot node names to XML elements.
-            std::map<std::string, mjcf::XMLElement*> nodeBodies;
-
-
-            const std::string t = "| ";
-
-        };
-
-    }
-}
diff --git a/VirtualRobot/XML/mjcf/utils.cpp b/VirtualRobot/XML/mjcf/utils.cpp
deleted file mode 100644
index be83738e4487d531078f6a3f2fc881b4e7ed99f2..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/utils.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-#include "utils.h"
-
-#include <algorithm>
-#include <map>
-
-
-namespace VirtualRobot
-{
-namespace mjcf
-{
-
-ActuatorType toActuatorType(std::string str)
-{
-    static const std::map<std::string, ActuatorType> map {
-        {"motor",    ActuatorType::MOTOR},
-        {"position", ActuatorType::POSITION},
-        {"velocity", ActuatorType::VELOCITY}
-    };
-    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
-    return map.at(str);
-}
-
-
-
-bool isElement(const XMLElement* elem, const char* tag)
-{
-    return isElement(*elem, tag);
-}
-
-bool isElement(const XMLElement* elem, const std::string& tag)
-{
-    return isElement(*elem, tag);
-}
-
-bool isElement(const XMLElement& elem, const char* tag)
-{
-    return std::strcmp(elem.Value(), tag) == 0;
-}
-
-bool isElement(const XMLElement& elem, const std::string& tag)
-{
-    return std::strcmp(elem.Value(), tag.c_str()) == 0;
-}
-
-
-bool hasElementChild(const XMLElement* elem, const std::string& elemName)
-{
-    return elem->FirstChildElement(elemName.c_str()) != nullptr;
-}
-
-bool hasMass(const XMLElement* body)
-{
-    assertElementIsBody(body);
-    return hasElementChild(body, "geom") || hasElementChild(body, "inertial");
-}
-
-
-
-std::string toAttr(bool b)
-{
-    static const std::string strings[] = { "false", "true" };
-    return strings[int(b)];
-}
-
-std::string toAttr(const Eigen::Quaternionf& quat)
-{
-    std::stringstream ss;
-    ss << quat.w() << " " << quat.x() << " " << quat.y() << " " << quat.z();
-    return ss.str();
-}
-
-
-Eigen::Vector2f strToVec2(const char* string)
-{
-    Eigen::Vector2f v;
-    sscanf(string, "%f %f", &v(0), &v(1));
-    return v;
-}
-
-Eigen::Vector3f strToVec(const char* string)
-{
-    Eigen::Vector3f v;
-    sscanf(string, "%f %f %f", &v(0), &v(1), &v(2));
-    return v;
-}
-
-Eigen::Quaternionf strToQuat(const char* string)
-{
-    Eigen::Quaternionf q;
-    sscanf(string, "%f %f %f %f", &q.w(), &q.x(), &q.y(), &q.z());
-    return q;
-}
-
-
-std::size_t commonPrefixLength(const std::string& a, const std::string& b)
-{
-    const std::string* smaller = &a;
-    const std::string* bigger = &b;
-    if (b.size() < a.size())
-    {
-        std::swap(smaller, bigger);
-    }
-    
-    auto mismatch = std::mismatch(smaller->begin(), smaller->end(), 
-                                  bigger->begin()).first;
-    return std::size_t(std::distance(smaller->begin(), mismatch));
-}
-
-
-void assertElementIsBody(const XMLElement* elem)
-{
-    assertElementIs(elem, "body");
-}
-
-bool hasAttr(const XMLElement* elem, const std::string& attrName)
-{
-    return hasAttr(*elem, attrName);
-}
-
-bool hasAttr(const XMLElement& elem, const std::string& attrName)
-{
-    return elem.Attribute(attrName.c_str());
-}
-
-bool isAttr(const XMLElement* elem, const std::string& attrName, const std::string& attrValue)
-{
-    return isAttr(*elem, attrName, attrValue);
-}
-
-bool isAttr(const XMLElement& elem, const std::string& attrName, const std::string& attrValue)
-{
-    return hasAttr(elem, attrName) && elem.Attribute(attrName.c_str()) == attrValue;
-}
-
-
-
-
-}
-}
diff --git a/VirtualRobot/XML/mjcf/utils.h b/VirtualRobot/XML/mjcf/utils.h
deleted file mode 100644
index 08e57af0f252f046a4b8c2bcc19a12f7340bac68..0000000000000000000000000000000000000000
--- a/VirtualRobot/XML/mjcf/utils.h
+++ /dev/null
@@ -1,111 +0,0 @@
-#pragma once
-
-#include <VirtualRobot/Util/xml/tinyxml2.h>
-#include <string>
-#include <Eigen/Eigen>
-
-
-namespace VirtualRobot 
-{
-namespace mjcf
-{
-
-enum class ActuatorType
-{
-    MOTOR, POSITION, VELOCITY
-};
-
-ActuatorType toActuatorType(std::string str);
-
-
-using XMLElement = tinyxml2::XMLElement;
-
-
-bool isElement(const XMLElement* elem, const char* tag);
-bool isElement(const XMLElement& elem, const char* tag);
-bool isElement(const XMLElement* elem, const std::string& tag);
-bool isElement(const XMLElement& elem, const std::string& tag);
-
-bool hasElementChild(const XMLElement* elem, const std::string& elemName);
-
-bool hasMass(const XMLElement* body);
-
-
-bool hasAttr(const XMLElement* elem, const std::string& attrName);
-bool hasAttr(const XMLElement& elem, const std::string& attrName);
-bool isAttr(const XMLElement* elem, const std::string& attrName, const std::string& attrValue);
-bool isAttr(const XMLElement& elem, const std::string& attrName, const std::string& attrValue);
-
-template <typename AttrT>
-void setAttr(XMLElement* elem, const std::string& name, const AttrT& value);
-template <typename AttrT>
-void setAttr(XMLElement& elem, const std::string& name, const AttrT& value);
-
-// Convert to MJCF XML attribute format.
-std::string toAttr(bool b);
-template <int dim>
-std::string toAttr(const Eigen::Matrix<float, dim, 1>& v);
-std::string toAttr(const Eigen::Quaternionf& v);
-
-// Convert from MJCF XML attribute.
-Eigen::Vector2f strToVec2(const char* string);
-Eigen::Vector3f strToVec(const char* string);
-Eigen::Quaternionf strToQuat(const char* string);
-
-// Get lenght of common prefix of two strings (was used for mergin body names).
-std::size_t commonPrefixLength(const std::string& a, const std::string& b);
-
-
-// Assert that isElement(elem, tag).
-template <class StringT>
-void assertElementIs(const XMLElement* elem, const StringT tag);
-
-
-// Assert that isElement(elem, "body").
-void assertElementIsBody(const XMLElement* elem);
-
-
-
-
-// DEFINITIONS of templated methods
-
-
-template <int dim>
-std::string toAttr(const Eigen::Matrix<float, dim, 1>& v)
-{
-    static const Eigen::IOFormat iofVector {7, 0, "", " ", "", "", "", ""};
-    
-    std::stringstream ss;
-    ss << v.format(iofVector);
-    return ss.str();
-}
-
-template <typename AttrT>
-void setAttr(XMLElement* elem, const std::string& name, const AttrT& value)
-{
-    setAttr(*elem, name, value);
-}
-
-template <typename AttrT>
-void setAttr(XMLElement& elem, const std::string& name, const AttrT& value)
-{
-    elem.SetAttribute(name.c_str(), toAttr(value).c_str());
-}
-
-template <class StringT>
-void assertElementIs(const XMLElement*
-                     #ifndef NDEBUG
-                     elem
-                     #endif
-                     , const StringT
-                     #ifndef NDEBUG
-                     tag
-                     #endif
-                     )
-{
-    assert(isElement(elem, tag));
-}
-
-}
-}
-
diff --git a/VirtualRobot/XML/mujoco/MasslessBodySanitizer.cpp b/VirtualRobot/XML/mujoco/MasslessBodySanitizer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf13eda4799ec49b3aaf783a5cce6ff6d3c0fc80
--- /dev/null
+++ b/VirtualRobot/XML/mujoco/MasslessBodySanitizer.cpp
@@ -0,0 +1,227 @@
+#include "MasslessBodySanitizer.h"
+
+#include <boost/algorithm/string/join.hpp>
+
+#include <VirtualRobot/Robot.h>
+#include <VirtualRobot/math/Helpers.h>
+
+
+namespace VirtualRobot::mujoco
+{
+
+using namespace mjcf;
+
+MasslessBodySanitizer::MasslessBodySanitizer(RobotPtr& robot) :
+    robot(robot)
+{}
+
+void MasslessBodySanitizer::sanitize(Body root)
+{
+    // merge body leaf nodes with parent if they do not have a mass (inertial or geom)
+    
+    for (Body body = root.firstChild<Body>();
+         body; body = body.nextSiblingElement<Body>())
+    {
+        sanitizeRecursion(body);
+    }
+}
+
+
+void MasslessBodySanitizer::sanitizeRecursion(mjcf::Body body)
+{
+    RobotNodePtr bodyNode = robot->getRobotNode(body.name);
+    Eigen::Matrix4f accChildPose = Eigen::Matrix4f::Identity();
+    
+    while (!body.hasMass())
+    {
+        std::cout << t << body.name << ": \t";
+        
+        if (!body.hasChild<Body>())
+        {
+            // leaf => end of recursion
+            sanitizeLeafBody(body);
+            return;
+        }
+        
+        // non-leaf body
+        // check whether there is only one child body
+        Body childBody = body.firstChild<Body>();
+        if (!childBody.nextSiblingElement<Body>())
+        {
+            mergeBodies(body, childBody, accChildPose);
+        }
+        else
+        {
+            std::cout << "Adding dummy inertial to massless body with >1 child bodies." << std::endl;
+            // add a small mass
+            body.addDummyInertial();
+            break;
+        }
+    }
+    
+    // recursive descend
+    for (Body child = body.firstChild<Body>();
+         child; child = child.nextSiblingElement<Body>())
+    {
+        sanitizeRecursion(child);
+    }
+}
+
+static void updatePos(AnyElement element, const Eigen::Matrix4f& accChildPose)
+{
+    const Eigen::Vector3f pos = element.getAttribute<Eigen::Vector3f>("pos", Eigen::Vector3f::Zero());
+    element.setAttribute("pos", math::Helpers::TransformPosition(accChildPose, pos));
+}
+
+static void updateOri(AnyElement element, const Eigen::Matrix3f& accChildOri)
+{
+    if (element.is<Joint>())
+    {
+        Joint joint = element.as<Joint>();
+        joint.axis = accChildOri * joint.axis.get();
+    }
+    else if (element.is<Light>())
+    {
+        Light light = element.as<Light>();
+        light.dir = accChildOri * light.dir.get();
+    }
+    else
+    {
+        const Eigen::Quaternionf quat = 
+                element.getAttribute<Eigen::Quaternionf>("quat", Eigen::Quaternionf::Identity());
+        element.setAttribute("quat", Eigen::Quaternionf(accChildOri * quat));
+    }
+}
+
+void copyChildren(Body body, Body child, const Eigen::Matrix4f& childPose)
+{
+    // merge childBody into body => move all its elements here
+    // while doing this, apply accChildPose to elements
+    for (AnyElement grandChild = child.firstChild<AnyElement>();
+         grandChild; grandChild = grandChild.template nextSiblingElement<AnyElement>())
+    {
+        // clone grandchild
+        AnyElement elem = grandChild.deepClone();
+        
+        if (elem)
+        {
+            /* Adapt pose/axis elements in child. Their poses/axes will be
+             * relative to body's frame, so the transformation from body
+             * to child will be lost. Therefore, apply accChildPose to
+             * their poses/axes. */
+            
+            updatePos(elem, childPose);
+            updateOri(elem, math::Helpers::Orientation(childPose));
+        }
+        
+        // insert to body
+        body.insertEndChild(elem);
+    }
+}
+
+
+
+void MasslessBodySanitizer::mergeBodies(Body body, Body childBody, Eigen::Matrix4f& accChildPose)
+{
+    std::cout << "Merging with '" << childBody.name << "' " << std::endl;
+
+    RobotNodePtr childNode = robot->getRobotNode(childBody.name);
+    Eigen::Matrix4f childPose = childNode->getTransformationFrom(childNode->getParent());
+    
+    // update accumulated child pose
+    // merged child's frame w.r.t. body's frame
+    accChildPose = childPose * accChildPose;
+    
+    // merge childBody into body => move all its elements here
+    // while doing this, apply accChildPose to elements
+    copyChildren(body, childBody, accChildPose);
+    
+    // update body name
+    MergedBodySet& bodySet = getMergedBodySetWith(body.name);
+    bodySet.addBody(childBody.name);
+    body.name = bodySet.getMergedBodyName();
+    
+    std::cout << t << "\t(new name: '" << bodySet.getMergedBodyName() << "')" << std::endl;
+    
+    // delete child
+    body.deleteChild(childBody);
+}
+
+
+void MasslessBodySanitizer::sanitizeLeafBody(Body body)
+{
+    VR_ASSERT_MESSAGE(!body.hasChild<Body>(), "Leaf body must not have a child body.");
+    VR_ASSERT_MESSAGE(!body.hasMass(), "Leaf body must not have mass.");
+    
+    if (!body.hasChildren()) // is completely empty?
+    {
+        // leaf without geom: make it a site
+        std::cout << "Changing to site." << std::endl;
+        body.transform<Site>();
+    }
+    else
+    {
+        // add a small mass
+        std::cout << "Adding dummy inertial to massless leaf body with children." << std::endl;
+        body.addDummyInertial();
+    }
+}
+
+const std::vector<MergedBodySet>& MasslessBodySanitizer::getMergedBodySets() const
+{
+    return mergedBodySets;
+}
+
+const std::string& MasslessBodySanitizer::getMergedBodyName(const std::string& originalBodyName)
+{
+    return getMergedBodySetWith(originalBodyName).getMergedBodyName();
+}
+
+MergedBodySet&MasslessBodySanitizer::getMergedBodySetWith(const std::string& bodyName)
+{
+    for (auto& set : mergedBodySets)
+    {
+        if (set.containsBody(bodyName))
+        {
+           return set;
+        }
+    }
+    
+    // not found => add
+    mergedBodySets.push_back(MergedBodySet(bodyName));
+    
+    return mergedBodySets.back();
+}
+
+
+MergedBodySet::MergedBodySet()
+= default;
+
+MergedBodySet::MergedBodySet(const std::string& bodyName)
+{
+    addBody(bodyName);
+}
+
+void MergedBodySet::addBody(const std::string& bodyName)
+{
+    originalBodyNames.push_back(bodyName);
+    updateMergedBodyName();
+}
+
+bool MergedBodySet::containsBody(const std::string& bodyName) const
+{
+    return std::find(originalBodyNames.begin(), originalBodyNames.end(),
+                     bodyName) != originalBodyNames.end();
+}
+
+const std::string& MergedBodySet::getMergedBodyName() const
+{
+    return mergedBodyName;
+}
+
+void MergedBodySet::updateMergedBodyName()
+{
+    mergedBodyName = boost::algorithm::join(originalBodyNames, "~");
+}
+
+}
diff --git a/VirtualRobot/XML/mjcf/MasslessBodySanitizer.h b/VirtualRobot/XML/mujoco/MasslessBodySanitizer.h
similarity index 60%
rename from VirtualRobot/XML/mjcf/MasslessBodySanitizer.h
rename to VirtualRobot/XML/mujoco/MasslessBodySanitizer.h
index d3bef857d759621187c48c273d88a313078514a0..25f1f327d2ddfa93e7322115021f65bbf73faabd 100644
--- a/VirtualRobot/XML/mjcf/MasslessBodySanitizer.h
+++ b/VirtualRobot/XML/mujoco/MasslessBodySanitizer.h
@@ -1,11 +1,12 @@
 #pragma once
 
-#include "MjcfDocument.h"
+#include <VirtualRobot/Robot.h>
+#include <VirtualRobot/MJCF/Document.h>
 
 
 namespace VirtualRobot
 {
-namespace mjcf 
+namespace mujoco
 {
 
     class MergedBodySet
@@ -35,9 +36,9 @@ namespace mjcf
     {
     public:
         
-        MasslessBodySanitizer(DocumentPtr& document, RobotPtr& robot);
+        MasslessBodySanitizer(RobotPtr& robot);
         
-        void sanitize();
+        void sanitize(mjcf::Body root);
         
         const std::vector<MergedBodySet>& getMergedBodySets() const;
 
@@ -48,22 +49,14 @@ namespace mjcf
         
     private:
         
-        void sanitizeRecursion(mjcf::XMLElement* body);
-        void sanitizeLeafBody(mjcf::XMLElement* body);
-        
-        void mergeBodies(XMLElement* body, XMLElement* childBody, Eigen::Matrix4f& accChildPose);
-        
-        void updateChildPos(XMLElement* elem, const Eigen::Matrix4f& accChildPose);
-        void updateChildQuat(XMLElement* elem, const Eigen::Matrix3f& accChildOri);
-        void updateChildAxis(XMLElement* elem, const Eigen::Matrix3f& accChildOri, 
-                             const char* attrName = "axis");
-        
+        void sanitizeRecursion(mjcf::Body body);
+        void sanitizeLeafBody(mjcf::Body body);
         
+        void mergeBodies(mjcf::Body body, mjcf::Body childBody, Eigen::Matrix4f& accChildPose);
         
         const std::string t = "| ";
         
         
-        DocumentPtr& document;
         RobotPtr& robot;
         
         std::vector<MergedBodySet> mergedBodySets;
diff --git a/VirtualRobot/XML/mujoco/MujocoIO.cpp b/VirtualRobot/XML/mujoco/MujocoIO.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..83aeb56977c0d99a27a0b031392460e7e02f4e88
--- /dev/null
+++ b/VirtualRobot/XML/mujoco/MujocoIO.cpp
@@ -0,0 +1,684 @@
+#include "MujocoIO.h"
+
+#include <VirtualRobot/RobotNodeSet.h>
+#include <VirtualRobot/VirtualRobotException.h>
+
+#include <VirtualRobot/MJCF/visitors/Collector.h>
+#include <VirtualRobot/Nodes/RobotNodePrismatic.h>
+#include <VirtualRobot/Nodes/RobotNodeRevolute.h>
+#include <VirtualRobot/Visualization/TriMeshModel.h>
+#include <VirtualRobot/XML/RobotIO.h>
+
+
+namespace fs = std::filesystem;
+
+
+namespace
+{
+    namespace fs = std::filesystem;
+    inline fs::path removeTrailingSeparator(fs::path p)
+    {
+        p /= "dummy";
+        return p.parent_path();
+    }
+}
+
+
+
+namespace VirtualRobot::mujoco
+{
+
+ActuatorType toActuatorType(const std::string& string)
+{
+    static const std::map<std::string, ActuatorType> map
+    {
+        {"motor",    ActuatorType::MOTOR},
+        {"position", ActuatorType::POSITION},
+        {"velocity", ActuatorType::VELOCITY}
+    };
+    std::string lower = string;
+    std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+    return map.at(lower);
+}
+
+
+MujocoIO::MujocoIO(RobotPtr robot) : robot(robot) 
+{
+    THROW_VR_EXCEPTION_IF(!robot, "Given RobotPtr robot is null.");
+}
+
+void MujocoIO::saveMJCF(const std::string& filename, const std::string& basePath, 
+                        const std::string& meshRelDir)
+{
+    THROW_VR_EXCEPTION_IF(filename.empty(), "Given filename is empty.");
+    
+    setPaths(filename, basePath, meshRelDir);
+    
+    document.reset(new mjcf::Document());
+    document->setModelName(robot->getName());
+    
+    makeCompiler();
+    
+    makeDefaultsClass();
+    document->setNewElementClass(robot->getName(), true);
+    
+    addSkybox();
+    
+    mjcf::Body mocapBody;
+    if (withMocapBody)
+    {
+        std::cout << "Adding mocap body ..." << std::endl;
+        mocapBody = addMocapBody();
+    }
+    
+    std::cout << "Creating bodies structure ..." << std::endl;
+    makeNodeBodies();
+    
+    std::cout << "Adding meshes and geoms ..." << std::endl;
+    addNodeBodyMeshes();
+    
+    if (verbose)
+    {
+        std::cout << "===========================" << std::endl
+                  << "Current model: "             << std::endl
+                  << "--------------"              << std::endl;
+        std::cout << *document;
+        std::cout << "===========================" << std::endl;
+    }
+    
+    std::cout << "Merging massless bodies ..." << std::endl;
+    masslessBodySanitizer.sanitize(robotRoot);
+    
+    std::cout << "Adding contact excludes ..." << std::endl;
+    addContactExcludes();
+
+    if (withMocapBody)
+    {
+        std::cout << "Adding mocap body contact excludes ..." << std::endl;
+        addMocapContactExcludes(mocapBody);
+    }
+    
+    std::cout << "Adding actuators ..." << std::endl;
+    addActuators();
+    
+    // this is now done directly when constructing the respective elements
+    //std::cout << "Scaling lengths by " << lengthScale << " ..." << std::endl;
+    //scaleLengths(robotRoot);
+    
+    std::cout << "Done." << std::endl;
+    
+    if (verbose)
+    {
+        std::cout << std::endl;
+        std::cout << "===========================" << std::endl
+                  << "Output file: "             << std::endl
+                  << "------------"              << std::endl;
+        std::cout << *document;
+        std::cout << "===========================" << std::endl;
+    }
+    
+    assert(!outputFileName.empty());
+    std::cout << "Writing to " << (outputDirectory / outputFileName) << std::endl;
+    document->saveFile((outputDirectory / outputFileName).string());
+}
+
+void MujocoIO::setUseRelativePaths(bool useRelative)
+{
+    this->useRelativePaths = useRelative;
+}
+
+void MujocoIO::setPaths(const std::string& filename, const std::string& basePath, const std::string& meshRelDir)
+{
+    outputDirectory = basePath;
+    outputFileName = filename;
+    outputMeshRelDirectory = meshRelDir;
+    
+    ensureDirectoriesExist();
+}
+
+void MujocoIO::ensureDirectoriesExist()
+{
+    auto ensureDirExists = [](const fs::path& dir, const std::string& errMsgName)
+    {
+        if (!fs::is_directory(dir))
+        {
+            std::cout << "Creating directory: " << dir << std::endl;
+            bool success = fs::create_directories(removeTrailingSeparator(dir));
+            THROW_VR_EXCEPTION_IF(!success, "Could not create " << errMsgName << ": " << dir);
+        }
+    };
+
+    ensureDirExists(outputDirectory, "output directory");
+    ensureDirExists(outputMeshDirectory(), "output mesh directory");
+}
+
+void MujocoIO::makeCompiler()
+{
+    document->compiler().angle = "radian";
+    document->compiler().balanceinertia = true;
+}
+
+void MujocoIO::makeDefaultsClass()
+{
+    mjcf::DefaultClass defaultsClass = document->default_().addClass(robot->getName());
+    
+    defaultsClass.insertComment("Add default values for " + robot->getName() + " here.", true);
+    
+    mjcf::Joint joint = defaultsClass.getElement<mjcf::Joint>();
+    joint.frictionloss = 1;
+    joint.damping = 0;
+    
+    mjcf::Mesh mesh = defaultsClass.getElement<mjcf::Mesh>();
+    mesh.scale = Eigen::Vector3f::Constant(meshScale);
+    
+    mjcf::Geom geom = defaultsClass.getElement<mjcf::Geom>();
+    geom.condim = 4;
+    
+    mjcf::ActuatorPosition actPos = defaultsClass.getElement<mjcf::ActuatorPosition>();
+    actPos.kp = 1;
+    
+    mjcf::ActuatorVelocity actVel = defaultsClass.getElement<mjcf::ActuatorVelocity >();
+    actVel.kv = 1;
+}
+
+
+void MujocoIO::addSkybox()
+{
+    document->asset().addSkyboxTexture(Eigen::Vector3f(.8f, .9f, .95f), 
+                                       Eigen::Vector3f(.4f, .6f, .8f));
+}
+
+
+mjcf::Body MujocoIO::addMocapBody()
+{
+    const std::string className = "mocap";
+    const float geomSize = 0.01f;
+    
+    std::string bodyName;
+    {
+        std::stringstream ss;
+        ss << robot->getName() << "_Mocap";
+        bodyName = ss.str();
+    }
+    
+    // add defaults class
+    mjcf::DefaultClass defaultClass = document->default_().getClass(className);
+    
+    mjcf::Geom geom = defaultClass.getElement<mjcf::Geom>();
+    geom.rgba = Eigen::Vector4f(.9f, .5f, .5f, .5f);
+    
+    {
+        mjcf::EqualityDefaults equality = defaultClass.getElement<mjcf::EqualityDefaults>();
+        Eigen::Vector5f solimp = equality.solimp;
+        solimp(1) = 0.99f;
+        equality.solimp = solimp;
+        //equality.solref = Eigen::Vector2f(.02f, 1.f);
+    }
+    
+    // add body
+    mjcf::Body mocap = document->worldbody().addMocapBody(bodyName, geomSize);
+    mocap.childclass = className;
+    
+    // add equality weld constraint
+    mjcf::EqualityWeld weld = document->equality().addWeld(bodyName, robot->getName(), bodyName);
+    weld.class_ = className;
+    
+    document->contact().addExclude(mocap.name, robot->getName());
+    
+    return mocap;
+}
+
+
+void MujocoIO::makeNodeBodies()
+{
+    nodeBodies.clear();
+    
+    RobotNodePtr rootNode = robot->getRootNode();
+    assert(rootNode);
+    
+    // add root
+    robotRoot = document->worldbody().addBody(robot->getName(), robot->getName());
+    
+    if (withMocapBody)
+    {
+        robotRoot.addDummyInertial();
+        mjcf::FreeJoint joint = robotRoot.addFreeJoint();
+        joint.name = robot->getName();
+    }
+    
+    mjcf::Body root = addNodeBody(robotRoot, rootNode);
+    nodeBodies[rootNode->getName()] = root;
+    assert(root);
+    
+    for (RobotNodePtr node : robot->getRobotNodes())
+    {
+        addNodeBody(node);
+    }
+}
+
+mjcf::Body MujocoIO::addNodeBody(mjcf::Body parent, RobotNodePtr node)
+{
+    mjcf::Body body = parent.addBody(node->getName());
+
+    if (node->hasParent())
+    {
+        Eigen::Matrix4f pose = node->getTransformationFrom(node->getParent());
+        math::Helpers::ScaleTranslation(pose, lengthScale);
+        body.setPose(pose);
+    }
+    
+    if (node->isRotationalJoint() || node->isTranslationalJoint())
+    {
+        addNodeJoint(body, node);
+    }
+    
+    addNodeInertial(body, node);
+    
+    return body;
+}
+
+mjcf::Joint MujocoIO::addNodeJoint(mjcf::Body body, RobotNodePtr node)
+{
+    assert(node->isRotationalJoint() xor node->isTranslationalJoint());
+    
+    mjcf::Joint joint = body.addJoint();
+    joint.name = node->getName();
+    
+    // get the axis
+    Eigen::Vector3f axis;
+    if (node->isRotationalJoint())
+    {
+        RobotNodeRevolutePtr revolute = boost::dynamic_pointer_cast<RobotNodeRevolute>(node);
+        assert(revolute);
+        axis = revolute->getJointRotationAxisInJointCoordSystem();
+    }
+    else if (node->isTranslationalJoint())
+    {
+        RobotNodePrismaticPtr prismatic = boost::dynamic_pointer_cast<RobotNodePrismatic>(node);
+        assert(prismatic);
+        axis = prismatic->getJointTranslationDirectionJointCoordSystem();
+    }
+    
+    joint.type = node->isRotationalJoint() ? "hinge" : "slide";
+    joint.axis = axis;
+    joint.limited = !node->isLimitless();
+    
+    if (!node->isLimitless())
+    {
+        Eigen::Vector2f range = { node->getJointLimitLow(), node->getJointLimitHigh() };
+        if (node->isTranslationalJoint())
+        {
+            range *= lengthScale;
+        }
+        joint.range = range;
+    }
+    
+    return joint;
+}
+
+mjcf::Inertial MujocoIO::addNodeInertial(mjcf::Body body, RobotNodePtr node)
+{
+    const Eigen::Matrix3f matrix = node->getInertiaMatrix();
+    if (matrix.isIdentity(document->getFloatCompPrecision()) 
+        && node->getMass() < document->getFloatCompPrecision())
+    {
+        // dont set an inertial element and let it be derived automatically
+        return { };
+    }
+    
+    mjcf::Inertial inertial = body.addInertial();
+    inertial.pos = node->getCoMLocal() * lengthScale;
+    inertial.mass = node->getMass() * massScale;
+    inertial.inertiaFromMatrix(matrix);
+    
+    return inertial;
+}
+
+void MujocoIO::addNodeBodyMeshes()
+{
+    bool meshlabserverAviable = system("which meshlabserver > /dev/null 2>&1") == 0;
+    bool notAvailableReported = false;
+    
+    for (RobotNodePtr node : robot->getRobotNodes())
+    {
+        VisualizationNodePtr visualization = node->getVisualization(SceneObject::VisualizationType::Full);
+        
+        if (!visualization)
+        {
+            continue;
+        }
+        
+        std::cout << t << "Node " << node->getName() << ":\t";
+        
+        const fs::path srcMeshPath = visualization->getFilename();
+        
+        fs::path dstMeshFileName = srcMeshPath.filename();
+        dstMeshFileName.replace_extension("stl");
+        const fs::path dstMeshPath = outputMeshDirectory() / dstMeshFileName;
+        
+        if (!fs::exists(dstMeshPath))
+        {
+            if (srcMeshPath.extension().string() != ".stl")
+            {
+                std::cout << "Converting to .stl: " << srcMeshPath << std::endl;
+                
+                if (!meshlabserverAviable)
+                {
+                    if (!notAvailableReported)
+                    {
+                        std::cout << std::endl 
+                                  << "Command 'meshlabserver' not available, "
+                                     "cannot convert meshes." << std::endl;
+                        notAvailableReported = true;
+                    }
+                    continue;
+                }
+                
+                // meshlabserver available
+                std::stringstream convertCommand;
+                convertCommand << "meshlabserver"
+                               << " -i " << srcMeshPath 
+                               << " -o " << dstMeshPath;
+                
+                // run command
+                std::cout << "----------------------------------------------------------" << std::endl;
+                std::cout << "Running command: " << convertCommand.str() << std::endl;
+                int r = system(convertCommand.str().c_str());
+                std::cout << "----------------------------------------------------------" << std::endl;
+                if (r != 0)
+                {
+                    std::cout << "Command returned with error: " << r << "\n"
+                              << "Command was: " << convertCommand.str() << std::endl;
+                }
+            }
+            else
+            {
+                std::cout << "Copying: " << srcMeshPath << "\n"
+                          << "     to: " << dstMeshPath;
+                fs::copy_file(srcMeshPath, dstMeshPath);
+            }
+        }
+        else
+        {
+            std::cout << "skipping (" << outputMeshRelDirectory / dstMeshFileName 
+                      << " already exists)";
+        }
+        std::cout << std::endl;
+        
+        
+        
+        // add asset
+        const std::string meshName = node->getName();
+        const fs::path meshPath = useRelativePaths 
+                ? outputMeshRelDirectory / dstMeshFileName
+                : fs::absolute(dstMeshPath);
+        
+        document->asset().addMesh(meshName, meshPath.string());
+        
+        // add geom to body
+        mjcf::Body& body = nodeBodies.at(node->getName());
+        mjcf::Geom geom = body.addGeomMesh(meshName);
+        geom.name = node->getName();
+    }
+}
+
+
+
+mjcf::Body MujocoIO::addNodeBody(RobotNodePtr node)
+{
+    // see whether body for the node already exists
+    auto find = nodeBodies.find(node->getName());
+    if (find != nodeBodies.end())
+    {
+        // exists => break recursion
+        return find->second;
+    }
+    
+    // check whether body exists for parent node
+    mjcf::Body parent;
+    find = nodeBodies.find(node->getParent()->getName());
+    if (find == nodeBodies.end())
+    {
+        // parent does not exist => create it first
+        parent = addNodeBody(robot->getRobotNode(node->getParent()->getName()));
+    }
+    else
+    {
+        // parent exists
+        parent = find->second;
+    }
+    
+    // add body as child of parent
+    mjcf::Body body = addNodeBody(parent, node);
+    nodeBodies[node->getName()] = body;
+
+    return body;
+}
+
+struct ParentChildContactExcludeVisitor : public mjcf::Visitor
+{
+    ParentChildContactExcludeVisitor(mjcf::Document& document) : mjcf::Visitor (document)
+    {}
+    virtual ~ParentChildContactExcludeVisitor() override = default;
+
+    //bool VisitEnter(const tinyxml2::XMLElement&, const tinyxml2::XMLAttribute*) override;
+    bool visitEnter(const mjcf::AnyElement& element) override;
+    
+    std::vector<std::pair<std::string, std::string>> excludePairs;
+    bool firstSkipped = false;  ///< Used to skip the root element.
+};
+
+bool ParentChildContactExcludeVisitor::visitEnter(const mjcf::AnyElement& element)
+{
+    if (!element.is<mjcf::Body>())
+    {
+        return true;
+    }
+    
+    const mjcf::Body body = element.as<mjcf::Body>();
+    
+    if (!firstSkipped)
+    {
+        firstSkipped = true;
+        return true;
+    }
+    
+    const mjcf::Body parent = body.parent<mjcf::Body>();
+    assert(parent);
+    excludePairs.emplace_back(parent.name.get(), body.name.get());
+    
+    return true;
+}
+
+
+void MujocoIO::addContactExcludes()
+{
+    RobotNodePtr rootNode = robot->getRootNode();
+    
+    std::vector<std::pair<std::string, std::string>> excludePairs;
+    
+    for (RobotNodePtr node : robot->getRobotNodes())
+    {
+        for (std::string& ignore : node->getPhysics().ignoreCollisions)
+        {
+            // I found an <IgnoreCollision> element referring to a non-existing node.
+            // => check node existence here
+            if (robot->hasRobotNode(ignore))
+            {
+                excludePairs.push_back({node->getName(), ignore});
+            }
+        }
+    }
+    
+    // resolve body names and add exludes
+    for (const auto& excludePair : excludePairs)
+    {
+        const std::string body1 = masslessBodySanitizer.getMergedBodyName(excludePair.first);
+        const std::string body2 = masslessBodySanitizer.getMergedBodyName(excludePair.second);
+        document->contact().addExclude(body1, body2);
+    }
+    
+    // Add excludes between parent and child elemenets. 
+    // This should actually not be necessary?
+    ParentChildContactExcludeVisitor visitor(*document);
+    robotRoot.accept(visitor);
+    for (const auto& excludePair : visitor.excludePairs)
+    {
+        document->contact().addExclude(excludePair.first, excludePair.second);
+    }
+}
+
+void MujocoIO::addMocapContactExcludes(mjcf::Body mocap)
+{
+    if (!mocap)
+    {
+        throw std::invalid_argument("Passed uninitialized mocap body to " + std::string(__FUNCTION__) + "()");
+    }
+    for (const auto& nodeBody : nodeBodies)
+    {
+        document->contact().addExclude(mocap, nodeBody.second);
+    }
+}
+
+void MujocoIO::addActuators()
+{
+    const std::vector<mjcf::Joint> jointElements = mjcf::Collector<mjcf::Joint>::collect(
+                *document, document->worldbody());
+    
+    for (const auto& joint : jointElements)
+    {
+        mjcf::AnyElement actuator;
+        
+        const std::string jointName = joint.name;
+        switch (actuatorType)
+        {
+            case ActuatorType::MOTOR:
+            {
+                mjcf::ActuatorMotor act = document->actuator().addMotor(jointName);
+                actuator = act;
+                break;
+            }
+                
+            case ActuatorType::POSITION:
+            {
+                mjcf::ActuatorPosition act = document->actuator().addPosition(jointName);
+                actuator = act;
+                
+                if (joint.limited)
+                {
+                    act.ctrllimited = joint.limited;
+                    act.ctrlrange = joint.range;
+                }
+            }
+                break;
+                
+            case ActuatorType::VELOCITY:
+                actuator = document->actuator().addVelocity(jointName);
+                break;
+        }
+        
+        std::stringstream actuatorName;
+        actuatorName << joint.name;
+        if (addActuatorTypeSuffix)
+        {
+            actuatorName << actuatorTypeSuffixes.at(actuatorType);
+        }
+        actuator.setAttribute("name", actuatorName.str());
+    }
+}
+
+void MujocoIO::scaleLengths(mjcf::AnyElement element)
+{
+    assert(elem);
+    if (verbose)
+    {
+        std::cout << "Traversing element " << element.actualTag() << std::endl;
+    }
+    
+    if (element.is<mjcf::Joint>())
+    {
+        mjcf::Joint joint = element.as<mjcf::Joint>();
+        
+        if (joint.type == "slide" && joint.range.isSet())
+        {
+            std::cout << t << "Scaling range of slide joint '" << joint.name << "'" << std::endl;
+            joint.range = joint.range.get() * lengthScale;
+        }
+    }
+    else if (element.is<mjcf::ActuatorPosition>())
+    {
+        mjcf::ActuatorPosition act = element.as<mjcf::ActuatorPosition>();
+        if (act.ctrlrange.isSet())
+        {
+            std::cout << t << "Scaling ctrlrange of position actuator '" << act.name << "'" << std::endl;
+            act.ctrlrange = act.ctrlrange.get() * lengthScale;
+        }
+    }
+    else if (element.isAttributeSet("pos"))
+    {
+        std::cout << t << "Scaling pos of " << element.actualTag() << " ";
+        if (element.isAttributeSet("name"))
+        {
+            std::cout << "'" << element.getAttribute("name") << "'";
+        }
+        else
+        {
+            std::cout << "element";
+        }
+        std::cout << std::endl;
+        
+        Eigen::Vector3f pos = element.getAttribute<Eigen::Vector3f>("pos");
+        pos *= lengthScale;
+        element.setAttribute("pos", pos);
+    }
+    
+    for (mjcf::AnyElement child = element.firstChild<mjcf::AnyElement>();
+         child; child = child.nextSiblingElement<mjcf::AnyElement>())
+    {
+        scaleLengths(child);
+    }
+}
+
+void MujocoIO::setLengthScale(float value)
+{
+    this->lengthScale = value;
+}
+
+void MujocoIO::setMeshScale(float value)
+{
+    this->meshScale = value;
+}
+
+void MujocoIO::setMassScale(float value)
+{
+    this->massScale = value;
+}
+
+void MujocoIO::setActuatorType(ActuatorType value)
+{
+    this->actuatorType = value;
+}
+
+void MujocoIO::setAddActuatorTypeSuffix(bool enable)
+{
+    this->addActuatorTypeSuffix = enable;
+}
+
+void MujocoIO::setActuatorTypeSuffixes(const std::map<ActuatorType, std::string>& suffixes)
+{
+    this->actuatorTypeSuffixes = suffixes;
+}
+
+void MujocoIO::setWithMocapBody(bool enabled)
+{
+    this->withMocapBody = enabled;
+}
+
+void MujocoIO::setVerbose(bool value)
+{
+    this->verbose = value;
+}
+
+
+
+}
diff --git a/VirtualRobot/XML/mujoco/MujocoIO.h b/VirtualRobot/XML/mujoco/MujocoIO.h
new file mode 100644
index 0000000000000000000000000000000000000000..98a040421cd9a0966613e97d4fd08122416434d8
--- /dev/null
+++ b/VirtualRobot/XML/mujoco/MujocoIO.h
@@ -0,0 +1,186 @@
+#pragma once
+
+#include <filesystem>
+
+#include <VirtualRobot/Robot.h>
+#include <VirtualRobot/MJCF/Document.h>
+
+#include "MasslessBodySanitizer.h"
+
+
+namespace VirtualRobot
+{
+
+namespace mujoco
+{
+
+    enum class ActuatorType
+    {
+        MOTOR, POSITION, VELOCITY
+    };
+    ActuatorType toActuatorType(const std::string& string);
+    
+
+    class MujocoIO
+    {
+    public:
+        
+        /// Constructor.
+        /// @throws VirtualRobotException if robot is null
+        MujocoIO(RobotPtr robot);
+        
+        /**
+         * @brief Create a Mujoco XML (MJCF) document for the given robot.
+         * @param filename   the output filename (without directory)
+         * @param basePath   the output directory
+         * @param meshRelDir the directory relative to basePath where meshes shall be placed
+         */
+        void saveMJCF(const std::string& filename, const std::string& basePath, 
+                      const std::string& meshRelDir);
+        
+        
+        /// Set whether paths (e.g. meshes) shall be relative instead of absolute.
+        /// This can cause problems when including the generated model from another directory.
+        void setUseRelativePaths(bool useRelative);
+        
+        /// Set the scaling for lengths.
+        void setLengthScale(float value);
+        /// Set the scaling for meshes.
+        void setMeshScale(float value);
+        /// Set the scaling for mass (to kg).
+        void setMassScale(float value);
+
+        /// Set the actuator type.
+        void setActuatorType(ActuatorType value);
+        /// Set whether a type suffix shall be added to actuator names.
+        void setAddActuatorTypeSuffix(bool enable);
+        /// Set suffixes appended to actuator names if adding actuator type suffixes is enabled.
+        void setActuatorTypeSuffixes(const std::map<ActuatorType, std::string>& suffixes);
+        
+        
+        /**
+         * @brief Enable or disable adding of a mocap body controlling the robot pose.
+         * 
+         * @param enabled If true:
+         * - Add a free joint to the robot root body mocap body
+         * - Add a mocap body in the world body (called <RobotName>_Mocap)
+         * - Add a weld constraint welding them together.
+         */
+        void setWithMocapBody(bool enabled);
+        
+        void setVerbose(bool value);
+        
+        
+    private:
+        
+        /// Set the output path members.
+        void setPaths(const std::string& filename, const std::string& basePath, 
+                      const std::string& meshRelDir);
+        /// Create output directories if the do not exist.
+        void ensureDirectoriesExist();
+        
+        /// Make the compiler section.
+        void makeCompiler();
+        /// Add a defaults group for the robot.
+        void makeDefaultsClass();
+        /// Add a skybox texture asset.
+        void addSkybox();
+        
+        /// Add a mocap body with defaults group.
+        mjcf::Body addMocapBody();
+        
+        /// Construct the body structure corresponding to the robot nodes.
+        void makeNodeBodies();
+        
+        /// Add a body element for a robot node.
+        /// If its parent does not exist, create the parent body first.
+        mjcf::Body addNodeBody(RobotNodePtr node);
+        
+        /// Add a body for the given node as child of parent and return it.
+        mjcf::Body addNodeBody(mjcf::Body parent, RobotNodePtr node);
+        /// Add a joint for the given node in body and return it.
+        mjcf::Joint addNodeJoint(mjcf::Body body, RobotNodePtr node);
+        /// Add an inertial for the given node in body and return it.
+        mjcf::Inertial addNodeInertial(mjcf::Body body, RobotNodePtr node);
+        
+        /// Convert meshes and add mesh assets for robot nodes with visualization.
+        void addNodeBodyMeshes();
+        
+        /// Add contact exclude elements for IgnoreCollision elements.
+        void addContactExcludes();
+        /// Add contact exclude elements for IgnoreCollision elements.
+        void addMocapContactExcludes(mjcf::Body mocap);
+        
+        /// Add actuators for all joints.
+        void addActuators();
+        
+        /// Scale all lengths by lengthScaling.
+        void scaleLengths(mjcf::AnyElement elem);
+        
+        
+        // Paremeters
+        
+        bool useRelativePaths = false;
+        
+        /// Scaling for lengths, such as positions and translations (to m).
+        float lengthScale = 0.001f;
+        /// Scaling for lengths, such as positions and translations (to m).
+        float meshScale = 1.f;
+        /// Scaling for mass (to kg).
+        float massScale = 1.f;
+        
+        /// The actuator type.
+        ActuatorType actuatorType = ActuatorType::MOTOR;
+        
+        /// Whether to add type suffix to actuator names
+        bool addActuatorTypeSuffix = false;
+        /// The suffixes added if addActuatorTypeSuffix is true.
+        std::map<ActuatorType, std::string> actuatorTypeSuffixes = {
+            { ActuatorType::MOTOR, "_motor" },
+            { ActuatorType::POSITION, "_position" },
+            { ActuatorType::VELOCITY, "_velocity" },
+        };
+        
+        
+        /// Add a mocap
+        bool withMocapBody = false;
+        
+        /// Verbose printing.
+        bool verbose = false;
+        
+        
+        // Paths
+        
+        std::filesystem::path outputDirectory;
+        std::filesystem::path outputFileName;
+        std::filesystem::path outputMeshRelDirectory;
+        std::filesystem::path outputMeshDirectory() { return outputDirectory / outputMeshRelDirectory; }
+        
+        
+        // Input
+        
+        /// The input robot.
+        RobotPtr robot;
+        
+        
+        // Output
+        
+        /// The built MJCF document.
+        mjcf::DocumentPtr document = nullptr;
+        mjcf::Body robotRoot;
+
+        
+        // Processing
+        
+        /// Sanitizes massless bodies.
+        mujoco::MasslessBodySanitizer masslessBodySanitizer { robot };
+        
+        /// Map of robot node names to XML elements.
+        std::map<std::string, mjcf::Body> nodeBodies;
+        
+        const std::string t = "| ";
+        
+    };
+    
+    
+}}
diff --git a/VirtualRobot/examples/Simox2Mjcf/main.cpp b/VirtualRobot/examples/Simox2Mjcf/main.cpp
index 28d62a8de95bd46499a40a1f1053930a5d498972..e65ab1cd2ac9186661d90d03d18e9b124ee17f13 100644
--- a/VirtualRobot/examples/Simox2Mjcf/main.cpp
+++ b/VirtualRobot/examples/Simox2Mjcf/main.cpp
@@ -3,7 +3,7 @@
 #include <VirtualRobot/RuntimeEnvironment.h>
 
 #include <VirtualRobot/XML/RobotIO.h>
-#include <VirtualRobot/XML/mjcf/MujocoIO.h>
+#include <VirtualRobot/XML/mujoco/MujocoIO.h>
 
 
 using namespace VirtualRobot;
@@ -12,17 +12,6 @@ using VirtualRobot::RuntimeEnvironment;
 namespace fs = std::filesystem;
 
 
-void printUsage(const char* argv0)
-{
-    std::cout << "Usage: " << argv0 
-              << " --robot <simox robot file> "
-              << "[--outdir <output directory>] "
-              << "[--meshRelDir <relative mesh directory>] "
-              << "[--actuator {motor|position|velocity}] "
-              << "[--mocap {y|n}]"
-              << std::endl;
-}
-
 /**
  * Loads a Simox robot and converts it to Mujoco's XML format (MJCF).
  * The converted file is stored in a directory mjcf/ placed in the directory
@@ -30,20 +19,46 @@ void printUsage(const char* argv0)
  */
 int main(int argc, char* argv[])
 {
-    RuntimeEnvironment::considerKey("robot");
-    RuntimeEnvironment::considerKey("outdir");
-    RuntimeEnvironment::considerKey("meshRelDir");
-    RuntimeEnvironment::considerKey("actuator");
-    RuntimeEnvironment::considerKey("mocap");
+    RuntimeEnvironment::setCaption("Convert Simox XML to MJCF (Mujoco XML)");
+    
+    RuntimeEnvironment::considerKey(
+                "robot", "The Simox robot model to convert. (required)");
+    RuntimeEnvironment::considerKey(
+                "outdir", "The output directory. (default: 'mjcf')");
+    RuntimeEnvironment::considerKey(
+                "mesh_rel_dir", "The mesh directory relative to outdir. (default: 'mesh')");
+    RuntimeEnvironment::considerKey(
+                "actuator", "The actuator type to add (motor, position, velocity). (default: motor)");
+    RuntimeEnvironment::considerFlag(
+                "mocap", "Add a mocap body to which the robot root body is welded.");
+    
+    RuntimeEnvironment::considerFlag(
+                "rel_paths", "Store relative mesh paths instead of absolute ones. (This can "
+                             "cause problems when including the generated model from another directory.)");
+    
+    RuntimeEnvironment::considerKey(
+                "scale_length", "Scaling of lengths and distances (to m). For meshes, see 'scale_mesh'. (default: 1.0)");
+    RuntimeEnvironment::considerKey(
+                "scale_mesh", "Scaling of meshes (to m). (default: 1.0)");
+    RuntimeEnvironment::considerKey(
+                "scale_mass", "Scaling of masses (to kg). (default: 1.0)");
+    
+    RuntimeEnvironment::considerFlag(
+                "actuator_suffix", "Add a type suffix to actuator names.");
+    
+    RuntimeEnvironment::considerFlag(
+                "verbose", "Enable verbose output.");
     
     RuntimeEnvironment::processCommandLine(argc, argv);
 
-    //RuntimeEnvironment::print();
-    
-    fs::path inputFilename;
     
+    if (RuntimeEnvironment::hasHelpFlag() || !RuntimeEnvironment::hasValue("robot"))
+    {
+        RuntimeEnvironment::printOptions();
+        return 0;
+    }
     
-    if (RuntimeEnvironment::hasValue("robot"))
+    fs::path inputFilename;
     {
         std::string robFile = RuntimeEnvironment::getValue("robot");
 
@@ -56,44 +71,79 @@ int main(int argc, char* argv[])
             std::cout << "Something is wrong with " << robFile;
         }
     }
-    else
-    {
-        printUsage(argv[0]);
-        return 0;
-    }
     
-    fs::path outputDir = RuntimeEnvironment::checkParameter(
+    const fs::path outputDir = RuntimeEnvironment::checkParameter(
                 "outdir", (inputFilename.parent_path() / "mjcf").string());
-    std::string meshRelDir = RuntimeEnvironment::checkParameter("meshRelDir", "mesh");
+    const std::string meshRelDir = RuntimeEnvironment::checkParameter("mesh_rel_dir", "mesh");
     
     
-    std::string actuatorTypeStr = RuntimeEnvironment::checkParameter("actuator", "motor");
-    mjcf::ActuatorType actuatorType;
+    const std::string actuatorTypeStr = RuntimeEnvironment::checkParameter("actuator", "motor");
+    mujoco::ActuatorType actuatorType;
     try
     {
-        actuatorType = mjcf::toActuatorType(actuatorTypeStr);
+        actuatorType = mujoco::toActuatorType(actuatorTypeStr);
     }
     catch (const std::out_of_range&)
     {
-        std::cout << "No actuator '" << actuatorTypeStr << "'" << std::endl;
+        std::cout << "No actuator type '" << actuatorTypeStr << "'" << std::endl;
         std::cout << "Avaliable: motor|position|velocity" << std::endl;
         return -1;
     }
     
-    bool mocap = RuntimeEnvironment::checkParameter("mocap", "n") == "y";
+    const bool mocap = RuntimeEnvironment::hasFlag("mocap");
+    const bool verbose = RuntimeEnvironment::hasFlag("verbose");
+    const bool addActuatorSuffix = RuntimeEnvironment::hasFlag("actuator_suffix");
+    
+    const bool useRelativePaths = RuntimeEnvironment::hasFlag("rel_paths");
+    
+  
+    auto parseFloatParameter = [](const std::string& key, const std::string& default_)
+    {
+        const std::string string = RuntimeEnvironment::checkParameter(key, default_);
+        try
+        {
+            return std::stof(string);
+        }
+        catch (const std::invalid_argument& e)
+        {
+            std::cerr << "Could not parse value of argument " << key << ": '" << string << "' \n" 
+                      << "Reason: " << e.what() << std::endl;
+            throw e;
+        }
+    };
+    
+    float scaleLength;
+    float scaleMesh;
+    float scaleMass;
+    try
+    {
+        scaleLength = parseFloatParameter("scale_length", "1");
+        scaleMesh = parseFloatParameter("mesh_length", "1");
+        scaleMass = parseFloatParameter("scale_mass", "1");
+    }
+    catch (const std::invalid_argument&)
+    {
+        return -1;
+    }
     
     
     std::cout << "Input file:      " << inputFilename << std::endl;
     std::cout << "Output dir:      " << outputDir << std::endl;
     std::cout << "Output mesh dir: " << outputDir / meshRelDir << std::endl;
-    //std::cout << "Actuator type: " << actuatorType << std::endl;
-    std::cout << "With mocap body: " << (mocap ? "yes" : "no ");
+    std::cout << "Actuator type:   " << actuatorTypeStr << std::endl;
+    std::cout << "Mocap body:      " << (mocap ? "yes" : "no ") << std::endl;
+    
+    std::cout << "Scaling: " <<  std::endl
+              << "  - length: " << scaleLength << std::endl
+              << "  - mesh:   " << scaleMesh << std::endl
+              << "  - mass:   " << scaleMass << std::endl;
 
     std::cout << "Loading robot ..." << std::endl;
     
     RobotPtr robot;
     try
     {
+        std::cout << "Loading robot from " << inputFilename << " ..." << std::endl;
         robot = RobotIO::loadRobot(inputFilename.string(), RobotIO::eFull);
         assert(robot);
     }
@@ -102,7 +152,7 @@ int main(int argc, char* argv[])
         throw; // rethrow
     }
     
-    if (false)
+    if (/* DISABLES CODE */ (false))
     {
         // using RobotIO
         RobotIO::saveMJCF(robot, inputFilename.filename().string(), outputDir.string(), meshRelDir);
@@ -110,9 +160,20 @@ int main(int argc, char* argv[])
     else
     {
         // direct API
-        mjcf::MujocoIO mujocoIO(robot);
+        mujoco::MujocoIO mujocoIO(robot);
+        
         mujocoIO.setActuatorType(actuatorType);
+        mujocoIO.setAddActuatorTypeSuffix(addActuatorSuffix);
+        
+        mujocoIO.setUseRelativePaths(useRelativePaths);
         mujocoIO.setWithMocapBody(mocap);
+        
+        mujocoIO.setLengthScale(scaleLength);
+        mujocoIO.setMeshScale(scaleMesh);
+        mujocoIO.setMassScale(scaleMass);
+        
+        mujocoIO.setVerbose(verbose);
+        
         mujocoIO.saveMJCF(inputFilename.filename().string(), outputDir.string(), meshRelDir);
     }
 }
diff --git a/VirtualRobot/math/Helpers.cpp b/VirtualRobot/math/Helpers.cpp
index 6ee4ca92209380f12b71f7235d5bea130cbe8122..643734184e81a0d4808af13bcf58ea2a0559bfce 100644
--- a/VirtualRobot/math/Helpers.cpp
+++ b/VirtualRobot/math/Helpers.cpp
@@ -229,6 +229,18 @@ void Helpers::InvertPose(Eigen::Matrix4f& pose)
     Position(pose) = - Orientation(pose) * Position(pose);
 }
 
+void Helpers::ScaleTranslation(Eigen::Matrix4f& pose, float scale)
+{
+    Position(pose) *= scale;
+}
+
+Eigen::Matrix4f Helpers::ScaledTranslation(const Eigen::Matrix4f& pose, float scale)
+{
+    Eigen::Matrix4f scaled = pose;
+    ScaleTranslation(scaled, scale);
+    return scaled;
+}
+
 
 Eigen::Matrix3f Helpers::GetRotationMatrix(const Eigen::Vector3f& source, const Eigen::Vector3f& target)
 {
diff --git a/VirtualRobot/math/Helpers.h b/VirtualRobot/math/Helpers.h
index 33703de24faf0dd13d399ca45884211fae43694d..9b3d079537ff1dd6e08bccd94b66f3fa4577e7f5 100644
--- a/VirtualRobot/math/Helpers.h
+++ b/VirtualRobot/math/Helpers.h
@@ -138,6 +138,11 @@ namespace math
         template <typename Derived>
         static Eigen::Matrix4f InvertedPose(const Eigen::MatrixBase<Derived>& pose);
         
+        /// Scale the translation/position of the given pose.
+        static void ScaleTranslation(Eigen::Matrix4f& pose, float scale);
+        /// Get the pose with its translation/position scaled.
+        static Eigen::Matrix4f ScaledTranslation(const Eigen::Matrix4f& pose, float scale);
+        
         /// Get a cartesian vector from cylinder coordinates.
         static Eigen::Vector3f CreateVectorFromCylinderCoords(float r, float angle, float z);
         /// Get a cartesian vector from cylinder coordinates.
diff --git a/VirtualRobot/tests/CMakeLists.txt b/VirtualRobot/tests/CMakeLists.txt
index 112052c6fb14f0f5ec8e3b8b5339d37f2507e058..d6399d134a6bcbd7e6190042d242209f176c785f 100644
--- a/VirtualRobot/tests/CMakeLists.txt
+++ b/VirtualRobot/tests/CMakeLists.txt
@@ -30,7 +30,10 @@ ADD_VR_TEST( VirtualRobotMeshImportTest )
 
 ADD_VR_TEST( VirtualRobotTimeOptimalTrajectoryTest )
 
+ADD_VR_TEST( VirtualRobotRuntimeEnvironmentTest )
+
 ADD_VR_TEST( VirtualRobotJsonEigenConversionTest )
+ADD_VR_TEST( VirtualRobotMjcfTest )
 
 ADD_VR_TEST( MathFitPlaneTest )
 ADD_VR_TEST( MathGaussianImplicitSurface3DNormalsTest )
diff --git a/VirtualRobot/tests/VirtualRobotMjcfTest.cpp b/VirtualRobot/tests/VirtualRobotMjcfTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..863addcdf96ca9b551fc4d873742df140380b25c
--- /dev/null
+++ b/VirtualRobot/tests/VirtualRobotMjcfTest.cpp
@@ -0,0 +1,134 @@
+/**
+* @package    VirtualRobot
+* @author     Rainer Kartmann
+* @copyright  2018 Rainer Kartmann
+*/
+
+#define BOOST_TEST_MODULE VirtualRobot_VirtualRobotMjcfTest
+
+#include <VirtualRobot/VirtualRobotTest.h>
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <VirtualRobot/MJCF/Document.h>
+
+
+namespace Eigen
+{
+    std::ostream& operator<<(std::ostream& os, const Vector3f& rhs)
+    {
+        static const IOFormat iof(4, 0, " ", " ", "", "", "[", "]");
+        os << rhs.format(iof);
+        return os;
+    }
+
+    bool operator==(const Quaternionf& lhs, const Quaternionf& rhs)
+    {
+        return lhs.isApprox(rhs);
+    }
+    
+    std::ostream& operator<<(std::ostream& os, const Quaternionf& rhs)
+    {
+        os << "[ " << rhs.w() << " | " << rhs.x() << " " << rhs.y() << " " << rhs.z() << " ]";
+        return os;
+    }
+}
+
+#define MSG_CONVERSION(in, string, out) \
+    BOOST_TEST_MESSAGE(in << " -> '" << string << "' -> " << out)
+
+BOOST_AUTO_TEST_SUITE(VirtualRobotMjcfTest)
+
+BOOST_AUTO_TEST_CASE(test_boost_lexical_cast)
+{
+    for (bool in : { true, false })
+    {
+        const std::string string = boost::lexical_cast<std::string>(in);
+        bool out = boost::lexical_cast<bool>(string);
+        MSG_CONVERSION(in, string, out);
+        BOOST_CHECK_EQUAL(in, out);
+    }
+    
+    // this cannot be handled by boost
+    BOOST_CHECK_THROW(boost::lexical_cast<bool>("true"), boost::bad_lexical_cast);
+    BOOST_CHECK_THROW(boost::lexical_cast<bool>("false"), boost::bad_lexical_cast);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+using namespace Eigen;
+
+
+BOOST_AUTO_TEST_CASE(test_parseCoeffs)
+{
+    const std::string string = "1 -3 2.4";
+    Eigen::Vector3f vector(1, -3, 2.4f);
+    
+    std::vector<float> coeffs = mjcf::parseCoeffs<float>(string, ' ');
+    
+    BOOST_CHECK_EQUAL(coeffs[0], vector.x());
+    BOOST_CHECK_EQUAL(coeffs[1], vector.y());
+    BOOST_CHECK_EQUAL(coeffs[2], vector.z());
+}
+
+
+BOOST_AUTO_TEST_CASE(test_attrib_conversion_vector3f)
+{
+    Vector3f in(1, -3, 2.4f), out;
+    
+    const std::string string = mjcf::toAttr(in);
+    mjcf::fromAttr(string, out);
+    MSG_CONVERSION(in, string, out);
+    
+    BOOST_CHECK_EQUAL(in, out);
+}
+
+BOOST_AUTO_TEST_CASE(test_attrib_conversion_quaternionf)
+{
+    Quaternionf in(AngleAxisf(1.4f, Vector3f(.5, -1, .3f).normalized())), out;
+    
+    const std::string string = mjcf::toAttr(in);
+    mjcf::fromAttr(string, out);
+    MSG_CONVERSION(in, string, out);
+    
+    BOOST_CHECK_EQUAL(in, out);
+}
+
+
+
+
+struct Fixture
+{
+    mjcf::Document document;
+    
+    mjcf::Body body;
+    mjcf::Joint joint;
+    
+    Fixture()
+    {
+        body = document.worldbody().addBody("thebody");
+        joint = body.addJoint();
+        joint.name = "thejoint";
+    }
+};
+
+
+BOOST_FIXTURE_TEST_SUITE(VirtualRobotMjcfTest, Fixture)
+
+BOOST_AUTO_TEST_CASE(test_attribute_pos)
+{
+    Eigen::Vector3f in(1, -3, 2.4f), out;
+    body.pos = in;
+    out = body.pos;
+    BOOST_CHECK_EQUAL(in, out);
+}
+
+BOOST_AUTO_TEST_CASE(test_attribute_quat)
+{
+    Eigen::Quaternionf out, in(Eigen::AngleAxisf(1.2, Eigen::Vector3f(1, -3, 2.4f).normalized()));
+    body.quat = in;
+    out = body.quat;
+    BOOST_CHECK_EQUAL(in, out);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/VirtualRobot/tests/VirtualRobotRuntimeEnvironmentTest.cpp b/VirtualRobot/tests/VirtualRobotRuntimeEnvironmentTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c1935b9d0be8a277e16e797a773b7a95c0a43cec
--- /dev/null
+++ b/VirtualRobot/tests/VirtualRobotRuntimeEnvironmentTest.cpp
@@ -0,0 +1,55 @@
+/**
+* @package    VirtualRobot
+* @author     Nikolaus Vahrenkamp
+* @copyright  2011 Nikolaus Vahrenkamp
+*/
+
+#define BOOST_TEST_MODULE VirtualRobot_VirtualRobotRuntimeEnvironmentTest
+
+#include <VirtualRobot/VirtualRobotTest.h>
+#include <VirtualRobot/RuntimeEnvironment.h>
+
+
+BOOST_AUTO_TEST_SUITE(RuntimeEnvironment)
+
+
+BOOST_AUTO_TEST_CASE(test_toVector3f_valid_input)
+{
+    Eigen::Vector3f vector;
+            
+    BOOST_CHECK(VirtualRobot::RuntimeEnvironment::toVector3f("(0, 0, 0)", vector));
+    BOOST_CHECK_EQUAL(vector, Eigen::Vector3f::Zero());
+    
+    BOOST_CHECK(VirtualRobot::RuntimeEnvironment::toVector3f("(1, 2, 3)", vector));
+    BOOST_CHECK_EQUAL(vector, Eigen::Vector3f(1, 2, 3));
+    
+    BOOST_CHECK(VirtualRobot::RuntimeEnvironment::toVector3f("(-1, 2, 5)", vector));
+    BOOST_CHECK_EQUAL(vector, Eigen::Vector3f(-1, 2, 5));
+    
+    BOOST_CHECK(VirtualRobot::RuntimeEnvironment::toVector3f("(-3.14, 0, 9.99)", vector));
+    BOOST_CHECK_EQUAL(vector, Eigen::Vector3f(-3.14f, 0, 9.99f));
+}
+
+
+BOOST_AUTO_TEST_CASE(test_toVector3f_invalid_input)
+{
+    Eigen::Vector3f vector;
+            
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("()", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("nonsense", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("(0)", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("(0, 0)", vector));
+    
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("1, 2, 3", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("1, 2, 3)", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("(1, 2, 3", vector));
+    
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("(0. 0, 0)", vector));
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("(0; 0; 0)", vector));
+    
+    BOOST_CHECK(!VirtualRobot::RuntimeEnvironment::toVector3f("(0, 0, a)", vector));
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()