diff --git a/SimulationAnalyser/main.py b/SimulationAnalyser/main.py
index d6239c8241ebd6dc560a7967bb6286913879db5a..5c1a51010028ef96cf6b3e896a4eb0710b024d85 100644
--- a/SimulationAnalyser/main.py
+++ b/SimulationAnalyser/main.py
@@ -17,10 +17,17 @@ LEARNING_STR = "LEARNING"
 FOLDER_PATH_LOGS_TO_ANALYSE = "../impulse/Assets/SimulationLogs"
 FOLDER_PATH_SAVE_GRAPH_ANALYSIS = "./Analysis"
 
+FEATURES = [
+        "scoreDelta", "distanceDelta", "obstacleDelta", "explorationEfficiency",
+        "variationInDirection", "velocityMagnitude", "collectibleCollectEfficiency",
+        "obstacleAvoidanceEfficiency", "timeSinceLastCollectible", "timeSinceLastHitObstacle"
+    ]
+
 def compute_velocity_magnitude(velocity):
     return np.sqrt(velocity.get("x", 0)**2 + velocity.get("y", 0)**2 + velocity.get("z", 0)**2)
 
 def auto_label(entry):
+    # TO REWORK TO BE BETTER or WHAT KIND OF LEARNING ML USE ?
     is_stationary = entry["distanceDelta"] < 0.01 and entry["velocityMagnitude"] < 0.01
     no_progress = entry["scoreDelta"] < 0.5 and entry["collectibleCollectEfficiency"] < 0.1
     if is_stationary or no_progress:
@@ -71,18 +78,19 @@ def run_unsupervised_clustering(df, output_folder):
     centers = pd.DataFrame(kmeans.cluster_centers_, columns=features)
     plateau_cluster = centers["scoreDelta"].idxmin()
     df["inferred_label"] = df["cluster"].apply(lambda c: PLATEAU_STR if c == plateau_cluster else LEARNING_STR)
-    plt.figure(figsize=(10, 6))
-    for label, color in zip([PLATEAU_STR, LEARNING_STR], ["red", "green"]):
-        subset = df[df["inferred_label"] == label]
-        plt.plot(subset["timestamp"], subset["scoreDelta"], label=label, color=color, alpha=0.6)
-    plt.title("Unsupervised Learning: Inferred Labels Over Time")
-    plt.xlabel("Timestamp (s)")
-    plt.ylabel("Score Delta")
-    plt.legend()
-    plt.grid(True)
-    plt.tight_layout()
-    plt.savefig(os.path.join(output_folder, "unsupervised_inferred_labels_over_time.png"))
-    plt.close()
+    # plt.figure(figsize=(10, 6))
+    # for label, color in zip([PLATEAU_STR, LEARNING_STR], ["red", "green"]):
+    #     subset = df[df["inferred_label"] == label]
+    #     plt.plot(subset["timestamp"], subset["scoreDelta"], label=label, color=color, alpha=0.6)
+    # plt.title("Unsupervised Learning: Inferred Labels Over Time")
+    # plt.xlabel("Timestamp (s)")
+    # plt.ylabel("Score Delta")
+    # plt.legend()
+    # plt.grid(True)
+    # plt.tight_layout()
+    # plt.savefig(os.path.join(output_folder, "unsupervised_inferred_labels_over_time.png"))
+    # plt.close()
+
 
 def compare_manual_vs_kmeans(df, output_folder):
     cm = confusion_matrix(df["label"], df["inferred_label"], labels=[PLATEAU_STR, LEARNING_STR])
@@ -101,11 +109,7 @@ def plot_decision_tree(X, y, feature_names, output_folder):
     plt.close()
 
 def plot_feature_evolution(df, output_folder):
-    features = [
-        "scoreDelta", "distanceDelta", "obstacleDelta", "explorationEfficiency",
-        "variationInDirection", "velocityMagnitude", "collectibleCollectEfficiency",
-        "obstacleAvoidanceEfficiency", "timeSinceLastCollectible", "timeSinceLastHitObstacle"
-    ]
+    features = FEATURES
     num_features = len(features)
     cols = 2
     rows = (num_features + 1) // cols
