Son aktivite 1786915903

What features should we make to deliver a productivity tool for multipc multimonitor work. Copy and paste works, this is a time saving application. Let's save time for anyone who uses this app. List features and other tasks to complete this project and save it all in SUMMARY.md

Revizyon 0abd60f3915faee234e97d879afce23735b0ae9e

Godot-Convention.md Ham

Godot 4.7 — Project Conventions & API Reference

A reference document for the EnvoyOS project targeting Godot 4.7. Derived from the official Godot 4.7 documentation structure and the project's AIFIX.md corrections.


Table of Contents

  1. GDScript Syntax & Type Hints
  2. Node Lifecycle
  3. Signals
  4. Input Handling
  5. Controls & UI
  6. Window Management
  7. Audio
  8. Networking (Multiplayer)
  9. File I/O
  10. Resources & Loading
  11. Performance
  12. Style Conventions
  13. Common Pitfalls & Corrections

1. GDScript Syntax & Type Hints

Typed Arrays

# WRONG (Godot 3 style, inferred empty array)
var rocks := []

# CORRECT (Godot 4.7 explicit type)
var rocks: Array[Label] = []
var items: Array[Dictionary] = []
var names: Array[String] = []
var scales: Array[float] = []

Variable Declarations

# Prefer explicit types over := inference when the type is unambiguous
var file: FileAccess = FileAccess.open(path, FileAccess.READ)
var parsed: Variant = JSON.parse_string(json_str)

# Use := only when the right-hand side type is clear
var btn := Button.new()
var style := StyleBoxFlat.new()

Color Construction

# WRONG
col.color = Color.rand()

# CORRECT
col.color = Color(randf(), randf(), randf())

Global Functions (Not Methods)

# WRONG (clampf is a global function, not a method on float)
_transparency_multiplier = value.clampf(0.0, 1.0)

# CORRECT
_transparency_multiplier = clampf(value, 0.0, 1.0)
# OR
_transparency_multiplier = clamp(value, 0.0, 1.0)

Vector Operations

# WRONG (ceiled() does not exist on Vector2)
var target := vec.ceiled()

# CORRECT
var target := Vector2i(vec.ceil())

Async/Await

# WRONG (yield was removed in Godot 4)
yield(get_tree().process_frame, "process_frame")

# CORRECT
await get_tree().process_frame

Process Delta Time

# WRONG (throws error)
var speed = Node.get_process_delta_time()

# CORRECT
var speed = get_process_delta_time()

Constants & Enums

const MAX_ITEMS := 12
const CONFIG_PATH := "user://inventory_config.cfg"

enum PowerState {
    OFF = 0,
    LOW = 1,
    NETWORK = 2,
    HIGH = 3,
}

2. Node Lifecycle

Key Notifications (Godot 4.7)

func _notification(what: int) -> void:
    match what:
        NOTIFICATION_WM_CLOSE_REQUEST:
            # Window close (replaces NOTIFICATION_WM_QUIT_REQUEST)
            pass
        NOTIFICATION_APPLICATION_PAUSED, NOTIFICATION_APPLICATION_FOCUS_OUT:
            # App backgrounded / lost focus
            pass
        NOTIFICATION_APPLICATION_RESUMED, NOTIFICATION_APPLICATION_FOCUS_IN:
            # App foregrounded / regained focus
            pass

Process Mode (Replaces Old Pause Mode)

# WRONG
timer.pause_mode = Timer.PAUSE_MODE_PROCESS

# CORRECT
timer.process_mode = Node.PROCESS_MODE_ALWAYS

Dialogs and Timers

# When a ConfirmationDialog is shown via popup_centered(),
# the SceneTree pauses. Timers inside will stop unless:
dialog.process_mode = Node.PROCESS_MODE_ALWAYS

Node Creation and Freeing

# To clear a container's children (VBoxContainer has no .clear() in Godot 4)
# WRONG
kitchen_sink_box.clear()

