diff --git a/README.md b/README.md
index 9fadd6f5..95d6ea6a 100644
--- a/README.md
+++ b/README.md
@@ -65,3 +65,11 @@ If the python bindings in the C++ code have changed you might need to regenerate
```shell
make stubgen
```
+
+### To build the documentation locally
+```
+cd docs
+sphinx-build -M html ./source/ ./build
+```
+
+docs/build/html/index.html will the final document
diff --git a/docs/doc_requirements.txt b/docs/doc_requirements.txt
new file mode 100644
index 00000000..072f818d
--- /dev/null
+++ b/docs/doc_requirements.txt
@@ -0,0 +1,3 @@
+pydata-sphinx-theme==0.16.1
+myst-parser==4.0.1
+sphinx-autodoc-typehints
\ No newline at end of file
diff --git a/docs/docs_action_observation_flow/action_obersvation_flow.md b/docs/docs_action_observation_flow/action_obersvation_flow.md
new file mode 100644
index 00000000..35d6bd88
--- /dev/null
+++ b/docs/docs_action_observation_flow/action_obersvation_flow.md
@@ -0,0 +1,132 @@
+# Action-Observation Flow
+
+## wrapper Hierarchy
+
+
+Vertical Order:
+
+- Top: Highest-level wrapper (first applied)
+
+- Bottom: Base environment
+
+Inheritance Notation:
+
+- Use (ParentClass) next to wrapper names
+
+Wrapping Notation
+
+- Show ← wraps arrows between layers
+
+
+
+
+## Flow
+1. **`RelativeActionSpace(ActionWrapper).step(act)`**
+
+ - 2- Calls step function of ActionWrapper (→2)
+
+2. **`ActionWrapper.step(act)`**
+ - 3. Calls `RelativeActionSpace.action(act)`
+ - 4. Calls `GripperWrapper.step(act)`
+
+3. **`RelativeActionSpace.action(act)`**
+ - Processes action: `{"tquart": [0.01, 0, 0, 0, 0, 0, 1], "gripper": 0}`
+ - Operations:
+ - Clips action within min/max limits
+ - Makes action relative (current_pose + action)
+ - Updates `action["tquart"]`
+
+4. **`GripperWrapper(ActObsInfoWrapper).step(act)`**
+ - →5. Calls `GripperWrapper.action(act)`
+ - →6. Calls `CameraSetWrapper.step(act)`
+ - →15. Calls `GripperWrapper.observation(obs)`
+
+5. **`GripperWrapper.action(act)`**
+ - Uses `act["gripper"]` to open/close gripper
+ - Only executes if state change needed
+ - Deletes `"gripper"` key from action dict
+
+6. **`CameraSetWrapper(ActObsInfoWrapper).step(act)`**
+ - →7. Calls `CameraSetWrapper.action(act)`
+ - →8. Calls `CameraSetWrapper(ActObsInfoWrapper).step(act)`
+ - →14. Calls `CameraSetWrapper.observation(obs)`
+
+7. **`CameraSetWrapper.action(act)`**
+ - (Pass-through) Returns original action
+
+8. **`CameraSetWrapper(ActObsInfoWrapper).step(act)`**
+ - →9. Calls `CameraSetWrapper.action(act)`
+ - →10. Calls `FR3Sim.step(act)`
+
+9. **`CameraSetWrapper.action(act)`**
+ - (Pass-through) Returns original action
+
+10. **`FR3Sim.step(act)`**
+ - →11. Calls `FR3Env.step(act)`
+ - 13. Executes:
+ ```python
+ self.sim.step_until_convergence()
+ state = self.sim_robot.get_state()
+ ```
+ - Returns observation
+
+11. **`FR3Env.step(act)`**
+ - Sets new pose:
+ ```python
+ self.robot.set_cartesian_position(
+ common.Pose(
+ translation=action_dict[self.tquart_key][:3],
+ quaternion=action_dict[self.tquart_key][3:]
+ )
+ )
+ ```
+ - →12. Calls `FR3Env.get_obs()`
+
+12. **`FR3Env.get_obs()`**
+ - Returns:
+ ```python
+ (
+ tquart=np.concatenate([
+ self.robot.get_cartesian_position().translation(),
+ self.robot.get_cartesian_position().rotation_q()
+ ]),
+ joints=self.robot.get_joint_position(),
+ xyzrpy=self.robot.get_cartesian_position().xyzrpy()
+ )
+ ```
+ - Shapes:
+ - `joints`: (7,)
+ - `tquart`: (7,) [x,y,z, qx,qy,qz,qw]
+ - `xyzrpy`: (6,) [x,y,z, roll,pitch,yaw]
+
+14. **`CameraSetWrapper.observation(obs)`**
+ - Adds camera data:
+ ```python
+ {
+ ...original_obs...,
+ "frames": {
+ "wrist": {
+ "rgb": (256,256,3),
+ "depth": (256,256,3)
+ },
+ "default_free": {
+ "wrist": {
+ "rgb": (256,256,3),
+ "depth": (256,256,3)
+ }
+ }
+ }
+ }
+ ```
+
+15. **`GripperWrapper.observation(obs)`**
+ - Adds gripper state:
+ ```python
+ {
+ ...previous_data...,
+ "gripper": float
+ }
+ ```
+# Sequence Diagram
+
+
diff --git a/docs/docs_action_observation_flow/images/class_hierarchy.png b/docs/docs_action_observation_flow/images/class_hierarchy.png
new file mode 100644
index 00000000..eb7be6d1
Binary files /dev/null and b/docs/docs_action_observation_flow/images/class_hierarchy.png differ
diff --git a/docs/docs_action_observation_flow/images/sequence_diagram.png b/docs/docs_action_observation_flow/images/sequence_diagram.png
new file mode 100644
index 00000000..0ea1df9e
Binary files /dev/null and b/docs/docs_action_observation_flow/images/sequence_diagram.png differ
diff --git a/docs/source/_templates/.gitkeep b/docs/source/_templates/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/source/architecture/rcs_architecture.md b/docs/source/architecture/rcs_architecture.md
new file mode 100644
index 00000000..cb20f0a1
--- /dev/null
+++ b/docs/source/architecture/rcs_architecture.md
@@ -0,0 +1,37 @@
+# Robot Control Stack architecture
+
+
+
+
+A core contribution of RCS is a simple yet versatile
+architecture that allows for easy extension and customization.
+The architecture is organized in multiple layers that represent
+increasing levels of abstraction from platform-specific implementation details.
+While lower layers are implemented in
+C++, higher layers are implemented in Python or provide
+bindings for Python. Rapid prototyping and performance-
+critical code are therefore supported equally well.
+RCS uses [MuJoCo](https://ieeexplore.ieee.org/document/6386109) as its simulator and the [Robotics
+Library](https://ieeexplore.ieee.org/document/8202232) for inverse kinematics. There is support for
+Franka robots through the native library provided by the
+manufacturer. New robot types can be added by implementing a small set of API functions.
+Both the simulation and the actual hardware share a unified interface for a
+seamless transition between the two. Adding sensors and
+actuators to the simulation is managed through a frequency-
+based callback mechanism that interfaces with the global
+simulation loop.
+
+At the most abstract level, RCS implements an easy-to-use
+[Gymnasium-style API](https://arxiv.org/abs/2407.17032). This interface is not only widely
+used in reinforcement learning but also enables the flexible
+composition of environment wrappers for adding features.
+
+For example, the collision checker depicted in the above figure is
+implemented as a wrapper that checks motion commands
+in simulation and filters them to prevent collisions.
+
+```{toctree}
+:maxdepth: 1
+
+wrappers.md
+```
diff --git a/docs/source/architecture/wrappers.md b/docs/source/architecture/wrappers.md
new file mode 100644
index 00000000..ee35da80
--- /dev/null
+++ b/docs/source/architecture/wrappers.md
@@ -0,0 +1,33 @@
+# Wrappers
+
+```
+Note:
+This content has not yet been proof read!
+```
+
+[Wrappers](https://www.gymlibrary.dev/api/wrappers/) are a convenient way to modify an existing environment without having to alter the underlying code directly.
+RCS offers the following wrappers that add functionality in a layered manner.
+
+1. FR3Env
+
+ This is the basic Joint Gym Environment for Franka Research 3.
+
+2. FR3Sim
+
+ This wraps the basic FR3Env with the MuJoCo simulation.
+
+3. CameraSetWrapper
+
+ This is an observation wrapper, that takes the observation from its parent environment and add rgbd information.
+
+4. GripperWrapper
+
+ This is an observation wrapper, that takes the observation from its parent environment and add gripper_state(whether open or close) information.
+
+5. CollisionGuard
+
+ This wrapper is used for safety from collisions. Before executing the action, this collision guard executes the action in simulation in a sub-collision environment to ensure there is no collision, after that the action will be executed on the parent environment. In case of collision, the user can decide whether to truncate the episode.
+
+6. RelativeActionSpace
+
+ This wrapper clips the actions based on pre-defined maximum limits and steps the clipped actions on the parent environment.
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 00000000..705e19f0
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,28 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = 'RCS'
+copyright = '2025, UTN'
+author = 'UTN'
+release = 'v0.3.1'
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = ["myst_parser", 'sphinx.ext.napoleon', "sphinx_autodoc_typehints"]
+
+templates_path = ['_templates']
+exclude_patterns = []
+
+
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = 'pydata_sphinx_theme'
+html_static_path = ['_static']
diff --git a/docs/source/index.md b/docs/source/index.md
new file mode 100644
index 00000000..a5b2ff03
--- /dev/null
+++ b/docs/source/index.md
@@ -0,0 +1,32 @@
+
+
+# RCS documentation
+
+
+
+
+
+
+No matter whether it is in simulation or in the
+lab – setting up robotics experiments is challenging, especially
+if they target both types of deployments. While a plethora of
+different robotics software frameworks exist, they usually make
+a trade-off between complexity and versatility. Drawing from
+this rich ecosystem, Robot Control Stack (RCS) is a
+robotics software stack that is designed to resolve this conflict by
+combining established robotics tools and frameworks through
+a lightweight multi-layered API that unifies simulation and
+real-world robot control.
+
+
+```{toctree}
+:maxdepth: 1
+
+user_guide/user_guide.md
+```
+
+
diff --git a/docs/source/models/custom_grippers.md b/docs/source/models/custom_grippers.md
new file mode 100644
index 00000000..6f51d537
--- /dev/null
+++ b/docs/source/models/custom_grippers.md
@@ -0,0 +1,55 @@
+# Custom Grippers
+
+Custom grippers can be used with RCS by following the instructions below.
+## How to add a custom gripper
+An example custom gripper is available for reference [here](https://gitos.rrze.fau.de/utn-machine-intelligence/lab/models/-/tree/main/grippers/digit_hand/obj?ref_type=heads) **(only if you have access to the RCS models repo)**
+
+The adjustment to fr3_0.xml and fr3_common.xml can be found [here](https://gitos.rrze.fau.de/utn-machine-intelligence/lab/models/-/tree/main/scenes/fr3_simple_pick_up_digit_hand?ref_type=heads) **(only if you have access to the RCS models repo)**
+
+### Step1: export obj files
+If the gripper is downloaded from somewhere convert it to .obj file.
+Make sure that the x, y, z axis of the default gripper and the custom gripper are the same. In case they are different, later the slide joint axis might have to be adjusted. This can be done by visualing the coordinate axis, by dragging the obj files in onshape.
+### Step2: convert obj to mjcf
+**Note:** First ensure that the file_names dont have space in their names
+
+**e.g** rename to in three places(obj file, mtl file, mtl file reference inside the obj file)
+
+A python package for converting obj files to mjcf files is available [here](https://pypi.org/project/obj2mjcf/0.0.3/).
+After installing it, use the following command to do the required conversion.
+
+
+
+```shell
+obj2mjcf --obj-dir --save-mjcf
+```
+
+
+### Step3: verify in mujoco viewer
+With the above two steps, the conversion should be successful, you should be able to view the standalone grippers in mujco with the following commands
+
+```shell
+python -m mujoco.viewer
+```
+
+
+after opening the mujoco viewer you can drag the converted scene and visualise it.
+
+### Step4: Adding the gripper to the lab or fr3_empty_world scenes
+ The following steps need to be followed:
+ 1. in fr3_common, the mesh should be renamed to the new gripper
+ 2. in fr3_0 and fr3_1 and all the robots, the fingers’ geom must be adjusted for material and if there are name changes
+ 3. physics parameters should be adjusted empirically..
+ e.g. new collision meshes specific to the gripper added, friction parameters adjustment
+
+## step5: update the tcp offset
+ add the correct tcp_offset value to the following to fr3_common.xml
+
+
+ ```
+
+
+
+ ```
diff --git a/docs/source/source_code/fr3_sim.md b/docs/source/source_code/fr3_sim.md
new file mode 100644
index 00000000..cf59c279
--- /dev/null
+++ b/docs/source/source_code/fr3_sim.md
@@ -0,0 +1,7 @@
+# rcsss.envs.factories
+
+```{eval-rst}
+.. automodule:: rcsss.envs.factories
+ :members:
+ :show-inheritance:
+```
\ No newline at end of file
diff --git a/docs/source/source_code/rcs_api.md b/docs/source/source_code/rcs_api.md
new file mode 100644
index 00000000..e9e90ff6
--- /dev/null
+++ b/docs/source/source_code/rcs_api.md
@@ -0,0 +1,12 @@
+# RCS API
+
+We are still in the process of documenting all of the functions.
+
+Subpackages:
+
+```{toctree}
+:titlesonly:
+:maxdepth: 1
+
+fr3_sim.md
+```
diff --git a/python/rcsss/envs/factories.py b/python/rcsss/envs/factories.py
index b5c85388..f2375176 100644
--- a/python/rcsss/envs/factories.py
+++ b/python/rcsss/envs/factories.py
@@ -200,7 +200,7 @@ def fr3_sim_env(
relative_to (RelativeTo): Specifies whether the movement is relative to a configured origin or the last step.
urdf_path (str | PathLike | None): Path to the URDF file. If None, the URDF file is automatically deduced
which requires a UTN compatible lab scene to be present.
- mjcf (str | PathLike): Path to the Mujoco scene XML file. Defaults to "fr3_empty_world".
+ mjcf (str | PathLike): Path to the MuJoCo scene XML file. Defaults to "fr3_empty_world".
sim_wrapper (Type[SimWrapper] | None): Wrapper to be applied before the simulation wrapper. This is useful
for reset management e.g. resetting objects in the scene with correct observations. Defaults to None.