diff --git a/main.py b/main.py
index b654579180d932ea6dd8c221132b9c79d60895b2..b5919fd21c06c22eaed6817c59c21475fc82b02f 100644
--- a/main.py
+++ b/main.py
@@ -1,3 +1,4 @@
+import hashlib
 import json
 import os
 import threading
@@ -293,6 +294,8 @@ def wr_get_config():
 # Loading functions #
 #####################
 
+widgetcache = {}
+
 def load_widget(widget_name: str, config_override: dict=None):
     # Get the widget properties from the config file
     widget_props = module_config.get(widget_name, {}).copy()
@@ -305,11 +308,24 @@ def load_widget(widget_name: str, config_override: dict=None):
         if (isinstance(v, int) or isinstance(v, float)) and k.startswith("scalable_"):
             widget_props[k.removeprefix("scalable_")] = v * PROP_WINDOW_SCALE
 
+    # Generate hash to store the widget in the cache
+    m = hashlib.md5()
+    m.update(widget_name.encode("utf8"))
+    m.update(encode_dict(widget_props).encode("utf8"))
+    widget_hash = m.hexdigest()
+
+    if widget_hash in widgetcache:
+        # If the widget is already in the cache, return it
+        widget = widgetcache[widget_hash]
+    else:
+        # Load the widget
+        widget = getattr(screenwidgets, widget_name)(widget_props, pygame)
+        # Add to cache
+        widgetcache[widget_hash] = widget
+
     # Add the pygame module to the widget properties
     widget_props["pygame"] = pygame
-
-    # Load the widget
-    return getattr(screenwidgets, widget_name)(widget_props)
+    return widget
 
 def load_pattern(pattern_name: str, leds: ILedString, config_override: dict=None):
     pattern_props = module_config.get(pattern_name, {}).copy()
diff --git a/module_defaults.json b/module_defaults.json
index 1e2c43471de2611374e8f1ed14a93e78b7e0ce00..ce60520674ca4c1a92265312c32d3c982df87c88 100644
--- a/module_defaults.json
+++ b/module_defaults.json
@@ -385,7 +385,7 @@
     "RainbowPattern": {
         "tick_rate": {
             "name": "Tick rate",
-            "description": "The delay between ticks (in ms). If negative, will only run once.",
+            "description": "The delay between ticks (in ms). Adjusting this will speed up or slow down the effect. If negative, will only run once.",
             "default": 10,
             "type": "integer"
         }
diff --git a/screenwidgets.py b/screenwidgets.py
index 284074faf591cda9f637ddbc0dc6267673cd7d5a..d586b0349d82d18f8b681d7f135c4d2a56d19875 100644
--- a/screenwidgets.py
+++ b/screenwidgets.py
@@ -23,7 +23,7 @@ class IWidget(metaclass=IWidgetMeta):
     """
     Interface for a widget which can be drawn on the screen
     """
-    def __init__(self, config: dict):
+    def __init__(self, config: dict, pygame):
         pass
     def draw(self, screen):
         pass
@@ -32,12 +32,12 @@ class DigitalClockWidget(IWidget):
     """
     A simple clock widget which displays the current time
     """
-    def __init__(self, config: dict):
+    def __init__(self, config: dict, pygame):
         # Call the parent constructor
-        super().__init__(config)
+        super().__init__(config, pygame)
 
         # Get the pygame module from the config
-        self.pygame = config['pygame']
+        self.pygame = pygame
 
         # Get the font path
         self.font_path = get_font_path_or_default(self.pygame, config.get("font_name", None), config.get("font_bold", False), config.get("font_italic", False))
@@ -83,9 +83,9 @@ class DigitalClockWidget(IWidget):
         screen.blit(text_surface, text_rect)
 
 class TestWidget(IWidget):
-    def __init__(self, config: dict):
-        super().__init__(config)
-        self.pygame = config['pygame']
+    def __init__(self, config: dict, pygame):
+        super().__init__(config, pygame)
+        self.pygame = pygame
         self.color = config.get("color", "white")
         self.bg_color = config.get("background_color", "black")
         self.text = config.get("text", "Hello, world!")
@@ -98,9 +98,9 @@ class TestWidget(IWidget):
         screen.blit(text_surface, text_rect)
 
 class AnalogClockWidget(IWidget):
-    def __init__(self, config: dict):
-        super().__init__(config)
-        self.pygame = config['pygame']
+    def __init__(self, config: dict, pygame):
+        super().__init__(config, pygame)
+        self.pygame = pygame
 
         # Set the colours
         self.background_color = config.get("background_color", "black")
@@ -200,9 +200,9 @@ class AnalogClockWidget(IWidget):
         self.clock_hand(screen, get_screen_centre(), self.hour_hand_length, hour * 30, self.hour_hand_thickness, self.hour_hand_color)
 
 class IPShowWidget(IWidget):
-    def __init__(self, config: dict):
-        super().__init__(config)
-        self.pygame = config['pygame']
+    def __init__(self, config: dict, pygame):
+        super().__init__(config, pygame)
+        self.pygame = pygame
 
         # Backgrounds
         self.background_color = config.get("background_color", "black")
@@ -244,9 +244,9 @@ class IPShowWidget(IWidget):
         screen.blit(text_surface_2, text_rect_2)
 
 class WeatherWidget(IWidget):
-    def __init__(self, config: dict):
-        super().__init__(config)
-        self.pygame = config['pygame']
+    def __init__(self, config: dict, pygame):
+        super().__init__(config, pygame)
+        self.pygame = pygame
 
         # Get the font path
         self.title_font_path = get_font_path_or_default(self.pygame, config.get("title_font_name", None),