diff --git a/Assets/Module/battery_module_mf_unity.fbx b/Assets/Module/battery_module_mf_unity.fbx
index edd71de..71da25d 100644
Binary files a/Assets/Module/battery_module_mf_unity.fbx and b/Assets/Module/battery_module_mf_unity.fbx differ
diff --git a/Assets/Module/dc_module.fbx b/Assets/Module/dc_module.fbx
index f4a0a60..8e82ce5 100644
Binary files a/Assets/Module/dc_module.fbx and b/Assets/Module/dc_module.fbx differ
diff --git a/Assets/Module/display_module.fbx b/Assets/Module/display_module.fbx
index 6adcb21..9130f9e 100644
Binary files a/Assets/Module/display_module.fbx and b/Assets/Module/display_module.fbx differ
diff --git a/Assets/Module/distance_sensor_module.fbx b/Assets/Module/distance_sensor_module.fbx
index 505210d..d4c1ad8 100644
Binary files a/Assets/Module/distance_sensor_module.fbx and b/Assets/Module/distance_sensor_module.fbx differ
diff --git a/Assets/Module/gripper_module_arm.fbx b/Assets/Module/gripper_module_arm.fbx
index 9f146a2..f2668d1 100644
Binary files a/Assets/Module/gripper_module_arm.fbx and b/Assets/Module/gripper_module_arm.fbx differ
diff --git a/Assets/Module/gripper_module_body.fbx b/Assets/Module/gripper_module_body.fbx
index b087e65..6e756a1 100644
Binary files a/Assets/Module/gripper_module_body.fbx and b/Assets/Module/gripper_module_body.fbx differ
diff --git a/Assets/Module/hub_module_eq_triangle_mmm.fbx b/Assets/Module/hub_module_eq_triangle_mmm.fbx
index 8a01b05..dc2d649 100644
Binary files a/Assets/Module/hub_module_eq_triangle_mmm.fbx and b/Assets/Module/hub_module_eq_triangle_mmm.fbx differ
diff --git a/Assets/Module/hub_module_mmmf.fbx b/Assets/Module/hub_module_mmmf.fbx
index 9675d6e..89ef027 100644
Binary files a/Assets/Module/hub_module_mmmf.fbx and b/Assets/Module/hub_module_mmmf.fbx differ
diff --git a/Assets/Module/hub_module_mmmf_unity.fbx b/Assets/Module/hub_module_mmmf_unity.fbx
index 71a0330..b969b6c 100644
Binary files a/Assets/Module/hub_module_mmmf_unity.fbx and b/Assets/Module/hub_module_mmmf_unity.fbx differ
diff --git a/Assets/Module/hub_module_mmmm.fbx b/Assets/Module/hub_module_mmmm.fbx
index cf0380f..a3f3d62 100644
Binary files a/Assets/Module/hub_module_mmmm.fbx and b/Assets/Module/hub_module_mmmm.fbx differ
diff --git a/Assets/Module/hub_module_right_triangle_mmf.fbx b/Assets/Module/hub_module_right_triangle_mmf.fbx
index 40cc010..42eb0c2 100644
Binary files a/Assets/Module/hub_module_right_triangle_mmf.fbx and b/Assets/Module/hub_module_right_triangle_mmf.fbx differ
diff --git a/Assets/Module/imu_module.fbx b/Assets/Module/imu_module.fbx
index e83c976..006ec46 100644
Binary files a/Assets/Module/imu_module.fbx and b/Assets/Module/imu_module.fbx differ
diff --git a/Assets/Module/power_module_rounded.fbx b/Assets/Module/power_module_rounded.fbx
index f275e55..66e66b0 100644
Binary files a/Assets/Module/power_module_rounded.fbx and b/Assets/Module/power_module_rounded.fbx differ
diff --git a/Assets/Module/servo_bend_module_arm.fbx b/Assets/Module/servo_bend_module_arm.fbx
index 0c5d311..651bf1e 100644
Binary files a/Assets/Module/servo_bend_module_arm.fbx and b/Assets/Module/servo_bend_module_arm.fbx differ
diff --git a/Assets/Module/servo_bend_module_body.fbx b/Assets/Module/servo_bend_module_body.fbx
index 9964af9..ed37347 100644
Binary files a/Assets/Module/servo_bend_module_body.fbx and b/Assets/Module/servo_bend_module_body.fbx differ
diff --git a/Assets/Module/servo_straight_module_arm.fbx b/Assets/Module/servo_straight_module_arm.fbx
index 6fc1e29..ed33cf9 100644
Binary files a/Assets/Module/servo_straight_module_arm.fbx and b/Assets/Module/servo_straight_module_arm.fbx differ
diff --git a/Assets/Module/servo_straight_module_body.fbx b/Assets/Module/servo_straight_module_body.fbx
index df5f83e..b83ce39 100644
Binary files a/Assets/Module/servo_straight_module_body.fbx and b/Assets/Module/servo_straight_module_body.fbx differ
diff --git a/Assets/Module/speaker2_module.fbx b/Assets/Module/speaker2_module.fbx
index efe9def..7cfc737 100644
Binary files a/Assets/Module/speaker2_module.fbx and b/Assets/Module/speaker2_module.fbx differ
diff --git a/Assets/ProgrammedMovements.meta b/Assets/ProgrammedMovements.meta
new file mode 100644
index 0000000..5c63780
--- /dev/null
+++ b/Assets/ProgrammedMovements.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 482781b67c03b448ba71ae05ddf4b82b
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ProgrammedMovements/Editor.meta b/Assets/ProgrammedMovements/Editor.meta
new file mode 100644
index 0000000..f12739f
--- /dev/null
+++ b/Assets/ProgrammedMovements/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b37c4fea096a34f9dac835964cbdaec9
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ProgrammedMovements/ProgrammedMovementsController.cs b/Assets/ProgrammedMovements/ProgrammedMovementsController.cs
new file mode 100644
index 0000000..0ce9743
--- /dev/null
+++ b/Assets/ProgrammedMovements/ProgrammedMovementsController.cs
@@ -0,0 +1,686 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEngine.EventSystems;
+using TMPro;
+
+///
+/// Controller for ProgrammedMovements view: timeline banner at bottom.
+/// 3 tracks, 0-10 seconds, movement blocks, Run button.
+///
+public class ProgrammedMovementsController : MonoBehaviour
+{
+ public const int TracksCount = 3;
+ public const int TimelineDurationSeconds = 10;
+ public static readonly Color HighlightBlue = new Color(0.2f, 0.5f, 1f, 1f);
+
+ [Header("References")]
+ public Camera mainCamera;
+ public RectTransform timelineRoot;
+ public Button runButton;
+
+ private RectTransform _bannerRoot;
+ private Transform _timelineView;
+ private Transform _configView;
+ private readonly List _blocks = new List();
+ private readonly Dictionary> _blocksBySecond = new Dictionary>();
+ private bool _isRunning;
+ private float _runStartTime;
+ private int _lastExecutedSecond = -1;
+ private float _lastRewireTime = -1f;
+ private ModuleBase _highlightedModule;
+ private readonly Dictionary _originalMaterialsByRenderer = new Dictionary();
+ private MovementBlock _pickModeBlock;
+ private MovementBlock _editingBlock;
+ private ModuleBase _pendingModule;
+
+ void OnEnable()
+ {
+ ResolveReferences();
+ if (_bannerRoot == null)
+ {
+ Debug.LogError("[ProgrammedMovements] timelineRoot not set. Assign it in the Inspector.");
+ return;
+ }
+ EnsureTimelineViewShown();
+ WireUpButtons();
+ RefreshRunButton();
+ // Force layout rebuild so block positions align with timeline after view switch
+ Canvas.ForceUpdateCanvases();
+ LayoutRebuilder.ForceRebuildLayoutImmediate(_bannerRoot);
+ }
+
+ void EnsureTimelineViewShown()
+ {
+ if (_timelineView != null) _timelineView.gameObject.SetActive(true);
+ if (_configView != null) _configView.gameObject.SetActive(false);
+ }
+
+ void ResolveReferences()
+ {
+ if (timelineRoot != null)
+ {
+ _bannerRoot = timelineRoot;
+ }
+ else
+ {
+ var pmView = transform.parent;
+ if (pmView == null) return;
+ var canvas = pmView.Find("ProgrammedMovementsCanvas");
+ if (canvas == null) return;
+ var banner = canvas.Find("TimelineBanner");
+ if (banner != null)
+ {
+ _bannerRoot = banner.GetComponent();
+ if (timelineRoot == null) timelineRoot = _bannerRoot;
+ }
+ }
+ if (_bannerRoot != null)
+ {
+ _timelineView = _bannerRoot.Find("TimelineView");
+ _configView = _bannerRoot.Find("ConfigView");
+ if (_timelineView == null)
+ {
+ _timelineView = _bannerRoot;
+ }
+ }
+ if (runButton == null && _bannerRoot != null)
+ {
+ var canvas = _bannerRoot.parent;
+ if (canvas != null)
+ {
+ var runGO = canvas.Find("RunButton");
+ if (runGO != null) runButton = runGO.GetComponent