# CORRECT
for child in container.get_children():
    child.queue_free()

Safe Instance Checks

# After any await or deferred call, verify the object still exists
if is_instance_valid(node) and node.is_inside_tree():
    node.do_something()

3. Signals

Declaration

signal item_updated(index: int)
signal stats_updated(latency_ms: float, jitter: float, packet_loss: float)

Connecting (with type-safe lambdas)

btn.pressed.connect(_on_button_pressed.bind(index))
slider.value_changed.connect(func(val: float): _on_slider(val))

Disconnecting

if signal_name in node.get_signal_connection_list(sig):
    node.disconnect(sig, callable)

RPC (Multiplayer)

@rpc("any_peer", "unreliable_ordered")
func receive_secure_clipboard(encrypted_data: PackedByteArray) -> void:
    pass

# Call from any peer:
rpc("receive_secure_clipboard", data)

4. Input Handling

Key Codes (Godot 4.7)

if event is InputEventKey and event.keycode == KEY_TAB and Input.is_key_pressed(KEY_CTRL):
    pass

Touchscreen

# WRONG
Input.is_touchscreen_available()

# CORRECT
DisplayServer.is_touchscreen_available()

WebRTC Feature Check

# WRONG
Engine.has_feature("web_view")

# CORRECT
OS.has_feature("web") or ClassDB.class_exists("WebRTCPeerConnection")

Mouse Position (Global vs Local)

# For window-level calculations (resize, drag), use GLOBAL screen coords:
var global_mouse: Vector2 = DisplayServer.mouse_get_position()

# For UI-local calculations:
var local_mouse: Vector2 = get_viewport().get_mouse_position()

5. Controls & UI

StyleBoxFlat (Per-Corner, Per-Side)

# WRONG (Godot 3 properties do not exist in 4.7)
style.border_width_all = 2
style.corner_radius_all = 16

# CORRECT (individual properties)
style.border_width_left = 2
style.border_width_right = 2
style.border_width_top = 2
style.border_width_bottom = 2
style.corner_radius_top_left = 16
style.corner_radius_top_right = 16
style.corner_radius_bottom_left = 16
style.corner_radius_bottom_right = 16

StyleBox Copying

# WRONG
var hover_style = StyleBoxFlat.new(style)

# CORRECT
var hover_style = style.duplicate()

TextEdit Wrapping

# WRONG
system_input.fit_content_width = true

# CORRECT
system_input.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY

Tree Items

# WRONG (type inference fails)
var child := control.create_item(root)

# CORRECT
var child: TreeItem = control.create_item(root)

Abstract Classes

# WRONG (Slider is abstract, cannot be constructed)
Slider.new()

# CORRECT
VSlider.new()
HSlider.new()

TabBar Close Buttons

# WRONG (property does not exist)
tab_bar.tabs_closeable = true

# CORRECT
tab_bar.tab_close_display_policy = TabBar.CLOSE_BUTTON_SHOW_ALWAYS
tab_bar.tab_close_pressed.connect(_on_tab_close_pressed)

Hiding TabContainer's Built-in Tab Bar

tab_container.tabs_visible = false

ConfirmationDialog

# Godot 4.7: use get_cancel_button() (not get_cancel())
dialog.get_cancel_button().text = "Cancel"

6. Window Management

V-Sync

# WRONG
DisplayServer.vsync = DisplayServer.VSYNC_ENABLED

# CORRECT
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED)

DPI / Content Scaling

# WRONG (size_scale does not exist)
get_window().size_scale = 2.0

# CORRECT
get_window().content_scale_factor = 2.0
# OR for base resolution:
get_window().content_scale_size = Vector2i(1920, 1080)

Window Size (Integer Required)

# Adjust physical window size inversely proportional to scale
var target_size := Vector2i((LOGICAL_BASE_SIZE / scale).ceil())
window.size = target_size

Deferred Window Size (Avoid Startup Race)

