diff --git a/Nodes/__pycache__/array_node.cpython-312.pyc b/Nodes/__pycache__/array_node.cpython-312.pyc
index aaf81b7..af5df88 100644
Binary files a/Nodes/__pycache__/array_node.cpython-312.pyc and b/Nodes/__pycache__/array_node.cpython-312.pyc differ
diff --git a/Nodes/__pycache__/comparison_node.cpython-312.pyc b/Nodes/__pycache__/comparison_node.cpython-312.pyc
index d49ae69..d2429cc 100644
Binary files a/Nodes/__pycache__/comparison_node.cpython-312.pyc and b/Nodes/__pycache__/comparison_node.cpython-312.pyc differ
diff --git a/Nodes/__pycache__/data_node.cpython-312.pyc b/Nodes/__pycache__/data_node.cpython-312.pyc
index be9ba52..29c8379 100644
Binary files a/Nodes/__pycache__/data_node.cpython-312.pyc and b/Nodes/__pycache__/data_node.cpython-312.pyc differ
diff --git a/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc b/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc
index 6b78cfb..d3efe3d 100644
Binary files a/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc and b/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc differ
diff --git a/Nodes/__pycache__/flyff_low_health_alert_node.cpython-312.pyc b/Nodes/__pycache__/flyff_low_health_alert_node.cpython-312.pyc
index cca471d..f6b97ce 100644
Binary files a/Nodes/__pycache__/flyff_low_health_alert_node.cpython-312.pyc and b/Nodes/__pycache__/flyff_low_health_alert_node.cpython-312.pyc differ
diff --git a/Nodes/__pycache__/math_operation_node.cpython-312.pyc b/Nodes/__pycache__/math_operation_node.cpython-312.pyc
index 75e12f5..50d15b8 100644
Binary files a/Nodes/__pycache__/math_operation_node.cpython-312.pyc and b/Nodes/__pycache__/math_operation_node.cpython-312.pyc differ
diff --git a/Nodes/array_node.py b/Nodes/array_node.py
index 5a4a26a..8f4e09e 100644
--- a/Nodes/array_node.py
+++ b/Nodes/array_node.py
@@ -5,8 +5,8 @@ class ArrayNode(BaseNode):
     Array Node:
       - Inputs: 'in' (value to store), 'ArraySize' (defines maximum length)
       - Output: 'Array' (the current array as a string)
-      - Stores incoming values in an array with size defined by ArraySize.
-        When full, it removes the oldest value.
+      - Stores incoming values in an array with a size defined by ArraySize.
+      - Updates are now handled via a global update timer.
     """
     __identifier__ = 'bunny-lab.io.array_node'
     NODE_NAME = 'Array'
diff --git a/Nodes/basic_nodes.py b/Nodes/basic_nodes.py
deleted file mode 100644
index 4d36de1..0000000
--- a/Nodes/basic_nodes.py
+++ /dev/null
@@ -1,86 +0,0 @@
-from OdenGraphQt import BaseNode, BaseNodeCircle
-
-
-class BasicNodeA(BaseNode):
-    """
-    A node class with 2 inputs and 2 outputs.
-    """
-
-    # unique node identifier.
-    __identifier__ = 'nodes.basic'
-
-    # initial default node name.
-    NODE_NAME = 'node A'
-
-    def __init__(self):
-        super(BasicNodeA, self).__init__()
-
-        # create node inputs.
-        self.add_input('in A')
-        self.add_input('in B')
-
-        # create node outputs.
-        self.add_output('out A')
-        self.add_output('out B')
-
-
-class BasicNodeB(BaseNode):
-    """
-    A node class with 3 inputs and 3 outputs.
-    The last input and last output can take in multiple pipes.
-    """
-
-    # unique node identifier.
-    __identifier__ = 'nodes.basic'
-
-    # initial default node name.
-    NODE_NAME = 'node B'
-
-    def __init__(self):
-        super(BasicNodeB, self).__init__()
-
-        # create node inputs
-        self.add_input('single 1')
-        self.add_input('single 2')
-        self.add_input('multi in', multi_input=True)
-
-        # create node outputs
-        self.add_output('single 1', multi_output=False)
-        self.add_output('single 2', multi_output=False)
-        self.add_output('multi out')
-
-
-class CircleNode(BaseNodeCircle):
-    """
-    A node class with 3 inputs and 3 outputs.
-    This node is a circular design.
-    """
-
-    # unique node identifier.
-    __identifier__ = 'nodes.basic'
-
-    # initial default node name.
-    NODE_NAME = 'Circle Node'
-
-    def __init__(self):
-        super(CircleNode, self).__init__()
-        self.set_color(10, 24, 38)
-
-        # create node inputs
-        p = self.add_input('in 1')
-        p.add_accept_port_type(
-            port_name='single 1',
-            port_type='out',
-            node_type='nodes.basic.BasicNodeB'
-        )
-
-        self.add_input('in 2')
-        self.add_input('in 3', multi_input=True)
-        self.add_input('in 4', display_name=False)
-        self.add_input('in 5', display_name=False)
-
-        # create node outputs
-        self.add_output('out 1')
-        self.add_output('out 2', multi_output=False)
-        self.add_output('out 3', multi_output=True, display_name=False)
-        self.add_output('out 4', multi_output=True, display_name=False)
\ No newline at end of file
diff --git a/Nodes/comparison_node.py b/Nodes/comparison_node.py
index deb52ab..34ad35a 100644
--- a/Nodes/comparison_node.py
+++ b/Nodes/comparison_node.py
@@ -1,15 +1,15 @@
 #!/usr/bin/env python3
+
 """