@@ -130,11 +134,7 @@ def main():
     df = extract_features_labels_from_logs(FOLDER_PATH_LOGS_TO_ANALYSE)
     run_unsupervised_clustering(df, FOLDER_PATH_SAVE_GRAPH_ANALYSIS)
     compare_manual_vs_kmeans(df, FOLDER_PATH_SAVE_GRAPH_ANALYSIS)
-    features = [
-        "scoreDelta", "distanceDelta", "obstacleDelta", "explorationEfficiency",
-        "variationInDirection", "velocityMagnitude", "collectibleCollectEfficiency",
-        "obstacleAvoidanceEfficiency", "timeSinceLastCollectible", "timeSinceLastHitObstacle"
-    ]
+    features = FEATURES
     X = df[features]
     y = df["inferred_label"]
     plot_decision_tree(X, y, features, FOLDER_PATH_SAVE_GRAPH_ANALYSIS)
diff --git a/SimulationGraph/Simulation-14-04-2025-10-14-58.json_full_analysis.png b/SimulationGraph/Simulation-14-04-2025-10-14-58.json_full_analysis.png
new file mode 100644
index 0000000000000000000000000000000000000000..f36204fc4d2e8fd0f674668ec576b71b5d7a2482
Binary files /dev/null and b/SimulationGraph/Simulation-14-04-2025-10-14-58.json_full_analysis.png differ
diff --git a/SimulationGraph/Simulation-14-04-2025-10-14-58.json_report.md b/SimulationGraph/Simulation-14-04-2025-10-14-58.json_report.md
new file mode 100644
index 0000000000000000000000000000000000000000..e8dedf7528c9d86b0a92998c8a59fa48977c059f
--- /dev/null
+++ b/SimulationGraph/Simulation-14-04-2025-10-14-58.json_report.md
@@ -0,0 +1,180 @@
+# Simulation report
+**File**: `Simulation-14-04-2025-10-14-58.json`  
+**Report generation date**: 2025-04-14 10:47:48  
+**Seed**: `723505677`  
+
+## Resume
+- Parcour length : **624.22** units
+- Collectibles collected : **41 / 41**
+- Obstacles hit : **8 / 43**
+- Distance made : **670.97** units (107.5%)
+
+## Performance over time
+-  Duration : **249.98 s**
+-  Speed average : **2.70 units/s**
+-  Time average between collectibles : **5.84 s**
+-  Time average between collisions : **38.14 s**
+
+## Efficacity
+- Collectibles : **100.00% (raw)** | **100.00% (smoothed)**
+- Obstacles : **81.40% (raw)** | **81.40% (smoothed)**
+- Exploration : **107.49% (raw)** | **107.43% (smoothed)**
+
+## Behaviour analysis
+- Directionnal variation (moving average) : **0.66 changes**
+  - Smooth and controlled exploration.
+
+## Parameters of the simulation
+- `Left` = **3.0**
+- `Large Left` = **5.0**
+- `Up` = **2.0**
+- `Right` = **5.0**
+- `Large Right` = **7.0**
+- `Down` = **3.0**
+- `Speed` = **0.0**
+- `Movement Sensibility` = **3.0**
+- `Rotation Sensibility` = **1.0**
+- `Obstacle Percentage` = **50.0**
+- `Collectible Preferences` = **2.0**
+- `Collectible Height` = **0.0**
+
+## Spawned elements
+### Road Parts
+- **Start 0** @ (-0.2, 0.0, 2.9)
+- **Straight 1** @ (-0.2, 0.0, 14.9)
+- **Straight 2** @ (-0.2, 0.0, 22.9)
+- **Straight 3** @ (-0.2, 0.0, 30.9)
+- **Straight 4** @ (-0.2, 0.0, 38.9)
+- **Right 5** @ (0.8, 0.0, 46.4)
+- **Up 6** @ (21.8, 0.0, 46.9)
+- **Right 7** @ (41.3, 8.0, 47.9)
+- **Up 8** @ (41.8, 8.0, 26.9)
+- **Straight 9** @ (43.8, 16.0, 6.9)
+- **Large Left 10** @ (45.8, 16.0, -5.1)
+- **Straight 11** @ (57.8, 16.0, -7.1)
+- **Large Left 12** @ (69.8, 16.0, -5.1)
+- **Straight 13** @ (71.8, 16.0, 6.9)
+- **Large Right 14** @ (73.8, 16.0, 18.9)
+- **Large Left 15** @ (89.8, 16.0, 22.9)
+- **Right 16** @ (92.8, 16.0, 34.4)
+- **Straight 17** @ (101.8, 16.0, 36.9)
+- **Straight 18** @ (109.8, 16.0, 36.9)
+- **Large Right 19** @ (121.8, 16.0, 34.9)
+- **Left 20** @ (125.0, 16.0, 22.6)
+- **Straight 21** @ (133.8, 16.0, 20.9)
+- **Large Right 22** @ (145.8, 16.0, 18.9)
+- **Straight 23** @ (147.8, 16.0, 6.9)
+- **Straight 24** @ (147.8, 16.0, -1.1)
+- **Large Right 25** @ (145.8, 16.0, -13.1)
+- **Left 26** @ (133.5, 16.0, -16.4)
+- **Straight 27** @ (131.8, 16.0, -25.1)
+- **Straight 28** @ (131.8, 16.0, -33.1)
+- **Straight 29** @ (131.8, 16.0, -41.1)
+- **Straight 30** @ (131.8, 16.0, -49.1)
+- **Down 31** @ (129.8, 7.8, -69.1)
+- **Large Left 32** @ (133.8, 8.0, -93.1)
+- **Straight 33** @ (145.8, 8.0, -95.1)
+- **Right 34** @ (153.3, 8.0, -96.1)
+- **Large Right 35** @ (153.8, 8.0, -109.1)
+- **Down 36** @ (129.8, -0.2, -109.1)
+- **Large Right 37** @ (105.8, 0.0, -109.1)
+- **Straight 38** @ (103.8, 0.0, -97.1)
+- **Straight 39** @ (103.8, 0.0, -89.1)
+- **Straight 40** @ (103.8, 0.0, -81.1)
+- **Right 41** @ (104.8, 0.0, -73.6)
+- **Large Right 42** @ (117.8, 0.0, -73.1)
+- **Large Left 43** @ (121.8, 0.0, -89.1)
+- **Straight 44** @ (133.8, 0.0, -91.1)
+- **Straight 45** @ (141.8, 0.0, -91.1)
+- **Straight 46** @ (149.8, 0.0, -91.1)
+- **Straight 47** @ (157.8, 0.0, -91.1)
+- **Straight 48** @ (165.8, 0.0, -91.1)
+- **Left 49** @ (174.0, 0.0, -89.9)
+- **Down 50** @ (177.8, -8.2, -69.1)
+- **End 51** @ (175.5, -8.0, -47.3)
+### Collectibles
+- **Cogwheel 0** @ (1.2, 0.7, 22.9)
+- **Cogwheel 1** @ (-1.3, 0.7, 30.9)
+- **Cogwheel 2** @ (1.2, 0.7, 38.9)
+- **Cogwheel 3** @ (1.7, 0.7, 47.3)
+- **Cogwheel 4** @ (31.7, 8.4, 50.2)
+- **Cogwheel 5** @ (41.2, 8.7, 46.1)
+- **Cogwheel 6** @ (42.5, 16.4, 17.0)
+- **Cogwheel 7** @ (45.1, 9.3, 36.8)
+- **Cogwheel 8** @ (45.1, 12.7, 26.9)
+- **Cogwheel 9** @ (43.6, 16.7, 6.9)
+- **Cogwheel 10** @ (57.8, 16.7, -7.3)
+- **Cogwheel 11** @ (70.7, 16.7, 6.9)
+- **Cogwheel 12** @ (75.3, 16.7, 16.7)
+- **Cogwheel 13** @ (78.7, 16.7, 19.2)
+- **Cogwheel 14** @ (90.2, 16.7, 28.9)
+- **Cogwheel 15** @ (84.9, 16.7, 21.4)
+- **Cogwheel 16** @ (94.5, 16.7, 34.3)
+- **Cogwheel 17** @ (119.6, 16.7, 33.4)
+- **Cogwheel 18** @ (115.3, 16.7, 35.3)
+- **Cogwheel 19** @ (124.3, 16.7, 22.1)
+- **Cogwheel 20** @ (147.6, 16.7, 6.9)
+- **Cogwheel 21** @ (148.9, 16.7, -1.1)
+- **Cogwheel 22** @ (147.4, 16.7, -7.0)
+- **Cogwheel 23** @ (135.6, 8.7, -91.3)
+- **Cogwheel 24** @ (138.7, 8.7, -95.8)
+- **Cogwheel 25** @ (145.8, 8.7, -96.5)
+- **Cogwheel 26** @ (152.3, 8.7, -106.9)
+- **Cogwheel 27** @ (150.2, 8.7, -111.6)
+- **Cogwheel 28** @ (119.8, 1.1, -109.8)
+- **Cogwheel 29** @ (107.2, 0.7, -108.6)
+- **Cogwheel 30** @ (106.5, 0.7, -73.7)
+- **Cogwheel 31** @ (116.4, 0.7, -73.6)
+- **Cogwheel 32** @ (112.2, 0.7, -70.3)
+- **Cogwheel 33** @ (118.1, 0.7, -78.0)
+- **Cogwheel 34** @ (126.7, 0.7, -91.8)
+- **Cogwheel 35** @ (120.2, 0.7, -84.2)
+- **Cogwheel 36** @ (133.8, 0.7, -90.0)
+- **Cogwheel 37** @ (141.8, 0.7, -90.0)
+- **Cogwheel 38** @ (157.8, 0.7, -91.3)
+- **Cogwheel 39** @ (174.5, -6.9, -59.1)
+- **Cogwheel 40** @ (177.0, 0.1, -79.0)
+### Obstacles
+- **Meteor 0** @ (-0.1, 0.0, 14.9)
+- **Meteor 1** @ (11.9, 0.7, 47.6)
+- **Meteor 2** @ (21.8, 4.1, 50.2)
+- **Meteor 3** @ (45.8, 16.0, -5.1)
+- **Meteor 4** @ (51.2, 16.0, -6.7)
+- **Meteor 5** @ (44.2, 16.0, -0.2)
+- **Meteor 6** @ (68.8, 16.0, -4.2)
+- **Meteor 7** @ (71.3, 16.0, 0.3)
+- **Meteor 8** @ (65.4, 16.0, -7.8)
+- **Meteor 9** @ (73.4, 16.0, 12.4)
+- **Meteor 10** @ (87.9, 16.0, 24.7)
+- **Meteor 11** @ (101.8, 16.0, 36.7)
+- **Meteor 12** @ (109.8, 16.0, 36.7)
+- **Meteor 13** @ (123.2, 16.0, 30.6)
+- **Meteor 14** @ (133.8, 16.0, 22.0)
+- **Meteor 15** @ (145.2, 16.0, 19.4)
+- **Meteor 16** @ (139.3, 16.0, 19.3)
+- **Meteor 17** @ (148.3, 16.0, 15.3)
+- **Meteor 18** @ (144.3, 16.0, -10.9)
+- **Meteor 19** @ (142.2, 16.0, -15.6)
+- **Meteor 20** @ (133.0, 16.0, -15.6)
+- **Meteor 21** @ (132.9, 16.0, -25.1)
+- **Meteor 22** @ (130.4, 16.0, -33.1)
+- **Meteor 23** @ (131.6, 16.0, -41.1)
+- **Meteor 24** @ (132.9, 16.0, -49.1)
+- **Meteor 25** @ (133.1, 8.4, -79.1)
+- **Meteor 26** @ (133.1, 15.4, -59.2)
+- **Meteor 27** @ (130.5, 11.8, -69.1)
+- **Meteor 28** @ (132.2, 8.0, -88.2)
+- **Meteor 29** @ (155.1, 8.0, -96.2)
+- **Meteor 30** @ (155.4, 8.0, -103.0)
+- **Meteor 31** @ (139.7, 7.4, -112.4)
+- **Meteor 32** @ (129.8, 3.8, -112.4)
+- **Meteor 33** @ (111.9, 0.0, -110.7)
+- **Meteor 34** @ (105.5, 0.0, -104.2)
+- **Meteor 35** @ (105.2, 0.0, -97.1)
+- **Meteor 36** @ (103.9, 0.0, -89.1)
+- **Meteor 37** @ (103.9, 0.0, -81.1)
+- **Meteor 38** @ (122.7, 0.0, -88.2)
+- **Meteor 39** @ (149.8, 0.0, -90.0)
+- **Meteor 40** @ (165.8, 0.0, -91.3)
+- **Meteor 41** @ (172.8, 0.0, -88.8)
+- **Meteor 42** @ (177.0, -4.2, -69.1)
\ No newline at end of file
diff --git a/SimulationGraph/graphMaker.py b/SimulationGraph/graphMaker.py
new file mode 100644
index 0000000000000000000000000000000000000000..0369d7899b2b26ef1650f14ba621cefd635fcbc0
--- /dev/null
+++ b/SimulationGraph/graphMaker.py
@@ -0,0 +1,76 @@
+import json
+import matplotlib.pyplot as plt
+import pandas as pd
+import sys
+import os
+
+SIMULATIONS_FOLDER_PATH = "impulse/Assets/SimulationLogs/"
+OUTPUT_FOLDER_PATH = "./SimulationGraph/"
+
+def plot_all_metrics(file_name):
+    with open(f"{SIMULATIONS_FOLDER_PATH}{file_name}", "r") as f:
+        data = json.load(f)
+
+    logs = data["logs"]
+    metadata = data.get("metadata", {})
+
+    df = pd.DataFrame(logs)
+    df["speed"] = df["velocity"].apply(lambda v: (v['x']**2 + v['y']**2 + v['z']**2)**0.5)
+
+    metrics = {
+        "Distance Since Last Frame": "distanceSinceLastFrame",
+        "Speed": "speed",
+        "Score Over Time": "currentScore",
+        "Average Time Between Collectibles": "averageTimeBetweenCollectibles",
+        "Collectible Efficiency (Raw)": "rawCollectibleEfficiency",
+        "Collectible Efficiency (Smoothed)": "collectibleCollectEfficiency",
+        "Obstacle Avoidance Efficiency (Raw)": "rawObstacleAvoidanceEfficiency",
+        "Obstacle Avoidance Efficiency (Smoothed)": "obstacleAvoidanceEfficiency",
+        "Exploration Efficiency (Raw)": "rawExplorationEfficiency",
+        "Exploration Efficiency (Smoothed)": "explorationEfficiency",
+        "Obstacles Hit Count": "obstaclesHitCount",
+        "Time Since Last Collectible": "timeSinceLastCollectible",
+        "Time Since Last Hit Obstacle": "timeSinceLastHitObstacle",
+        "Direction Variation": "variationInDirection",
+    }
+
+    num_plots = len(metrics)
+    cols = 2
+    rows = (num_plots + cols - 1) // cols
+
+    fig, axs = plt.subplots(rows, cols, figsize=(16, 5 * rows))
+    fig.suptitle(f"Simulation Analysis: {file_name} | Seed: {metadata.get('seed', 'N/A')}", fontsize=18)
+    axs = axs.flatten()
+
+    for i, (title, column) in enumerate(metrics.items()):
+        if column in df.columns:
+            axs[i].plot(df["timestamp"], df[column], label=title)
+            axs[i].set_title(title)
+            axs[i].set_xlabel("Time (s)")
+            axs[i].set_ylabel(column)
+            axs[i].legend()
+            axs[i].grid(True)
+        else:
+            axs[i].text(0.5, 0.5, f"{column} not found", ha='center', va='center')
+            axs[i].axis("off")
+
+    for j in range(i + 1, len(axs)):
+        axs[j].axis("off")
+
+    plt.tight_layout(rect=[0, 0.03, 1, 0.95])
+    output_path = os.path.join(OUTPUT_FOLDER_PATH, f"{file_name}_full_analysis.png")
+    plt.savefig(output_path)
+    print(f"Graph saved to: {output_path}")
+
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        print("Usage: python graphMaker.py <simulation_file.json>")
+        print(f"Note: The file should be in {SIMULATIONS_FOLDER_PATH} !")
+        sys.exit(1)
+
+    simulation_file = sys.argv[1]
+    if not os.path.exists(f"{SIMULATIONS_FOLDER_PATH}{simulation_file}"):
+        print(f"File not found: {SIMULATIONS_FOLDER_PATH}{simulation_file}")
+        sys.exit(1)
+
+    plot_all_metrics(simulation_file)
diff --git a/SimulationGraph/main.py b/SimulationGraph/main.py
deleted file mode 100644
index 8e7e64b53a185f1d58c070b412489f33f2d8893c..0000000000000000000000000000000000000000
--- a/SimulationGraph/main.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import json
-import matplotlib.pyplot as plt
-import pandas as pd
-import sys
-import os
-
-SIMULATIONS_FOLDER_PATH = "impulse/Assets/SimulationLogs/"
-OUTPUT_FOLDER_PATH = "./"
-
-def plot_simulation_analysis(file_name):
-    with open(f"{SIMULATIONS_FOLDER_PATH}{file_name}", "r") as f:
-        data = json.load(f)
-
-    logs = data["logs"]
-
-    df = pd.DataFrame(logs)
-
-    fig, axs = plt.subplots(3, 2, figsize=(15, 12))
-    fig.suptitle("Simulation Session Analysis", fontsize=16)
-
-    axs[0, 0].plot(df["timestamp"], df["totalDistance"], label="Total Distance", color="blue")
-    axs[0, 0].set_title("Total Distance Travelled")
-    axs[0, 0].set_xlabel("Time (s)")
-    axs[0, 0].set_ylabel("Distance (units)")
-    axs[0, 0].legend()
-
-    axs[0, 1].plot(df["timestamp"], df["currentScore"], label="Score", color="green")
-    axs[0, 1].set_title("Score Over Time")
-    axs[0, 1].set_xlabel("Time (s)")
-    axs[0, 1].set_ylabel("Score")
-    axs[0, 1].legend()
-
-    df["speed"] = df["velocity"].apply(lambda v: (v['x']**2 + v['y']**2 + v['z']**2)**0.5)
-    axs[1, 0].plot(df["timestamp"], df["speed"], label="Speed", color="orange")
-    axs[1, 0].set_title("Instantaneous Speed")
-    axs[1, 0].set_xlabel("Time (s)")
-    axs[1, 0].set_ylabel("Speed (units/s)")
-    axs[1, 0].legend()
-
-    axs[1, 1].plot(df["timestamp"], df["variationInDirection"], label="Direction Changes", color="purple")
-    axs[1, 1].set_title("Direction Variation (sliding window)")
-    axs[1, 1].set_xlabel("Time (s)")
-    axs[1, 1].set_ylabel("Changes")
-    axs[1, 1].legend()
-
-    axs[2, 0].plot(df["timestamp"], df["explorationEfficiency"], label="Exploration Efficiency", color="red")
-    axs[2, 0].set_title("Exploration Efficiency")
-    axs[2, 0].set_xlabel("Time (s)")
-    axs[2, 0].set_ylabel("Ratio (%)")
-    axs[2, 0].legend()
-
-    axs[2, 1].plot(df["timestamp"], df["obstaclesHitCount"], label="Obstacles Hit", color="brown")
-    axs[2, 1].set_title("Obstacles Hit Over Time")
-    axs[2, 1].set_xlabel("Time (s)")
-    axs[2, 1].set_ylabel("Count")
-    axs[2, 1].legend()
-
-    plt.tight_layout(rect=[0, 0.03, 1, 0.95])
-    output_path = f"{OUTPUT_FOLDER_PATH}{file_name}_simulation_analysis.png"
-    plt.savefig(output_path)
-    print(f"Graph saved to {output_path}")
-
-if __name__ == "__main__":
-    if len(sys.argv) != 2:
-        print("Usage: python main.py <simulation_file.json>")
-        print(f"Note: The file should be in {SIMULATIONS_FOLDER_PATH} !")
-        sys.exit(1)
-    
-    simulation_file = sys.argv[1]
-    if not os.path.exists(f"{SIMULATIONS_FOLDER_PATH}{simulation_file}"):
-        print(f"File not found: {SIMULATIONS_FOLDER_PATH}{simulation_file}")
-        sys.exit(1)
-
-    plot_simulation_analysis(simulation_file)
diff --git a/SimulationGraph/reportMaker.py b/SimulationGraph/reportMaker.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c607417ba41a904dd2eb938937d733fb664fc80
--- /dev/null
+++ b/SimulationGraph/reportMaker.py
@@ -0,0 +1,128 @@
+import json
+from datetime import datetime
+import os
+import sys
+import pandas as pd
+
+SIMULATIONS_FOLDER_PATH = "impulse/Assets/SimulationLogs/"
+OUTPUT_FOLDER_PATH = "./SimulationGraph/"
+
+def interpret_direction_variation(value):
+    if value < 0.3:
+        return "Very stable direction — almost no changes."
+    elif value < 0.7:
+        return "Smooth and controlled exploration."
+    elif value < 1.2:
+        return "Moderately active — some directional adjustments."
+    else:
+        return "High variation — chaotic or exploratory movement."
+
+def generate_md_report(file_name):
+    with open(f"{SIMULATIONS_FOLDER_PATH}{file_name}", "r") as f:
+        data = json.load(f)
+
+    logs = data["logs"]
+    metadata = data.get("metadata", {})
+    df = pd.DataFrame(logs)
+
+    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    seed = metadata.get("seed", "N/A")
+    parcour_length = metadata.get("totalParcourLength", 0.0)
+    total_collectibles = metadata.get("totalCollectibles", 0)
+    total_obstacles = metadata.get("totalObstacles", 0)
+
+    if not df.empty:
+        final_score = int(df["currentScore"].iloc[-1])
+        total_distance = df["distanceSinceLastFrame"].sum()
+        simulation_duration = df["timestamp"].iloc[-1]
+        mean_speed = df["velocity"].apply(lambda v: (v['x']**2 + v['y']**2 + v['z']**2)**0.5).mean()
+        avg_collectible_time = df["averageTimeBetweenCollectibles"].iloc[-1]
+        avg_time_between_hits = df["timeSinceLastHitObstacle"].mean()
+        variation_direction = df["variationInDirection"].mean()
+
+        raw_collectible_eff = df["rawCollectibleEfficiency"].iloc[-1]
+        smooth_collectible_eff = df["collectibleCollectEfficiency"].iloc[-1]
+        raw_avoid_eff = df["rawObstacleAvoidanceEfficiency"].iloc[-1]
+        smooth_avoid_eff = df["obstacleAvoidanceEfficiency"].iloc[-1]
+        raw_exploration_eff = df["rawExplorationEfficiency"].iloc[-1]
+        smooth_exploration_eff = df["explorationEfficiency"].iloc[-1]
+
+        hits = int(df["obstaclesHitCount"].iloc[-1])
+    else:
+        final_score = total_distance = simulation_duration = mean_speed = avg_collectible_time = 0
+        avg_time_between_hits = variation_direction = 0
+        raw_collectible_eff = smooth_collectible_eff = 0
+        raw_avoid_eff = smooth_avoid_eff = 0
+        raw_exploration_eff = smooth_exploration_eff = 0
+        hits = 0
+
+    direction_comment = interpret_direction_variation(variation_direction)
+
+    report_lines = [
+        f"# Simulation report",
+        f"**File**: `{file_name}`  ",
+        f"**Report generation date**: {now}  ",
+        f"**Seed**: `{seed}`  ",
+        "",
+        "## Resume",
+        f"- Parcour length : **{parcour_length:.2f}** units",
+        f"- Collectibles collected : **{final_score} / {total_collectibles}**",
+        f"- Obstacles hit : **{hits} / {total_obstacles}**",
+        f"- Distance made : **{total_distance:.2f}** units ({(total_distance/parcour_length)*100 if parcour_length else 0:.1f}%)",
+        "",
+        "## Performance over time",
+        f"-  Duration : **{simulation_duration:.2f} s**",
+        f"-  Speed average : **{mean_speed:.2f} units/s**",
+        f"-  Time average between collectibles : **{avg_collectible_time:.2f} s**",
+        f"-  Time average between collisions : **{avg_time_between_hits:.2f} s**",
+        "",
+        "## Efficacity",
+        f"- Collectibles : **{raw_collectible_eff:.2%} (raw)** | **{smooth_collectible_eff:.2%} (smoothed)**",
+        f"- Obstacles : **{raw_avoid_eff:.2%} (raw)** | **{smooth_avoid_eff:.2%} (smoothed)**",
+        f"- Exploration : **{raw_exploration_eff:.2%} (raw)** | **{smooth_exploration_eff:.2%} (smoothed)**",
+        "",
+        "## Behaviour analysis",
+        f"- Directionnal variation (moving average) : **{variation_direction:.2f} changes**",
+        f"  - {direction_comment}",
+        "",
+        "## Parameters of the simulation"
+    ]
+
+    for param in metadata.get("parameters", []):
+        report_lines.append(f"- `{param['name']}` = **{param['value']}**")
+
+    report_lines.append("")
+    report_lines.append("## Spawned elements")
+
+    def format_spawn_list(title, items):
+        section = [f"### {title}"]
+        if items:
+            for obj in items:
+                pos = obj["position"]
+                section.append(f"- **{obj['name']}** @ ({pos['x']:.1f}, {pos['y']:.1f}, {pos['z']:.1f})")
+        else:
+            section.append("_Nothing recorded._")
+        return section
+
+    report_lines.extend(format_spawn_list("Road Parts", metadata.get("roadParts", [])))
+    report_lines.extend(format_spawn_list("Collectibles", metadata.get("collectibles", [])))
+    report_lines.extend(format_spawn_list("Obstacles", metadata.get("obstacles", [])))
+
+    output_path = os.path.join(OUTPUT_FOLDER_PATH, f"{file_name}_report.md")
+    with open(output_path, "w", encoding="utf-8") as f:
+        f.write("\n".join(report_lines))
+
+    output_path
+
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        print("Usage: python reportMaker.py <simulation_file.json>")
+        print(f"Note: The file should be in {SIMULATIONS_FOLDER_PATH} !")
+        sys.exit(1)
+
+    simulation_file = sys.argv[1]
+    if not os.path.exists(f"{SIMULATIONS_FOLDER_PATH}{simulation_file}"):
+        print(f"File not found: {SIMULATIONS_FOLDER_PATH}{simulation_file}")
+        sys.exit(1)
+
+    generate_md_report(simulation_file)