window.content_scale_factor = scale
var target_size := Vector2i((LOGICAL_BASE_SIZE / scale).ceil())
window.set_deferred("size", target_size)

Borderless Window

get_window().borderless = true
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, true)

Resize Flag (Windows DWM)

# WRONG (RESIZE flag does not exist as a set-to-true operation)
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE, true)

# CORRECT (pass false to RESIZE_DISABLED to ENABLE resizing)
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE_DISABLED, false)

Borderless Resize (Global Mouse)

# Must use global screen coordinates for borderless resize
var global_mouse := DisplayServer.mouse_get_position()
var window_top_left := get_window().position
var target_width: int = int(max(global_mouse.x - window_top_left.x, 800))
var target_height: int = int(max(global_mouse.y - window_top_left.y, 500))
get_window().size = Vector2i(target_width, target_height)

Cursor Shapes

DisplayServer.cursor_set_shape(DisplayServer.CURSOR_DRAG)
DisplayServer.cursor_set_shape(DisplayServer.CURSOR_HSIZE)
DisplayServer.cursor_set_shape(DisplayServer.CURSOR_ARROW)

Always on Top

get_window().always_on_top = true

Window Position

DisplayServer.window_set_position(Vector2i(x, y))
# OR
get_window().position = Vector2i(x, y)

7. Audio

Bus Management

AudioServer.add_bus()
AudioServer.set_bus_volume_db(index, db)
AudioServer.set_bus_mute(index, true)
AudioServer.get_bus_count()
AudioServer.get_bus_name(index)

Audio Effects

var capture := AudioEffectCapture.new()
AudioServer.add_bus_effect(bus_index, capture)
AudioServer.set_bus_effect_enabled(bus_index, effect_index, true)

Microphone Input

var mic_stream := AudioStreamMicrophone.new()
player.stream = mic_stream
player.bus = AudioServer.get_bus_name(bus_index)
player.autoplay = true

PCM Playback

var wav := AudioStreamWAV.new()
wav.format = AudioStreamWAV.FORMAT_16_BITS
wav.mix_rate = 48000
wav.stereo = true
wav.set_data(PackedFloat32Array)
player.stream = wav
player.play()

Input Device List

if AudioServer.has_method("get_input_device_list"):
    var devices: Array[String] = AudioServer.call("get_input_device_list")

8. Networking (Multiplayer)

ENet Multiplayer

var peer := ENetMultiplayerPeer.new()
var err: int = peer.create_server(port)
# OR
var err: int = peer.create_client("192.168.1.10", 8443)

multiplayer.multiplayer_peer = peer

Signals

multiplayer.connected_to_server.connect(_on_connected)
multiplayer.connection_failed.connect(_on_failed)
multiplayer.server_disconnected.connect(_on_disconnected)
multiplayer.peer_connected.connect(_on_peer_joined)
multiplayer.peer_disconnected.connect(_on_peer_left)
multiplayer.get_peers()  # Array[int]
multiplayer.get_unique_id()  # int

UDP (VoIP)

var pkt_peer := PacketPeerUDP.new()
pkt_peer.connect_to_host(ip, port)
pkt_peer.put_data(PackedByteArray)
pkt_peer.get_available_packet_count()
pkt_peer.get_packet()  # PackedByteArray
pkt_peer.close()

Local Addresses

# WRONG
IP.get_network_interfaces()  # as static call

# CORRECT (on the singleton instance)
var addresses: Array = IP.get_local_addresses()
var interfaces: Array = IP.get_network_interfaces()

Crypto (AES-256)

var aes := AESContext.new()
var hash_ctx := HashingContext.new()
hash_ctx.start(HashingContext.HASH_SHA256)
hash_ctx.update(key_bytes)
var key: PackedByteArray = hash_ctx.finish()

aes.start(AESContext.MODE_ECB_ENCRYPT, key)
var encrypted: PackedByteArray = aes.update(data)
aes.finish()

9. File I/O

ConfigFile