-Comparison Node:
-  - Inputs: Two input ports ("A" and "B").
-  - Output: One output port ("Result").
-  - Operation: A dropdown (combo menu) to select:
-      Equal (==), Not Equal (!=), Greater Than (>), Less Than (<),
-      Greater Than or Equal (>=), Less Than or Equal (<=).
-  - Displays the computed result in a read-only text box labeled "Result".
+Standardized Comparison Node:
+  - Compares two input values using a selected operator (==, !=, >, <, >=, <=).
+  - Outputs a result of 1 (True) or 0 (False).
+  - Uses a global update timer for processing.
+  - Supports an additional 'Input Type' dropdown to choose between 'Number' and 'String'.
 """
 
 from OdenGraphQt import BaseNode
+from Qt import QtCore
 
 class ComparisonNode(BaseNode):
     __identifier__ = 'bunny-lab.io.comparison_node'
@@ -17,112 +17,106 @@ class ComparisonNode(BaseNode):
 
     def __init__(self):
         super(ComparisonNode, self).__init__()
-
-        # ----------------------------------------------------------------------
-        # Initialization Section:
-        #   - Create two input ports: A, B
-        #   - Create one output port: Result
-        #   - Add a combo box for logical operator selection
-        #   - Add a text input for displaying the computed result
-        # ----------------------------------------------------------------------
         self.add_input('A')
         self.add_input('B')
         self.add_output('Result')
 
-        # Operator combo box (==, !=, >, <, >=, <=)
+        # Add the Input Type dropdown first.
+        self.add_combo_menu('input_type', 'Input Type', items=['Number', 'String'])
         self.add_combo_menu('operator', 'Operator', items=[
-            'Equal (==)', 
-            'Not Equal (!=)', 
-            'Greater Than (>)', 
-            'Less Than (<)', 
-            'Greater Than or Equal (>=)', 
-            'Less Than or Equal (<=)'
+            'Equal (==)', 'Not Equal (!=)', 'Greater Than (>)',
+            'Less Than (<)', 'Greater Than or Equal (>=)', 'Less Than or Equal (<=)'
         ])
-
-        # Text input for displaying the computed result.
-        # We'll make it read-only by accessing the underlying QLineEdit.
-        self.add_text_input('calc_result', 'Result', text='0')
-        result_widget = self.get_widget('calc_result')  # This is a NodeLineEdit wrapper
-        if result_widget:
-            # Get the underlying QLineEdit
-            line_edit = result_widget.get_custom_widget()
-            # Make the QLineEdit read-only
-            line_edit.setReadOnly(True)
-
+        # Replace calc_result with a standardized "value" text input.
+        self.add_text_input('value', 'Value', text='0')
         self.value = 0
         self.set_name("Comparison Node")
-        self.process_input()
+        self.processing = False  # Guard for process_input
 
-    def process_input(self, event=None):
-        """
-        Compute Section:
-          - For each input port (A, B), if connected, grab the 'value' from
-            the upstream node; otherwise default to 0.0.
-          - Convert to float when possible, apply the selected comparison operator,
-            update the "Result" text box, node title, and output port.
-        """
-        # Gather input A
+        # Set default properties explicitly
+        self.set_property('input_type', 'Number')
+        self.set_property('operator', 'Equal (==)')
+
+    def process_input(self):
+        if self.processing:
+            return
+        self.processing = True
+        
+        # Retrieve input values; if no connection or None, default to "0"
         input_a = self.input(0)
-        if input_a and input_a.connected_ports():
-            a_raw = input_a.connected_ports()[0].node().get_property('value')
-        else:
-            a_raw = 0.0
-
-        # Gather input B
         input_b = self.input(1)
-        if input_b and input_b.connected_ports():
-            b_raw = input_b.connected_ports()[0].node().get_property('value')
+        a_raw = (input_a.connected_ports()[0].node().get_property('value')
+                 if input_a.connected_ports() else "0")
+        b_raw = (input_b.connected_ports()[0].node().get_property('value')
+                 if input_b.connected_ports() else "0")
+        a_raw = a_raw if a_raw is not None else "0"
+        b_raw = b_raw if b_raw is not None else "0"
+        
+        # Get input type property
+        input_type = self.get_property('input_type')
+        
+        # Convert values based on input type
+        if input_type == 'Number':
+            try:
+                a_val = float(a_raw)
+            except (ValueError, TypeError):
+                a_val = 0.0
+            try:
+                b_val = float(b_raw)
+            except (ValueError, TypeError):
+                b_val = 0.0
+        elif input_type == 'String':
+            a_val = str(a_raw)
+            b_val = str(b_raw)
         else:
-            b_raw = 0.0
+            try:
+                a_val = float(a_raw)
+            except (ValueError, TypeError):
+                a_val = 0.0
+            try:
+                b_val = float(b_raw)
+            except (ValueError, TypeError):
+                b_val = 0.0
 
-        # Convert raw inputs to float if possible, otherwise keep as-is for string comparison.
-        try:
-            a_val = float(a_raw)
-            b_val = float(b_raw)
-        except (ValueError, TypeError):
-            a_val = a_raw
-            b_val = b_raw
-
-        # Retrieve the selected operator from the combo box.
         operator = self.get_property('operator')
-        result = False
-
-        if operator == 'Equal (==)':
-            result = a_val == b_val
-        elif operator == 'Not Equal (!=)':
-            result = a_val != b_val
-        elif operator == 'Greater Than (>)':
-            result = a_val > b_val
-        elif operator == 'Less Than (<)':
-            result = a_val < b_val
-        elif operator == 'Greater Than or Equal (>=)':
-            result = a_val >= b_val
-        elif operator == 'Less Than or Equal (<=)':
-            result = a_val <= b_val
-
-        # Convert boolean result to integer (1 for True, 0 for False)
-        self.value = 1 if result else 0
-
-        # Update the read-only text input and node title.
-        self.set_property('calc_result', str(self.value))
-
-        # Transmit the numeric result to any connected output nodes.
-        output_port = self.output(0)
-        if output_port and output_port.connected_ports():
-            for cp in output_port.connected_ports():
-                connected_node = cp.node()
-                if hasattr(connected_node, 'receive_data'):
-                    connected_node.receive_data(self.value, source_port_name='Result')
+        
+        # Perform the comparison
+        result = {
+            'Equal (==)': a_val == b_val,
+            'Not Equal (!=)': a_val != b_val,
+            'Greater Than (>)': a_val > b_val,
+            'Less Than (<)': a_val < b_val,
+            'Greater Than or Equal (>=)': a_val >= b_val,
+            'Less Than or Equal (<=)': a_val <= b_val
+        }.get(operator, False)
+        
+        new_value = 1 if result else 0
+        self.value = new_value
+        self.set_property('value', str(self.value))
+        self.transmit_data(self.value)
+        
+        self.processing = False
 
     def on_input_connected(self, input_port, output_port):
-        self.process_input()
+        pass
 
     def on_input_disconnected(self, input_port, output_port):
-        self.process_input()
+        pass
 
     def property_changed(self, property_name):
-        if property_name in ['operator']:
-            self.process_input()
+        pass
 
     def receive_data(self, data, source_port_name=None):
-        self.process_input()
+        pass
+
+    def transmit_data(self, data):
+        output_port = self.output(0)
+        if output_port and output_port.connected_ports():
+            for connected_port in output_port.connected_ports():
+                connected_node = connected_port.node()
+                if hasattr(connected_node, 'receive_data'):
+                    try:
+                        data_int = int(data)
+                        connected_node.receive_data(data_int, source_port_name='Result')
+                    except ValueError:
+                        pass
diff --git a/Nodes/data_node.py b/Nodes/data_node.py
index 1b1304b..6803833 100644
--- a/Nodes/data_node.py
+++ b/Nodes/data_node.py
@@ -1,21 +1,13 @@
 #!/usr/bin/env python3
 
 """
