Skip to content

Upload Labs - Suggestions

1. Expose Window/Node Metadata in Data.windows

Section titled “1. Expose Window/Node Metadata in Data.windows”

Problem: To build the wire-drop node picker, we had to load and instantiate every window scene to discover what connectors it has.

Current workaround: Load scene → instantiate → scan for ResourceContainers → get connector info → free instance

Suggestion: Pre-compute metadata in Data.windows:

Data.windows["compiler"] = {
"scene": "window_compiler",
"category": "processing",
"inputs": [{"shape": "square", "color": "lime", "resource": "code"}],
"outputs": [{"shape": "circle", "color": "orange", "resource": "file"}],
"max_count": -1, # -1 = unlimited
}

Problem: Had to infer when wire was dropped on empty canvas from Signals.connection_droppped and check if connection was actually made.

Suggestion: Add explicit signals:

signal connection_drag_started(origin_id: String, connection_type: int)
signal connection_cancelled(origin_id: String, connection_type: int, position: Vector2) # Wire dropped on empty canvas
signal connection_preview(origin_id: String, target_id: String) # Hovering over valid target

3. Expose ResourceContainer Connector Type

Section titled “3. Expose ResourceContainer Connector Type”

Problem: Had to search for child nodes named “InputConnector”/“OutputConnector” to determine if a pin is input or output.

Suggestion: Add direct properties to ResourceContainer:

@export var connector_type: int # Utils.connections_types.INPUT or OUTPUT or BOTH
func is_input() -> bool
func is_output() -> bool
func has_connection() -> bool

Problem: Spawning windows requires: load scene → instantiate → set position → emit signal → await initialization → check validity.

Suggestion: Add utility function:

# In Utils or Globals
static func spawn_window(window_id: String, position: Vector2, auto_connect_to: String = "") -> WindowContainer
# Usage
var new_node = Utils.spawn_window("compiler", drop_position)

Problem: Accessed internals like Globals.desktop.selected directly, had to call internal methods.

Suggestion: Clean public API on Desktop:

func select_all() -> void
func select_by_category(category: String) -> void
func clear_selection() -> void
func get_selection() -> Array[WindowContainer]
func center_view_on_selection() -> void
func delete_selection() -> void

Problem: Screenshot feature needed to access and manipulate camera for proper rendering.

Suggestion: Expose camera controls:

Globals.desktop.get_camera() -> Camera2D
Globals.desktop.get_viewport_rect() -> Rect2
Globals.desktop.capture_viewport(quality: int = 1) -> Image

Problem: Had to create custom callback chains for settings like opacity, glow.

Suggestion: Centralized settings event:

signal setting_changed(key: String, old_value: Variant, new_value: Variant)

Problem: Had to dig into Globals.max_window_count and Utils.MAX_WINDOW to understand limits.

Suggestion: Clean API:

func get_node_count() -> int
func get_node_limit() -> int
func set_node_limit(limit: int) -> void
func can_add_node(window_id: String = "") -> bool

signal initialized() # After fully ready with ResourceContainers registered
signal closing() # Already exists ✓
signal selected()
signal deselected()
signal moved(old_pos: Vector2, new_pos: Vector2)

Add virtual methods for modding extension points:

func _mod_pre_delete_window(window: WindowContainer) -> bool # Return false to cancel
func _mod_post_create_connection(output_id: String, input_id: String)
func _mod_pre_save() -> Dictionary # Return extra data to save
func _mod_post_load(data: Dictionary)

Problem: Had to navigate scene tree to find HUD → Overlay for placing mod UI.

Suggestion: Named access:

Globals.get_ui_layer() -> CanvasLayer # For overlays like command palette
Globals.get_hud() -> Control # For HUD buttons

Problem: Currency modification required understanding internal mechanics.

Suggestion:

func get_currency(type: String) -> float # "money", "research", "token"
func add_currency(type: String, amount: float)
func set_currency(type: String, amount: float)

Signals.connection_droppped has triple ‘p’ - consider fixing for consistency.


SuggestionEffortImpactFeature Affected
Window metadataMediumHighWire-drop menu, Command palette
Connection signalsLowHighWire-drop menu
Connector type exposeLowHighWire-drop menu
Spawn helperMediumHighWire-drop menu
Selection APILowMediumCommand palette
Camera accessLowMediumScreenshot
Settings signalLowMediumAll settings
Node count APILowMediumNode limit feature
Lifecycle signalsLowLowGeneral modding
Hook pointsMediumMediumGeneral modding
UI layer accessLowLowSettings UI, Palette
Currency APILowLowCheats tab

The main challenge is that many internals aren’t designed for external access, requiring mods to reach into private state.