var config := ConfigFile.new()
config.load("user://settings.cfg")
var val = config.get_value("section", "key", default)
config.set_value("section", "key", value)
config.save("user://settings.cfg")

FileAccess

# Plain
var file := FileAccess.open(path, FileAccess.READ)
var text := file.get_as_text()
file.close()

# Compressed (FastLZ)
var file := FileAccess.open_compressed(path, FileAccess.WRITE, FileAccess.COMPRESSION_FASTLZ)
file.store_string(json_str)
file.close()

# Check existence
FileAccess.file_exists("user://data.json")

CSV

file.store_csv_line(["col1", "col2", "col3"])
var row: PackedStringArray = file.get_csv_line()

JSON

var parsed: Variant = JSON.parse_string(json_text)
var json_str: String = JSON.stringify(data, "\t")

10. Resources & Loading

Loading Scripts

# Static (compile-time)
const MyScript = preload("res://scripts/my_script.gd")

# Dynamic (runtime)
var script: GDScript = load("res://scripts/dynamic.gd")
var instance: Node = script.new()

Loading Fonts

var custom_font: Font = load("res://font/text_with_emojis.tres")

Class Registration

class_name MyEngine
extends Node

Note: If two scripts reference each other (circular dependency), relax the type hint to the base class to break the loop:

# Instead of:
var tab_bar: MainTabBar
# Use:
var tab_bar: TabBar

11. Performance

FPS

Engine.get_frames_per_second()
Engine.max_fps = 60

Draw Calls

Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME)

Low Processor Usage

OS.low_processor_usage_mode = true

Object Pooling

# Pre-allocate nodes, toggle visibility instead of create/free
var pool: Array[Label] = []
for i in POOL_SIZE:
    var node := Label.new()
    node.visible = false
    add_child(node)
    pool.append(node)

Avoid Per-Frame Allocations

# Reuse cache arrays
var _cache: Array[Node] = []

func update():
    _cache.clear()
    for item in items:
        if item.valid:
            _cache.append(item)
    # Swap with working array
    var temp = items
    items = _cache
    _cache = temp

Debounce Timers

var _save_timer := Timer.new()
_save_timer.wait_time = 1.0
_save_timer.one_shot = true
add_child(_save_timer)

# In event handler:
_save_timer.stop()
_save_timer.start()

12. Style Conventions

File Naming

Pattern Purpose
*_engine.gd Logic / data / network layer
*_ui.gd Presentation / node construction
*_helper.gd Static utility functions

Engine Pattern

extends Node
class_name MyEngine

signal data_changed(value: Variant)

const CONFIG_PATH := "user://my_settings.cfg"

var _state: Dictionary = {}

func _ready() -> void:
    _load()

func _exit_tree() -> void:
    _save()

func _process(delta: float) -> void:
    # Per-frame logic

# Public API
func get_value(key: String) -> Variant: ...
func set_value(key: String, val: Variant) -> void: ...

# Private helpers
func _load() -> void: ...
func _save() -> void: ...

UI Pattern

extends RefCounted
class_name MyUI

static func setup_ui(page_container: Node, engine: Node) -> void:
    # Guard against double-setup
    if page_container.has_node("MyWrapper"):
        return

    # Locate content area
    var layout_vbox = page_container.get_child(0)
    var main_content = layout_vbox.get_child(0)

    # Clear previous
    for child in main_content.get_children():
        child.queue_free()

    # Build UI...

Print Statements

print("[EngineName] Message: ", detail)
push_warning("[EngineName] Non-fatal issue")
push_error("[EngineName] Fatal issue: ", err)

13. Common Pitfalls & Corrections