-Data Node:
-  - Input: Accepts a value (string, integer, or float) from an input port.
-  - Output: Outputs the current value, either from the input port or set manually via a text box.
-
-Behavior:
-- If both input and output are connected:
-  - Acts as a passthrough, displaying the input value and transmitting it to the output.
-  - Manual input is disabled.
-- If only the output is connected:
-  - Allows manual value entry, which is sent to the output.
-- If only the input is connected:
-  - Displays the input value but does not transmit it further.
+Standardized Data Node:
+  - Accepts and transmits values consistently.
+  - Updates its value based on a global update timer.
 """
 
 from OdenGraphQt import BaseNode
+from Qt import QtCore
 
 class DataNode(BaseNode):
     __identifier__ = 'bunny-lab.io.data_node'
@@ -23,103 +15,58 @@ class DataNode(BaseNode):
 
     def __init__(self):
         super(DataNode, self).__init__()
-        # Add input and output ports.
         self.add_input('Input')
         self.add_output('Output')
-        # Add a text input widget for manual entry.
         self.add_text_input('value', 'Value', text='')
-        # Initialize the value from the widget property.
         self.process_widget_event()
-        self.set_name(f"Data Node")
+        self.set_name("Data Node")
+        # Removed self-contained update timer; global timer now drives updates.
 
     def post_create(self):
-        """
-        Called after the node's widget is fully created.
-        Connect the text input widget's textChanged signal to process_widget_event.
-        """
         text_widget = self.get_widget('value')
         if text_widget is not None:
             try:
-                text_widget.textChanged.connect(self.process_widget_event)
+                # Removed textChanged signal connection; global timer will call process_input.
+                pass
             except Exception as e:
                 print("Error connecting textChanged signal:", e)
 
     def process_widget_event(self, event=None):
-        """
-        Reads the current text from the node's property and updates the node's internal value.
-        """
         current_text = self.get_property('value')
         self.value = current_text
+        self.transmit_data(current_text)
 
     def property_changed(self, property_name):
-        """
-        Called when a node property changes. If the 'value' property changes,
-        update the internal value.
-        """
         if property_name == 'value':
-            self.process_widget_event()
+            # Immediate update removed; relying on global timer.
+            pass
 
-    def update_stream(self):
-        """
-        Updates the node's behavior based on the connection states.
-        """
+    def process_input(self):
         input_port = self.input(0)
         output_port = self.output(0)
-
-        if input_port.connected_ports() and output_port.connected_ports():
-            # Both input and output are connected; act as passthrough.
-            self.set_property('value', '')
-            self.get_widget('value').setEnabled(False)
+        if input_port.connected_ports():
             input_value = input_port.connected_ports()[0].node().get_property('value')
             self.set_property('value', input_value)
+            self.transmit_data(input_value)
         elif output_port.connected_ports():
-            # Only output is connected; allow manual input.
-            self.get_widget('value').setEnabled(True)
-        elif input_port.connected_ports():
-            # Only input is connected; display input value.
-            self.get_widget('value').setEnabled(False)
-            input_value = input_port.connected_ports()[0].node().get_property('value')
-            self.set_property('value', input_value)
-        else:
-            # Neither input nor output is connected; allow manual input.
-            self.get_widget('value').setEnabled(True)
+            self.transmit_data(self.get_property('value'))
 
     def on_input_connected(self, input_port, output_port):
-        """
-        Called when an input port is connected.
-        """
-        self.update_stream()
+        # Removed immediate update; global timer handles updates.
+        pass
 
     def on_input_disconnected(self, input_port, output_port):
-        """
-        Called when an input port is disconnected.
-        """
-        self.update_stream()
-
-    def on_output_connected(self, output_port, input_port):
-        """
-        Called when an output port is connected.
-        """
-        self.update_stream()
-
-    def on_output_disconnected(self, output_port, input_port):
-        """
-        Called when an output port is disconnected.
-        """
-        self.update_stream()
+        # Removed immediate update; global timer handles updates.
+        pass
 
     def receive_data(self, data, source_port_name=None):
-        """
-        Receives data from connected nodes and updates the internal value.
-        """
-        self.set_property('value', str(data))  # Ensure it's always stored as a string
+        self.set_property('value', str(data))
+        self.transmit_data(data)
 
-        # Transmit data further if there's an output connection
+    def transmit_data(self, data):
         output_port = self.output(0)
         if output_port and output_port.connected_ports():
             for connected_port in output_port.connected_ports():
                 connected_node = connected_port.node()
                 if hasattr(connected_node, 'receive_data'):
-                    connected_node.receive_data(data, source_port_name)
-
-
+                    connected_node.receive_data(data, source_port_name="Output")
diff --git a/Nodes/flyff_character_status_node.py b/Nodes/flyff_character_status_node.py
index 9275104..3b7ded2 100644
--- a/Nodes/flyff_character_status_node.py
+++ b/Nodes/flyff_character_status_node.py
@@ -1,47 +1,23 @@
 #!/usr/bin/env python3
 
+"""
+Standardized Flyff Character Status Node:
+  - Polls an API for character stats and updates values dynamically.
+  - Uses a global update timer for processing.
+  - Immediately transmits updated values to connected nodes.
+"""
+
 from OdenGraphQt import BaseNode
-from Qt import QtCore, QtGui
+from Qt import QtCore
 import requests
 import traceback
 
-def get_draw_stat_port(color, border_color=None, alpha=127):
-    """
-    Returns a custom port painter function that draws a circular port with a
-    semi-transparent fill and then draws text (port label and current value)
-    next to it.
-    """
-    if border_color is None:
-        border_color = color
-
-    def painter_func(painter, rect, info):
-        painter.save()
-        pen = QtGui.QPen(QtGui.QColor(*border_color))
-        pen.setWidth(1.8)
-        painter.setPen(pen)
-        semi_transparent_color = QtGui.QColor(color[0], color[1], color[2], alpha)
-        painter.setBrush(semi_transparent_color)
-        painter.drawEllipse(rect)
-        port = info.get('port')
-        if port is not None:
-            node = port.node()
-            stat = port.name()
-            value = node.values.get(stat, "N/A") if hasattr(node, 'values') else "N/A"
-            text_rect = rect.adjusted(rect.width() + 4, 0, rect.width() + 70, 0)
-            painter.setPen(QtGui.QColor(0, 0, 0))
-            painter.drawText(text_rect, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft,
-                             f"{stat}: {value}")
-        painter.restore()
-    return painter_func
-
-class CharacterStatusNode(BaseNode):
+class FlyffCharacterStatusNode(BaseNode):
     __identifier__ = 'bunny-lab.io.flyff_character_status_node'
     NODE_NAME = 'Flyff - Character Status'
 
     def __init__(self):
-        super(CharacterStatusNode, self).__init__()
-
-        # Define exact expected keys to avoid transformation mismatches
+        super(FlyffCharacterStatusNode, self).__init__()
         self.values = {
             "HP: Current": "N/A", "HP: Total": "N/A",
             "MP: Current": "N/A", "MP: Total": "N/A",
@@ -49,97 +25,60 @@ class CharacterStatusNode(BaseNode):
             "EXP": "N/A"
         }
 
-        # Add output ports
-        self.add_output("HP: Current", painter_func=get_draw_stat_port((217, 36, 78)))
-        self.add_output("HP: Total", painter_func=get_draw_stat_port((217, 36, 78)))
-        self.add_output("MP: Current", painter_func=get_draw_stat_port((35, 124, 213)))
-        self.add_output("MP: Total", painter_func=get_draw_stat_port((35, 124, 213)))
-        self.add_output("FP: Current", painter_func=get_draw_stat_port((36, 197, 28)))
-        self.add_output("FP: Total", painter_func=get_draw_stat_port((36, 197, 28)))
-        self.add_output("EXP", painter_func=get_draw_stat_port((52, 195, 250)))
+        for stat in self.values.keys():
+            self.add_output(stat)
 
         self.set_name("Flyff - Character Status (API Disconnected)")
+        # Removed self-contained polling timer; global timer now drives updates.
 
-        # Start polling timer
-        self.timer = QtCore.QTimer()
-        self.timer.timeout.connect(self.poll_api)
-        self.timer.start(500)
-
-    def poll_api(self):
-        """
-        Polls the API endpoint to retrieve the latest character stats and updates
-        the node's internal values.
-        """
+    def process_input(self):
         try:
             response = requests.get("http://127.0.0.1:5000/data", timeout=1)
-            
             if response.status_code == 200:
                 data = response.json()
-
                 if isinstance(data, dict):
-                    try:
-                        for key, value in data.items():
-                            # Ensure the keys match the expected ones exactly
-                            formatted_key = {
-                                "hp_current": "HP: Current",
-                                "hp_total": "HP: Total",
-                                "mp_current": "MP: Current",
-                                "mp_total": "MP: Total",
-                                "fp_current": "FP: Current",
-                                "fp_total": "FP: Total",
-                                "exp": "EXP"
-                            }.get(key, key)  # Use mapping or fallback to raw key
-
-                            if formatted_key in self.values:
+                    mapping = {
+                        "hp_current": "HP: Current",
+                        "hp_total": "HP: Total",
+                        "mp_current": "MP: Current",
+                        "mp_total": "MP: Total",
+                        "fp_current": "FP: Current",
+                        "fp_total": "FP: Total",
+                        "exp": "EXP"
+                    }
+                    updated = False
+                    for key, value in data.items():
+                        if key in mapping:
+                            formatted_key = mapping[key]
+                            if str(value) != self.values.get(formatted_key, None):
                                 self.values[formatted_key] = str(value)
-                            else:
-                                print(f"[WARNING] Unexpected API key: {key} (not mapped)")
-
+                                updated = True
+                    if updated:
                         self.set_name("Flyff - Character Status (API Connected)")
-                        self.update()
                         self.transmit_data()
-
-                    except Exception as e:
-                        print("[ERROR] Error processing API response data:", e)
-                        print("[ERROR] Stack Trace:\n", traceback.format_exc())
                 else:
                     print("[ERROR] Unexpected API response format (not a dict):", data)
                     self.set_name("Flyff - Character Status (API Disconnected)")
-
             else:
                 print(f"[ERROR] API request failed with status code {response.status_code}")
                 self.set_name("Flyff - Character Status (API Disconnected)")
-
         except Exception as e:
             self.set_name("Flyff - Character Status (API Disconnected)")
             print("[ERROR] Error polling API in CharacterStatusNode:", str(e))
-            print("[ERROR] Stack Trace:\n", traceback.format_exc())
 
     def transmit_data(self):
-        """
-        Sends the updated character stats to connected nodes.
-        """
         for stat, value in self.values.items():
-            try:
-                port = self.get_output(stat)
-                
-                if port is None:
-                    print(f"[ERROR] Port '{stat}' not found in node outputs. Skipping...")
-                    continue
-
-                if port.connected_ports():
-                    for connected_port in port.connected_ports():
-                        connected_node = connected_port.node()
-                        if hasattr(connected_node, 'receive_data'):
-                            try:
-                                connected_node.receive_data(value, stat)
-                            except Exception as e:
-                                print(f"[ERROR] Error transmitting data to {connected_node}: {e}")
-                                print("[ERROR] Stack Trace:\n", traceback.format_exc())
-                        else:
-                            print(f"[WARNING] Connected node {connected_node} does not have receive_data method.")
-
-            except Exception as e:
-                print(f"[ERROR] Error while handling port {stat}: {e}")
-                print("[ERROR] Stack Trace:\n", traceback.format_exc())
+            port = self.get_output(stat)
+            if port and port.connected_ports():
+                for connected_port in port.connected_ports():
+                    connected_node = connected_port.node()
+                    if hasattr(connected_node, 'receive_data'):
+                        try:
+                            connected_node.receive_data(value, stat)
+                        except Exception as e:
+                            print(f"[ERROR] Error transmitting data to {connected_node}: {e}")
+                            print("[ERROR] Stack Trace:\n", traceback.format_exc())
 
+    def receive_data(self, data, source_port_name=None):
+        # This node only transmits data; it does not receive external data.
+        pass
diff --git a/Nodes/flyff_low_health_alert_node.py b/Nodes/flyff_low_health_alert_node.py
index 2aa0b1d..699e1bd 100644
--- a/Nodes/flyff_low_health_alert_node.py
+++ b/Nodes/flyff_low_health_alert_node.py
@@ -1,177 +1,133 @@
-import time
-import sys
-from OdenGraphQt import BaseNode
-from Qt import QtWidgets, QtCore, QtGui
+#!/usr/bin/env python3
+
+"""
+Standardized Flyff Low Health Alert Node:
+  - Monitors an input value (1 = health alert, 0 = normal).
+  - Displays a visual alert and plays a sound if enabled.
+  - Uses a global update timer for processing.
+  - Automatically processes float, int, and string values.
+"""
+
+import time
+from OdenGraphQt import BaseNode
+from Qt import QtCore, QtWidgets, QtGui
 
-# Attempt to import winsound (Windows-only)
 try:
     import winsound
     HAS_WINSOUND = True
 except ImportError:
     HAS_WINSOUND = False
 
-
 class OverlayCanvas(QtWidgets.QWidget):
     """
     UI overlay for displaying a red warning box, which can be repositioned by dragging.
     """
-
     def __init__(self, parent=None):
         super().__init__(parent)
-
-        # **Full-screen overlay**
         screen_geo = QtWidgets.QApplication.primaryScreen().geometry()
-        self.setGeometry(screen_geo)  # Set to full screen
-
+        self.setGeometry(screen_geo)
         self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
         self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
-        self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
-        self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent, False)
-        self.setAttribute(QtCore.Qt.WA_AlwaysStackOnTop, True)
-
-        # **Draggable Low Health Alert**
-        self.helper_LowHealthAlert = QtCore.QRect(250, 300, 900, 35)  # Default Position
+        self.setVisible(False)
+        self.helper_LowHealthAlert = QtCore.QRect(250, 300, 900, 35)
         self.dragging = False
-        self.drag_offset = QtCore.QPoint()
-
-        self.setVisible(False)  # Initially hidden
+        self.drag_offset = None
 
     def paintEvent(self, event):
-        """Draw the helper overlay objects."""
         if not self.isVisible():
-            return  # Don't draw anything if invisible
-
+            return
         painter = QtGui.QPainter(self)
         painter.setPen(QtCore.Qt.NoPen)
-        painter.setBrush(QtGui.QColor(255, 0, 0))  # Solid red rectangle
+        painter.setBrush(QtGui.QColor(255, 0, 0))
         painter.drawRect(self.helper_LowHealthAlert)
-
-        # Draw bold white text centered within the rectangle
         font = QtGui.QFont("Arial", 14, QtGui.QFont.Bold)
         painter.setFont(font)
         painter.setPen(QtGui.QColor(255, 255, 255))
-
-        text = "LOW HEALTH"
-        metrics = QtGui.QFontMetrics(font)
-        text_width = metrics.horizontalAdvance(text)
-        text_height = metrics.height()
-        text_x = self.helper_LowHealthAlert.center().x() - text_width // 2
-        text_y = self.helper_LowHealthAlert.center().y() + text_height // 4
-
-        painter.drawText(text_x, text_y, text)
+        text_x = self.helper_LowHealthAlert.center().x() - 50
+        text_y = self.helper_LowHealthAlert.center().y() + 5
+        painter.drawText(text_x, text_y, "LOW HEALTH")
 
     def toggle_alert(self, state):
-        """
-        Show or hide the overlay based on the state (1 = show, 0 = hide).
-        """
         self.setVisible(state == 1)
         self.update()
 
     def mousePressEvent(self, event):
-        """Detect clicks inside the red box and allow dragging."""
-        if event.button() == QtCore.Qt.LeftButton and self.helper_LowHealthAlert.contains(event.pos()):
-            self.dragging = True
-            self.drag_offset = event.pos() - self.helper_LowHealthAlert.topLeft()
+        if event.button() == QtCore.Qt.LeftButton:
+            if self.helper_LowHealthAlert.contains(event.pos()):
+                self.dragging = True
+                self.drag_offset = event.pos() - self.helper_LowHealthAlert.topLeft()
+        super().mousePressEvent(event)
 
     def mouseMoveEvent(self, event):
-        """Handle dragging movement."""
         if self.dragging:
-            new_x = event.pos().x() - self.drag_offset.x()
-            new_y = event.pos().y() - self.drag_offset.y()
-            self.helper_LowHealthAlert.moveTopLeft(QtCore.QPoint(new_x, new_y))
+            new_top_left = event.pos() - self.drag_offset
+            self.helper_LowHealthAlert.moveTo(new_top_left)
             self.update()
+        super().mouseMoveEvent(event)
 
     def mouseReleaseEvent(self, event):
-        """Stop dragging when the mouse button is released."""
-        self.dragging = False
-
+        if event.button() == QtCore.Qt.LeftButton:
+            self.dragging = False
+        super().mouseReleaseEvent(event)
 
 class FlyffLowHealthAlertNode(BaseNode):
-    """
-    Custom OdenGraphQt node that toggles a visual alert overlay and plays a beep when health is low.
-    """
-
     __identifier__ = 'bunny-lab.io.flyff_low_health_alert_node'
     NODE_NAME = 'Flyff - Low Health Alert'
 
-    overlay_instance = None  # Shared overlay instance
-    last_beep_time = 0  # Time tracking for beep interval
-    BEEP_INTERVAL_SECONDS = 2  # Beep every 2 seconds
+    overlay_instance = None
+    last_beep_time = 0
+    BEEP_INTERVAL_SECONDS = 2
 
     def __init__(self):
         super(FlyffLowHealthAlertNode, self).__init__()
-
-        # Create checkboxes to decide which kind of alert(s) to utilize
         self.add_checkbox('cb_1', '', 'Sound Alert', True)
         self.add_checkbox('cb_2', '', 'Visual Alert', True)
-
-        # Create Input Port
         self.add_input('Toggle (1 = On | 0 = Off)', color=(200, 100, 0))
-
-        # Add text input widget to display received value
         self.add_text_input('value', 'Current Value', text='0')
+        self.add_combo_menu('beep_interval', 'Beep Interval', items=["0.5s", "1.0s", "2.0s"])
 
-        # Ensure only one overlay instance exists
         if not FlyffLowHealthAlertNode.overlay_instance:
             FlyffLowHealthAlertNode.overlay_instance = OverlayCanvas()
             FlyffLowHealthAlertNode.overlay_instance.show()
 
     def process_input(self):
-        """
-        This function runs every 500ms (via the global update loop).
-        It updates the displayed value and toggles the alert if needed.
-        """
         input_port = self.input(0)
+        value = input_port.connected_ports()[0].node().get_property('value') if input_port.connected_ports() else "0"
+        self.receive_data(value)
 
-        # If there is a connected node, fetch its output value
-        if input_port.connected_ports():
-            connected_node = input_port.connected_ports()[0].node()
-            if hasattr(connected_node, 'get_property'):
-                value = connected_node.get_property('value')
-            else:
-                value = "0"
-        else:
-            value = "0"  # Default to zero if nothing is connected
-
+    def receive_data(self, data, source_port_name=None):
         try:
-            input_value = int(value)  # Ensure we interpret input as an integer (0 or 1)
+            if isinstance(data, str):
+                data = float(data) if '.' in data else int(data)
+            if isinstance(data, (float, int)):
+                data = 1 if data > 1 else 0 if data <= 0 else int(data)
+            else:
+                data = 0
         except ValueError:
-            input_value = 0  # Default to off if the input is not valid
+            data = 0
 
-        # Update the value display box
-        self.set_property('value', str(input_value))
-
-        # Check if the "Visual Alert" checkbox is enabled
-        visual_alert_enabled = self.get_property('cb_2')
-
-        # Ensure that if "Visual Alert" is unchecked, the overlay is always hidden
-        if not visual_alert_enabled:
-            FlyffLowHealthAlertNode.overlay_instance.toggle_alert(0)
-        else:
-            FlyffLowHealthAlertNode.overlay_instance.toggle_alert(input_value)
-
-        # Check if "Sound Alert" is enabled and beep if necessary
-        self.handle_beep(input_value)
+        self.set_property('value', str(data))
+        if self.get_property('cb_2'):
+            FlyffLowHealthAlertNode.overlay_instance.toggle_alert(data)
+        self.handle_beep(data)
 
     def handle_beep(self, input_value):
-        """
-        Plays a beep sound every 2 seconds when the value is `1` and "Sound Alert" is enabled.
-        """
-        sound_alert_enabled = self.get_property('cb_1')
-        current_time = time.time()
+        # Update beep interval from the dropdown property
+        interval_str = self.get_property('beep_interval')
+        if interval_str.endswith("s"):
+            interval_seconds = float(interval_str[:-1])
+        else:
+            interval_seconds = float(interval_str)
+        self.BEEP_INTERVAL_SECONDS = interval_seconds
 
-        if input_value == 1 and sound_alert_enabled:
-            if (current_time - FlyffLowHealthAlertNode.last_beep_time) >= FlyffLowHealthAlertNode.BEEP_INTERVAL_SECONDS:
+        if input_value == 1 and self.get_property('cb_1'):
+            current_time = time.time()
+            if (current_time - FlyffLowHealthAlertNode.last_beep_time) >= self.BEEP_INTERVAL_SECONDS:
                 FlyffLowHealthAlertNode.last_beep_time = current_time
                 self.play_beep()
-        else:
-            FlyffLowHealthAlertNode.last_beep_time = 0  # Reset when health is safe
 
     def play_beep(self):
-        """
-        Plays a beep using `winsound.Beep` (Windows) or prints a terminal bell (`\a`).
-        """
         if HAS_WINSOUND:
-            winsound.Beep(376, 100)  # 376 Hz, 100ms duration
+            winsound.Beep(376, 100)
         else:
-            print('\a', end='')  # Terminal bell for non-Windows systems
+            print('\a', end='')
diff --git a/Nodes/math_operation_node.py b/Nodes/math_operation_node.py
index 149b895..1aea0fa 100644
--- a/Nodes/math_operation_node.py
+++ b/Nodes/math_operation_node.py
@@ -1,14 +1,15 @@
 #!/usr/bin/env python3
+
 """