# Wrong Correct Reason
1 var items := [] var items: Array[Label] = [] Typed arrays required
2 DisplayServer.vsync = true DisplayServer.window_set_vsync_mode(...) API changed in 4.x
3 Input.is_touchscreen_available() DisplayServer.is_touchscreen_available() Moved to DisplayServer
4 Color.rand() Color(randf(), randf(), randf()) No static rand()
5 yield(...) await ... yield removed in Godot 4
6 container.clear() for c in container.get_children(): c.queue_free() No clear() on Container
7 style.border_width_all = 2 Per-side border_width_left/right/top/bottom No _all shortcut
8 style.corner_radius_all = 16 Per-corner corner_radius_top_left/... No _all shortcut
9 StyleBoxFlat.new(style) style.duplicate() No copy constructor
10 fit_content_width = true wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY Property renamed
11 Slider.new() VSlider.new() / HSlider.new() Slider is abstract
12 tab_bar.tabs_closeable = true tab_bar.tab_close_display_policy = ... Property renamed
13 get_window().size_scale = 2.0 get_window().content_scale_factor = 2.0 Property renamed
14 DisplayServer.window_set_flag(RESIZE, true) DisplayServer.window_set_flag(RESIZE_DISABLED, false) Flag semantics inverted
15 dialog.get_cancel() dialog.get_cancel_button() Method renamed in 4.6+
16 Node.get_process_delta_time() get_process_delta_time() Instance method, not static
17 vec.ceiled() Vector2i(vec.ceil()) Wrong method name
18 IP.get_network_interfaces() (static) IP.get_network_interfaces() (on singleton) Must be instance call
19 NOTIFICATION_WM_QUIT_REQUEST NOTIFICATION_WM_CLOSE_REQUEST Renamed in Godot 4
20 timer.pause_mode = PAUSE_MODE_PROCESS timer.process_mode = PROCESS_MODE_ALWAYS Renamed in Godot 4
21 Engine.has_feature("web_view") OS.has_feature("web") Correct singleton + feature
22 var child := control.create_item(root) var child: TreeItem = control.create_item(root) Type inference fails
23 Engine.get_process_time() Does not exist Use Time.get_ticks_msec()
24 NOTIFICATION_FOCUS_OUT NOTIFICATION_APPLICATION_FOCUS_OUT Correct constant name

Quick Reference: Godot 4.7 Class Hierarchy (UI)

CanvasItem
├── Control
│   ├── Container
│   │   ├── VBoxContainer
│   │   ├── HBoxContainer
│   │   ├── GridContainer
│   │   ├── MarginContainer
│   │   ├── PanelContainer
│   │   ├── ScrollContainer
│   │   ├── TabContainer
│   │   ├── HSplitContainer / VSplitContainer
│   │   └── CenterContainer
│   ├── Label
│   ├── Button
│   ├── CheckBox
│   ├── OptionButton
│   ├── LineEdit
│   ├── TextEdit
│   ├── RichTextLabel
│   ├── HSlider / VSlider
│   ├── ProgressBar
│   ├── SpinBox
│   ├── ColorPickerButton
│   ├── Tree
│   ├── TabBar
│   ├── PopupMenu
│   └── ConfirmationDialog (extends Window)
├── Node2D
├── AudioStreamPlayer
└── Node (base)

References


Last updated for Godot 4.7. Cross-reference with AIFIX.md for project-specific corrections.

Qwen-SUMMARY.md Ham

EnvoyOS — Multi-PC, Multi-Monitor Productivity Suite

A productivity-focused desktop application built with Godot 4.6. Designed for engineers and knowledge workers who work across multiple PCs and monitors. The core value proposition: every keystroke, file, and timer is one hop away regardless of which machine you're sitting at.


Project Highlights

  • All-in-One Toolkit: AI tools, clipboard sync, file transfer, timers, inventory tracking, video/audio settings, and built-in support documentation in a single interface.
  • Modular Architecture: Clean separation between logic (*_engine.gd) and UI (*_ui.gd) ensures scalability and easy maintenance.
  • Cross-PC Sync: ENet-based multiplayer with AES-256 encrypted clipboard, planned file transfer, and shared state.
  • Multi-Monitor Aware: DPI scaling, per-monitor layout memory, window tiling, and floating overlays.
  • AI Integration: Local Ollama-powered code assistant, suggestions, and (planned) transcription.