-Math Operation Node:
-  - Inputs: Two input ports ("A" and "B").
-  - Output: One output port ("Result").
-  - Operation: A dropdown (combo menu) to select:
-      Add, Subtract, Multiply, Divide, Average.
-  - Displays the computed result in a read-only text box labeled "Result".
+Standardized Math Operation Node:
+  - Performs mathematical operations (+, -, *, /, avg) on two inputs.
+  - Outputs the computed result.
+  - Uses a global update timer for processing (defined in borealis.py).
+  - Ensures it always has a "value" property that the Comparison Node can read.
 """
 
 from OdenGraphQt import BaseNode
+from Qt import QtCore
 
 class MathOperationNode(BaseNode):
     __identifier__ = 'bunny-lab.io.math_node'
@@ -16,60 +17,38 @@ class MathOperationNode(BaseNode):
 
     def __init__(self):
         super(MathOperationNode, self).__init__()
-
-        # ----------------------------------------------------------------------
-        # Initialization Section:
-        #   - Create two input ports: A, B
-        #   - Create one output port: Result
-        #   - Add a combo box for operator selection
-        #   - Add a text input for displaying the computed result
-        # ----------------------------------------------------------------------
         self.add_input('A')
         self.add_input('B')
         self.add_output('Result')
-
-        # Operator combo box (Add, Subtract, Multiply, Divide, Average)
+        
+        # Drop-down to choose which operation we do:
         self.add_combo_menu('operator', 'Operator', items=[
             'Add', 'Subtract', 'Multiply', 'Divide', 'Average'
         ])
 
-        # Text input for displaying the computed result.
-        # We'll make it read-only by accessing the underlying QLineEdit.
+        # A text field for showing the result to the user:
         self.add_text_input('calc_result', 'Result', text='0')
-        result_widget = self.get_widget('calc_result')  # This is a NodeLineEdit wrapper
-        if result_widget:
-            # Get the underlying QLineEdit
-            line_edit = result_widget.get_custom_widget()
-            # Make the QLineEdit read-only
-            line_edit.setReadOnly(True)
 
+        # IMPORTANT: define a "value" property that the Comparison Node can read
+        # We do not necessarily need a text input for it, but adding it ensures
+        # it becomes an official property recognized by OdenGraphQt.
+        self.add_text_input('value', 'Internal Value', text='0')
+
+        # Keep a Python-side float of the current computed result:
         self.value = 0
+
+        # Give the node a nice name:
         self.set_name("Math Operation")
-        self.process_input()
 
-    def process_input(self, event=None):
-        """
-        Compute Section:
-          - For each input port (A, B), if connected, grab the 'value' from
-            the upstream node; otherwise default to 0.0.
-          - Convert to float, apply the selected operation from the combo box,
-            update the "Result" text box, node title, and output port.
-        """
-        # Gather input A
+        # Removed self-contained timer; global timer calls process_input().
+
+    def process_input(self):
+        # Attempt to read "value" from both inputs:
         input_a = self.input(0)
-        if input_a and input_a.connected_ports():
-            a_raw = input_a.connected_ports()[0].node().get_property('value')
-        else:
-            a_raw = 0.0
-
-        # Gather input B
         input_b = self.input(1)
-        if input_b and input_b.connected_ports():
-            b_raw = input_b.connected_ports()[0].node().get_property('value')
-        else:
-            b_raw = 0.0
+        a_raw = input_a.connected_ports()[0].node().get_property('value') if input_a.connected_ports() else "0"
+        b_raw = input_b.connected_ports()[0].node().get_property('value') if input_b.connected_ports() else "0"
 
-        # Convert raw inputs to floats (default 0.0 on failure).
         try:
             a_val = float(a_raw)
         except (ValueError, TypeError):
@@ -79,10 +58,7 @@ class MathOperationNode(BaseNode):
         except (ValueError, TypeError):
             b_val = 0.0
 
-        # Retrieve the selected operator from the combo box.
         operator = self.get_property('operator')
-        result = 0.0
-
         if operator == 'Add':
             result = a_val + b_val
         elif operator == 'Subtract':
@@ -93,30 +69,41 @@ class MathOperationNode(BaseNode):
             result = a_val / b_val if b_val != 0 else 0.0
         elif operator == 'Average':
             result = (a_val + b_val) / 2.0
+        else:
+            result = 0.0
 
-        self.value = result
+        # If the computed result changed, update our internal properties and transmit
+        if self.value != result:
+            self.value = result
 
-        # Update the read-only text input and node title.
-        self.set_property('calc_result', str(result))
+            # Update the two text fields so the user sees the numeric result:
+            self.set_property('calc_result', str(result))
+            self.set_property('value', str(result))  # <= This is the critical step
 
-        # Transmit the numeric result to any connected output nodes.
-        output_port = self.output(0)
-        if output_port and output_port.connected_ports():
-            for cp in output_port.connected_ports():
-                connected_node = cp.node()
-                if hasattr(connected_node, 'receive_data'):
-                    connected_node.receive_data(result, source_port_name='Result')
+            # Let downstream nodes know there's new data:
+            self.transmit_data(result)
 
     def on_input_connected(self, input_port, output_port):
-        self.process_input()
+        pass
 
     def on_input_disconnected(self, input_port, output_port):
-        self.process_input()
+        pass
 
     def property_changed(self, property_name):
-        if property_name in ['operator']:
-            self.process_input()
+        pass
 
     def receive_data(self, data, source_port_name=None):
-        self.process_input()
+        pass
 
+    def transmit_data(self, data):
+        output_port = self.output(0)
+        if output_port and output_port.connected_ports():
+            for connected_port in output_port.connected_ports():
+                connected_node = connected_port.node()
+                if hasattr(connected_node, 'receive_data'):
+                    try:
+                        # Attempt to convert to int if possible, else float
+                        data_int = int(data)
+                        connected_node.receive_data(data_int, source_port_name='Result')
+                    except ValueError:
+                        connected_node.receive_data(data, source_port_name='Result')
diff --git a/borealis.py b/borealis.py
index 1f8eb20..8aff9c5 100644
--- a/borealis.py
+++ b/borealis.py
@@ -1,27 +1,27 @@
 #!/usr/bin/env python3
 
-## --- Patch QGraphicsScene.setSelectionArea to handle selection arguments ---
-#from Qt import QtWidgets, QtCore, QtGui
-#
-#_original_setSelectionArea = QtWidgets.QGraphicsScene.setSelectionArea
-#
-#def _patched_setSelectionArea(self, painterPath, second_arg, *args, **kwargs):
-#    try:
-#        # Try calling the original method with the provided arguments.
-#        return _original_setSelectionArea(self, painterPath, second_arg, *args, **kwargs)
-#    except TypeError as e:
-#        # If a TypeError is raised, assume the call was made with only a QPainterPath
-#        # and an ItemSelectionMode, and patch it by supplying defaults.
-#        # Default operation: ReplaceSelection, default transform: QTransform()
-#        return _original_setSelectionArea(self, painterPath,
-#                                          QtCore.Qt.ReplaceSelection,
-#                                          second_arg,
-#                                          QtGui.QTransform())
-#
-## Monkey-patch the setSelectionArea method.
-#QtWidgets.QGraphicsScene.setSelectionArea = _patched_setSelectionArea
-#
-## --- End of patch section ---
+# --- Patch QGraphicsScene.setSelectionArea to handle selection arguments ---
+from Qt import QtWidgets, QtCore, QtGui
+
+_original_setSelectionArea = QtWidgets.QGraphicsScene.setSelectionArea
+
+def _patched_setSelectionArea(self, painterPath, second_arg, *args, **kwargs):
+    try:
+        # Try calling the original method with the provided arguments.
+        return _original_setSelectionArea(self, painterPath, second_arg, *args, **kwargs)
+    except TypeError as e:
+        # If a TypeError is raised, assume the call was made with only a QPainterPath
+        # and an ItemSelectionMode, and patch it by supplying defaults.
+        # Default operation: ReplaceSelection, default transform: QTransform()
+        return _original_setSelectionArea(self, painterPath,
+                                          QtCore.Qt.ReplaceSelection,
+                                          second_arg,
+                                          QtGui.QTransform())
+
+# Monkey-patch the setSelectionArea method.
+QtWidgets.QGraphicsScene.setSelectionArea = _patched_setSelectionArea
+
+# --- End of patch section ---
 
 import sys
 import pkgutil
@@ -92,7 +92,6 @@ if __name__ == '__main__':
     graph.widget.show()
 
     # Global update timer:
-    #  - Call process_input() on every node that implements it.
     def global_update():
         for node in graph.all_nodes():
             if hasattr(node, "process_input"):
@@ -104,5 +103,4 @@ if __name__ == '__main__':
     timer.timeout.connect(global_update)
     timer.start(500)
 
-    sys.exit(app.exec())
-
+    sys.exit(app.exec())
\ No newline at end of file
diff --git a/debug_processed.png b/debug_processed.png
new file mode 100644
index 0000000..41a544d
Binary files /dev/null and b/debug_processed.png differ
diff --git a/debug_screenshot.png b/debug_screenshot.png
new file mode 100644
index 0000000..fb57647
Binary files /dev/null and b/debug_screenshot.png differ