Why Support?

Developing and maintaining open-source tools takes time, effort, and resources. Your support directly funds:

  • New feature development & bug fixes
  • Performance optimizations & engine updates
  • Documentation & community resources

Every contribution, no matter the size, helps keep this project growing and accessible to everyone. Thank you for your support! ☕✨


Current State

Completed / Working

Module Status
Clipboard sync (ENet + AES-256) ✅ Working
AI Chat (Ollama streaming) ✅ Working
Markdown Editor (autosave) ✅ Working
VoIP (UDP, VAD, jitter buffer) 🚧 In Progress
Audio settings (volume, mute, mic level) 🚧 In Progress
Timer panel (12 slots, fuel-bar UI) ✅ Working
Inventory panel (12 slots, fuel-bar UI) 🚧 In Progress
Tab management (custom tab bar, session persistence) ✅ Working
OS Grid layout (configurable rows × cols) 🚧 In Progress
Theme builder (bg/font/accent/shade/transparency) ✅ Working
Video settings (FPS, DPI, window mode, position, size) ✅ Working
Web tab browser (paginated Chrome export) 🚧 In Progress
Ship game (2D physics, object pooling) ✅ Working
TOP / Power state tracker 🚧 In Progress
User AFK detection (cross-platform) ✅ Working
Window drag/resize (borderless) ✅ Working
System tray minimization ✅ Working

Missing / Stub (Blocking)

File Status Action Required
system_engine.gd Empty Implement CPU/RAM/disk/GPU stats
system_ui.gd Empty Build system dashboard (CPU graph, RAM bar, disk, AFK)
ai_code_engine.gd Empty Build code-gen/review/explain engine
ai_code_ui.gd Empty Side-by-side code editor + AI panel
music_engine.gd extends Node only Implement playback queue, seeking, shuffle

Known Bugs / Technical Debt

Issue Location Fix
grid_engine.gd references clipboard_engine.is_connected_to_network (doesn't exist) grid_engine.gd line ~230 Change to clipboard_engine.can_broadcast / clipboard_engine.is_connecting
tab_engine.gd and top_engine.gd are 95% duplicates Both files Merge into one class or have TopEngine extend TabEngine
No input validation on VoIP port field voip_ui.gd Add is_valid_int() check before int() cast
Timer/Inventory hh:mm:ss parse has no overflow guard time_ui.gd, inventory_ui.gd Validate h≤23, m≤59, s≤59 before arithmetic
Music/Media tab is a dead tab main_engine.gd ALL_TABS Either implement or remove from list
No CI / automated testing Repo root Add GitHub Actions with godot --headless --check-only

Feature Roadmap

Phase 1 — Fix & Stabilise (Weeks 1–2)

# Task Details
1.1 Implement system_engine.gd CPU %, RAM used/total, disk usage, GPU load (platform-specific), network throughput. Emit signals for UI.
1.2 Implement system_ui.gd Dashboard with live-updating gauges, AFK timer (reuse user_active_engine.gd), process list (optional).
1.3 Fix grid_engine.gd broken refs Replace is_connected_to_networkcan_broadcast, is_reconnectingis_connecting.
1.4 Merge tab_engine / top_engine One base class, reduce duplication.
1.5 Add input validation VoIP port, Timer/Inventory time parsing, all user-facing number fields.
1.6 Implement or remove Music tab Either build music_engine.gd + wire music_ui.gd, or remove "Media" from ALL_TABS.
1.7 Add unit tests (GUT) ThemeSerializer round-trip, TabEngine CRUD, TimeEngine tick, InventoryEngine expiry, ClipboardEngine encrypt/decrypt.
1.8 CI pipeline GitHub Actions: godot --headless --check-only + GUT test run on push.

Phase 2 — Multi-PC Power Features (Weeks 3–6)

# Task Details
2.1 Clipboard History Ring Buffer Store last 100 items (text + images) with timestamp, source PC, app name. Global hotkey Ctrl+Shift+V opens searchable picker across all peers.
2.2 Snippet Library Save frequently-used text blocks (code snippets, email templates, API keys). Sync to all PCs. One-click paste.
2.3 Cross-PC Text Search Type a keyword → search all peers' clipboard history simultaneously via RPC.
2.4 P2P File Transfer Drag file onto Network tab → AES-256 encrypt → chunked ENet stream → progress bar → destination PC. Reuse existing crypto.
2.5 Shared Workspace Folder Synced directory (chunked transfer). Edit on PC-A, open on PC-B.
2.6 Shared Kanban Board To-Do / In-Progress / Done. RPC-synced in real-time. Cards: title, tags, due date, assigned PC. Reuse clipboard_engine RPC pattern.
2.7 Notification Mirroring System/app notifications broadcast to all peers. "PC-A idle > 10 min" → toast on PC-B. Timer expiry → alert all.
2.8 Command Palette (Ctrl+K) Fuzzy-search all actions: "open tab", "change theme", "start timer 3", "connect to PC-B", "mute audio". One keystroke to do anything.
2.9 Global Hotkeys (OS-level) Register via native helper: clipboard history, screenshot, quick paste. Works even when app is unfocused.
2.10 Offline Queue When disconnected, queue clipboard/file/task changes. Auto-sync on reconnect (extend existing reconnection logic).

Phase 3 — Multi-Monitor & AI (Weeks 7–10)

# Task Details
3.1 Monitor Layout Memory Detect monitors, save per-monitor window positions/sizes per panel. Restore on reconnect. user://monitor_layout.json.
3.2 Floating Overlays Always-on-top widgets: timer countdown, clipboard dock (last 5 items), AFK indicator glow. Assignable to specific monitor.
3.3 Window Tiling / Snapping Ctrl+1..4 → quadrant. Ctrl+Shift+Left/Right → half. Save/load named layouts. Ctrl+L to cycle.
3.4 Per-Monitor Contrast Each monitor can have different shade/brightness. Auto-adjust based on ambient light or time-of-day.
3.5 AI Code Engine ai_code_engine.gd: Explain selected code, Refactor + diff view, Generate from prompt, Review PR diff. Reuse Ollama streaming client.
3.6 AI Code UI ai_code_ui.gd: Side-by-side editor + AI response panel. Syntax highlighting, diff view, copy-to-clipboard.
3.7 AI Meeting Notes Stream mic audio → local Whisper (Ollama-compatible) → bullet-point summary → sync to all peers.
3.8 Cross-PC Input Mirroring (KVM) Type on PC-A → keystrokes stream to PC-B. Mouse delta streaming (relative, not absolute). Per-peer toggle.
3.9 AI Suggestion Engine Wire existing "Suggestion" prompt field to a "Smart Suggestions" button on clipboard tab. 3 context-aware actions.

Phase 4 — Polish & Release (Weeks 11–12)

# Task Details
4.1 Auto-start with OS Registry key (Win), .desktop file (Linux), LaunchAgent (macOS).
4.2 System Tray Menu "Show", "Mute", "Disconnect", "Open Timer", "Open Kanban", "Exit".
4.3 Backup / Restore One-click export all user:// settings to .zip. Import on new PC.
4.4 Accessibility Pass High-contrast mode, UI font scaling, screen-reader labels on all controls.
4.5 Session Replay Record 10s UI interaction replay as JSON for bug reports.
4.6 User Documentation Expand SUMMARY.md → full user manual. Keyboard shortcut reference. Setup guide per OS.
4.7 Export / Packaging godot --export-release for Windows / Linux / macOS. In-app updater (optional).

Phase 5 — Differentiators (Ongoing)

# Feature Description
5.1 Screen recording per monitor GPU capture, "record this monitor" toggle, export to file.
5.2 Screenshot + AI annotate Capture region → send to Ollama → written description.
5.3 Pomodoro focus mode 25/5 preset. Auto-pauses AI streaming and network sync during focus.
5.4 Dark-light auto-switch Theme tied to system clock (dark after 18:00).
5.5 Peer presence bar Avatar strip showing online PCs (reuse multiplayer.get_peers()).
5.6 Voice commands "Hey, paste the last email" → VAD → match snippet → paste.
5.7 Shared timer countdown Timer on PC-A shows live on PC-B. Sync end_timestamp over network.
5.8 Calendar view Timers/inventory deadlines on a mini monthly calendar.
5.9 CSV export Timer/inventory state as CSV for spreadsheet tracking.
5.10 Low-stock alerts Inventory item below threshold → red flag on all PCs.

Architecture Notes

┌─────────────────────────────────────────────────────────────────────┐
│                        MainUI / GridUI (Root)                        │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  TabBar / Grid Toolbar                                         │  │
│  └───────────────────────────────────────────────────────────────┘  │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  TabContainer / Content Area                                   │  │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐            │  │
│  │  │ AI Chat │ │ Editor  │ │ Network │ │  Timer  │  ...        │  │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘            │  │
│  └───────────────────────────────────────────────────────────────┘  │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  Engines (Nodes)                                               │  │
│  │  clipboard_engine │ ai_engine │ video_engine │ audio_engine    │  │
│  │  mic_engine │ web_engine │ time_engine │ inventory_engine     │  │
│  │  ui_engine │ top_engine │ tab_engine │ voip_engine            │  │
│  └───────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

Network Layer: ENet (MultiplayerPeer) + AES-256 (AESContext)
Persistence:   ConfigFile (*.cfg) + JSON (*.json) + CSV (timers/inventory)
Theme:         ThemeSerializer (compressed JSON, hex colors, FastLZ)

Supported Platforms

OS Clipboard Audio Idle Detection Network
Windows WASAPI GetLastInputInfo (P/Invoke) ENet
macOS CoreAudio IOHIDSystem (ioreg) ENet
Linux PipeWire/PulseAudio D-Bus (Mutter/KWin) / xprintidle ENet

Keyboard Shortcuts (Planned)

Shortcut Action
Ctrl+K Command Palette
Ctrl+Shift+V Clipboard History (cross-PC)
Ctrl+1..4 Snap to quadrant
Ctrl+Shift+Left/Right Snap to half
Ctrl+L Cycle saved layouts
Ctrl+W / close_tab Close current tab
Ctrl+T / new_tab New tab
Ctrl+Tab / Ctrl+Shift+Tab Next / Previous tab

Why This Saves Time

Pain Point Solution Time Saved
Copy on PC-A, walk to PC-B, paste Cross-PC clipboard sync 30s–2min per transfer
Re-type same email/snippet on each machine Snippet library + one-click paste 1–5min per repetition
"Where did I save that file?" Shared workspace + cross-PC search 5–15min per search
Set up different configs per monitor Monitor layout memory + auto-restore 5–10min per session
Explain code to colleague on another screen AI explain + share to all PCs 5–10min per explanation
Track physical inventory across desk drawers Shared inventory with expiry alerts Ongoing
"Did I finish that task?" Shared Kanban visible on all PCs 2–5min per check
Context-switch between 4 monitors on 2 PCs Window tiling + input mirroring 1–3min per switch

Contribution Guidelines

  1. Read AIFIX.md for Godot 4.6 API corrections before editing.
  2. Follow the *_engine.gd / *_ui.gd naming convention.
  3. All new UI must handle tab-switch cleanup (check for existing wrapper before adding).
  4. Network changes must go through clipboard_engine.gd RPC pattern (or the new MultiplayerChannel helper).
  5. Theme changes must flow through ui_engine.gdMainUI.apply_full_theme().
  6. Run tests: godot --headless -s res://addons/gut/gut_cmdln.gd -gdir=res://tests

License & Attribution

See repository for license file. Built with ❤️ and too much coffee. ☕