
Godot Platform Desktop
- 216 installs
- 454 repo stars
- Updated July 28, 2026
- thedivergentai/gd-agentic-skills
Use godot-platform-desktop for development tasks
About
godot-platform-desktop: A skill for development. This provides functionality for development workflows.
- godot-platform-desktop
Godot Platform Desktop by the numbers
- 216 all-time installs (skills.sh)
- +23 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,857 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-platform-desktopAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 216 |
|---|---|
| repo stars | ★ 454 |
| Last updated | July 28, 2026 |
| Repository | thedivergentai/gd-agentic-skills ↗ |
What it does
Use godot-platform-desktop for development tasks
Files
Platform: Desktop
Settings flexibility, window management, and kb/mouse precision define desktop gaming.
NEVER Do (Expert Desktop Rules)
Window & Display
- NEVER hardcode resolution or fullscreen modes — A 1920x1080 fullscreen on a 4K monitor is blurry. Always provide a settings menu with a resolution dropdown and a mode toggle.
- NEVER ignore DPI scale factors — Manually centering windows without
DisplayServer.screen_get_scale()results in incorrect positioning on HiDPI displays. - NEVER skip a borderless window option — Exclusive fullscreen can break multi-monitor focus. Offer
WINDOW_MODE_FULLSCREEN(borderless).
Input & Persistence
- NEVER use `keycode` for movement rebinds — Use
physical_keycodeto ensure WASD works correctly across international keyboard layouts (AZERTY/Dvorak). - NEVER save settings or user data to `res://` — Filesystem is read-only in exported releases. Always use
user://. - NEVER skip `NOTIFICATION_WM_CLOSE_REQUEST` — Failing to handle quit signals causes data loss. Intercept and flush and ConfigFile data before
get_tree().quit().
Performance & Integration
- NEVER run utility tools at max framerate — Enable
OS.low_processor_usage_modeto prevent high GPU heat in static desktop apps. - NEVER call proprietary SDKs (Steam/Epic) directly — Always wrap in
Engine.has_singleton()to prevent crashes in non-store builds. - NEVER block the main thread with massive I/O — Deserializing 100MB+ configs stalls the engine. Offload to
WorkerThreadPool.
---
Available Scripts
MANDATORY: Read the appropriate script before implementing the corresponding pattern.
desktop_window_manager.gd
Expert DPI-aware multi-monitor window positioning using DisplayServer.
desktop_settings_persistent.gd
Production settings persistence using ConfigFile for persistent INI data.
physical_input_rebinder.gd
Expert positional rebind system using physical_keycode for AZERTY/Dvorak.
platform_sdk_wrapper.gd
Safe PC SDK singleton wrapper (Steamworks/Epic) with crash guards.
native_dialog_helper.gd
Expert native OS file dialogs and system alerts logic.
secondary_window_spawner.gd
True multi-window management for secondary Viewports/Windows.
graceful_shutdown_handler.gd
Safe close-request interceptor for data flushing and exit guards.
low_processor_eco_mode.gd
Eco mode optimization for desktop tools and launchers.
desktop_performance_monitor.gd
OS-level hardware detection for dynamic graphics presets.
native_shell_executor.gd
Expert native shell command execution and output capture.
---
# settings.gd
extends Control
func _ready() -> void:
load_settings()
apply_settings()
func load_settings() -> void:
var config := ConfigFile.new()
config.load("user://settings.cfg")
$Graphics/ResolutionDropdown.selected = config.get_value("graphics", "resolution", 0)
$Graphics/FullscreenCheck.button_pressed = config.get_value("graphics", "fullscreen", false)
$Audio/MasterSlider.value = config.get_value("audio", "master_volume", 1.0)
func save_settings() -> void:
var config := ConfigFile.new()
config.set_value("graphics", "resolution", $Graphics/ResolutionDropdown.selected)
config.set_value("graphics", "fullscreen", $Graphics/FullscreenCheck.button_pressed)
config.set_value("audio", "master_volume", $Audio/MasterSlider.value)
config.save("user://settings.cfg")
func apply_settings() -> void:
# Resolution
var resolutions := [Vector2i(1920, 1080), Vector2i(2560, 1440), Vector2i(3840, 2160)]
var resolution := resolutions[$Graphics/ResolutionDropdown.selected]
get_window().size = resolution
# Fullscreen
if $Graphics/FullscreenCheck.button_pressed:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
else:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
# Audio
AudioServer.set_bus_volume_db(0, linear_to_db($Audio/MasterSlider.value))Keyboard Remapping
# Allow players to rebind keys
func rebind_action(action: String, new_key: Key) -> void:
# Remove existing
InputMap.action_erase_events(action)
# Add new
var event := InputEventKey.new()
event.keycode = new_key
InputMap.action_add_event(action, event)
# Save
save_input_map()Window Management
# Toggle fullscreen
func toggle_fullscreen() -> void:
if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
else:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)Steam Integration (if using)
# Using GodotSteam plugin
var steam_id: int
func _ready() -> void:
if Steam.isSteamRunning():
steam_id = Steam.getSteamID()
Steam.achievement_progress.connect(_on_achievement_progress)
func unlock_achievement(name: String) -> void:
Steam.setAchievement(name)
Steam.storeStats()Best Practices
1. Settings - Extensive graphics/audio options 2. Keybinds - Allow remapping 3. Alt+F4 - Support quit shortcuts 4. Save Location - Use user:// directory
Expert Techniques & Optimizations
1. Alt-Tab-Pause (Stuck Input Guard)
When a game loses focus, the OS may intercept "key up" events, leaving Godot's Input state stuck. Use NOTIFICATION_APPLICATION_FOCUS_OUT to pause the game and reset input logic.
func _notification(what: int) -> void:
match what:
NOTIFICATION_APPLICATION_FOCUS_OUT:
get_tree().paused = true
# Optional: Manually release critical actions
Input.action_release("move_forward")
NOTIFICATION_APPLICATION_FOCUS_IN:
get_tree().paused = false2. Social Integrations (GDExtension)
For Discord-RPC or Vapor network pipes, use GDExtension to bind native shared libraries (.dll, .so, .dylib) to Godot at runtime. This keeps the engine core small while enabling expert-level social features.
# Logic assuming a 'SocialIntegration' GDExtension is loaded
func _init_social() -> void:
if ClassDB.class_exists("SocialIntegration"):
var social = ClassDB.instantiate("SocialIntegration")
social.set_activity("In Menu", "Level 1")3. Desktop-Launcher Template
Use a dedicated Godot project as a lightweight launcher. It reads/writes user://settings.cfg and spawns the main game using OS.create_process().
func _on_play_pressed() -> void:
var exe_path := OS.get_executable_path()
var args := PackedStringArray(["--main-pack", "game_data.pck"])
var pid := OS.create_process(exe_path, args)
if pid > 0:
get_tree().quit()Reference
- Related:
godot-export-builds,godot-save-load-systems
Related
- Master Skill: godot-master
# skills/platform-desktop/scripts/desktop_integration_manager.gd
extends Node
## Desktop Integration Manager Expert Pattern
## Handles window management, Steam integration (mocked), and quit requests.
class_name DesktopIntegrationManager
signal settings_changed
signal app_quit_requested
# Configuration
const SETTINGS_PATH = "user://settings.cfg"
# State
var _config := ConfigFile.new()
func _ready() -> void:
# 1. Handle Quit Requests (Alt+F4, Cmd+Q)
get_tree().set_auto_accept_quit(false)
# 2. Load Settings
_load_settings()
_apply_graphics_settings()
# 3. Initialize Steam (Mock/Check)
_init_steam()
print("[DesktopIntegrationManager] Initialized")
func _notification(what: int) -> void:
if what == NOTIFICATION_WM_CLOSE_REQUEST:
_handle_quit_request()
func _handle_quit_request() -> void:
print("[DesktopIntegrationManager] Quit Requested")
# Perform saves, cleanup, etc.
app_quit_requested.emit()
# Force quit after delay if needed, or let game logic call quit
get_tree().quit()
func set_resolution(index: int) -> void:
var resolutions = [
Vector2i(1920, 1080),
Vector2i(2560, 1440),
Vector2i(3840, 2160)
]
if index >= 0 and index < resolutions.size():
var res = resolutions[index]
get_window().size = res
_center_window()
_config.set_value("graphics", "resolution_index", index)
_save_settings()
func set_fullscreen(enabled: bool) -> void:
if enabled:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) # Or EXCLUSIVE
else:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
_center_window()
_config.set_value("graphics", "fullscreen", enabled)
_save_settings()
func _center_window() -> void:
var screen_id = DisplayServer.window_get_current_screen()
var screen_rect = DisplayServer.screen_get_usable_rect(screen_id)
var window_size = get_window().size
get_window().position = screen_rect.position + (screen_rect.size - window_size) / 2
func _init_steam() -> void:
if Engine.has_singleton("Steam"):
var steam = Engine.get_singleton("Steam")
var init_info: Dictionary = steam.steamInit()
print("[DesktopIntegrationManager] Steam Status: ", init_info.get("verbal", "Unknown"))
else:
print("[DesktopIntegrationManager] Steamworks SDK not found (Development Mode)")
func _load_settings() -> void:
if _config.load(SETTINGS_PATH) != OK:
# Defaults
_config.set_value("graphics", "resolution_index", 0)
_config.set_value("graphics", "fullscreen", false)
_save_settings()
func _save_settings() -> void:
_config.save(SETTINGS_PATH)
func _apply_graphics_settings() -> void:
set_resolution(_config.get_value("graphics", "resolution_index", 0))
set_fullscreen(_config.get_value("graphics", "fullscreen", false))
## EXPERT USAGE:
## Add as AutoLoad. Connect to settings menu UI.
class_name DesktopPerformanceMonitor
extends Node
## Expert OS-level hardware monitoring for PC deployments.
## Used to auto-detect hardware and suggest graphics presets.
func get_hardware_info() -> Dictionary:
return {
"cpu": OS.get_processor_name(),
"ram_total_mb": OS.get_static_memory_usage() / 1024 / 1024, # Current usage
"gpu": RenderingServer.get_video_adapter_name(),
"is_sandboxed": OS.is_sandboxed_app()
}
func suggest_preset() -> StringName:
# Simplified logic for demonstration
var gpu = RenderingServer.get_video_adapter_name().to_lower()
if "rtx" in gpu or "rx 6" in gpu:
return &"ultra"
return &"balanced"
class_name DesktopSettingsPersistent
extends Node
## Expert settings persistence using ConfigFile.
## Stores window state and graphics presets in a standard INI format.
const SETTINGS_PATH = "user://settings.ini"
var _config := ConfigFile.new()
func save_desktop_state() -> void:
var window := get_window()
_config.set_value("display", "screen", window.current_screen)
_config.set_value("display", "mode", window.mode)
_config.set_value("display", "size", window.size)
_config.set_value("display", "position", window.position)
var err = _config.save(SETTINGS_PATH)
if err != OK:
push_error("DesktopSettings: Failed to save to ", SETTINGS_PATH)
func load_desktop_state() -> void:
if _config.load(SETTINGS_PATH) == OK:
var window := get_window()
window.current_screen = _config.get_value("display", "screen", window.current_screen)
window.mode = _config.get_value("display", "mode", window.mode)
# Expert: Only apply size/pos if windowed to avoid resolution corruption
if window.mode == Window.MODE_WINDOWED:
window.size = _config.get_value("display", "size", window.size)
window.position = _config.get_value("display", "position", window.position)
class_name DesktopWindowManager
extends Node
## Expert handler for PC multi-monitor and DPI-aware window positioning.
## Ensures windows are centered and sized correctly across varying monitor scales.
func center_on_current_screen() -> void:
var current_screen := DisplayServer.window_get_current_screen()
var usable_rect := DisplayServer.screen_get_usable_rect(current_screen)
var scale_factor := DisplayServer.screen_get_scale(current_screen)
var window := get_window()
# Apply OS-level scale factor to ensure consistent size on HiDPI displays
var target_size := Vector2i(Vector2(window.size) * scale_factor)
var target_pos := usable_rect.position + (usable_rect.size / 2) - (target_size / 2)
window.position = target_pos
func set_mode_safe(mode: DisplayServer.WindowMode) -> void:
# Expert: Ensure we don't switch to exclusive fullscreen if not supported
if mode == DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
if not DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG_FILE): # Simple proxy check
mode = DisplayServer.WINDOW_MODE_FULLSCREEN
DisplayServer.window_set_mode(mode)
class_name GracefulShutdownHandler
extends Node
## Expert handler for OS-level close requests (Alt+F4 / Window 'X').
## Ensures all data is flushed and saved before the process terminates.
func _ready() -> void:
# Intercept the quit signal
get_tree().set_auto_accept_quit(false)
func _notification(what: int) -> void:
if what == NOTIFICATION_WM_CLOSE_REQUEST:
_on_close_requested()
func _on_close_requested() -> void:
print("Desktop: Close requested. Flushing data...")
# Trigger your SaveManager.save_all() synchronously here
# Wait for I/O completion if necessary, then quit
get_tree().quit()
## Warning: Skipping this often leads to corrupted .ini/.cfg files during force-quits.
class_name LowProcessorEcoMode
extends Node
## Expert Eco Mode/Low Processor usage optimization.
## Ideal for desktop utilities, launchers, or laptop-friendly settings.
func set_eco_mode(enabled: bool) -> void:
# Only redraw if something changes (animations, input)
OS.low_processor_usage_mode = enabled
if enabled:
# Increase sleep time between frames to reduce CPU heat
OS.low_processor_usage_mode_sleep_usec = 8000
else:
OS.low_processor_usage_mode_sleep_usec = 6900 # Default
## Tip: This can reduce GPU power draw by up to 90% in idle/static UI apps.
class_name NativeDialogHelper
extends Node
## Expert native OS integration for desktop platforms.
## Bypasses internal Godot UI for a native UX feel.
func show_native_alert(message: String, title: String = "Alert") -> void:
# Blocks main thread - use sparingly
OS.alert(message, title)
func open_native_file_selector(callback: Callable) -> void:
if DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG_FILE):
DisplayServer.file_dialog_show(
"Select File",
OS.get_user_data_dir(),
"",
false,
DisplayServer.FILE_DIALOG_MODE_OPEN_FILE,
["*.dat; Data Files"],
callback
)
else:
print("Desktop: Native dialogs not supported on this host.")
class_name NativeShellExecutor
extends Node
## Expert native shell integration via OS.execute_with_pipe.
## Allows running CLI tools and capturing their output for editor integrations.
func run_shell_command(command: String, args: PackedStringArray) -> String:
var output = []
var err = OS.execute(command, args, output, true)
if err == OK:
return "".join(output)
return "Error: " + str(err)
## Warning: Use caution with shell execution to avoid security vulnerabilities.
class_name PhysicalInputRebinder
extends Node
## Expert rebind system using Physical Keycodes.
## Ensures WASD movement works on AZERTY/Dvorak without manual remapping.
func rebind_action_physical(action: StringName, key_event: InputEventKey) -> void:
# Convert standard keycode to physical location-based keycode
if key_event.keycode != KEY_NONE:
key_event.physical_keycode = key_event.keycode
key_event.keycode = KEY_NONE
InputMap.action_erase_events(action)
InputMap.action_add_event(action, key_event)
_notify_input_updated()
func _notify_input_updated() -> void:
# Signal other systems (UI prompts) that bindings have changed
pass
## Rule: Always use 'physical_keycode' for positional gameplay controls (WASD/ESDF).
# platform_desktop_patterns.gd
extends Node
# 1. Enabling Client-Side Decorations (macOS/Windows)
# EXPERT NOTE: Custom title bars create a premium "App" feel.
func setup_app_styles() -> void:
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, true)
# Further logic for custom minimize/close buttons would go here
# 2. Triggering Native OS File Dialogs
# EXPERT NOTE: Users prefer the system-native look over Godot's built-in FileDialog.
func open_file_browser(callback: Callable) -> void:
DisplayServer.file_dialog_show(
"Open Configuration",
"user://",
"",
false,
DisplayServer.FILE_DIALOG_MODE_OPEN_FILE,
["*.json"],
callback
)
# 3. Spawning Detached Tool Windows
# EXPERT NOTE: Multi-window support is a powerful Desktop exclusive feature in Godot 4.
func create_secondary_display(scene: PackedScene) -> Window:
var popup := Window.new()
popup.title = "Side Tool"
popup.unresizable = false
add_child(popup)
popup.add_child(scene.instantiate())
popup.popup_centered()
return popup
# 4. Opening Encoded URLs
# EXPERT NOTE: Always encode URIs to prevent injection or broken links on different OSs.
func open_support_page() -> void:
var uri := "https://docs.godotengine.org".uri_encode()
OS.shell_open(uri)
# 5. Low Processor Mode (App Optimization)
# EXPERT NOTE: Essential for background tools (editors, launchers) to save power.
func enable_eco_mode() -> void:
OS.low_processor_usage_mode = true
OS.low_processor_usage_mode_sleep_usec = 6900 # Sleep ~7ms to save CPU
# 6. Polling Screen Pixel Color
# EXPERT NOTE: Useful for eye-dropper tools or dynamic ambient lighting from screen content.
func get_pixel_at_cursor() -> Color:
var pos := DisplayServer.mouse_get_position()
return DisplayServer.screen_get_pixel(pos)
# 7. OS Drag-and-Drop Callback
# EXPERT NOTE: Enhances user experience for level editors or file importers.
func setup_drag_drop() -> void:
DisplayServer.window_set_drop_files_callback(_on_files_dropped)
func _on_files_dropped(files: PackedStringArray) -> void:
for f in files:
print("User dropped: ", f)
# 8. macOS App Sandbox Verification
# EXPERT NOTE: Entitlements on macOS can block logic. Always check the environment.
func is_in_sandbox() -> bool:
return OS.has_feature(&"macos") and OS.is_sandboxed()
# 9. Creating System Tray (Status) Indicators
# EXPERT NOTE: Allows apps to "minimize to tray" on Windows/Linux/macOS.
func register_tray_icon(icon: Texture2D) -> void:
DisplayServer.create_status_indicator(icon, "Godot Agent", _on_tray_clicked)
func _on_tray_clicked(btn: int) -> void:
if btn == MOUSE_BUTTON_LEFT:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
# 10. Background Process Forking
# EXPERT NOTE: Launch a separate headless instance for heavy data tasks or dedicated servers.
func fork_background_process() -> int:
return OS.create_process(OS.get_executable_path(), ["--headless", "--no-window"])
class_name PlatformSDKWrapper
extends Node
## Expert wrapper for proprietary PC SDKs (Steam, Epic).
## Uses safety checks to prevent crashes when singletons are missing.
var _steam_api: Object = null
func _ready() -> void:
if Engine.has_singleton("Steam"):
_steam_api = Engine.get_singleton("Steam")
var init = _steam_api.steamInit()
if init.status == 1:
print("Desktop: Steamworks Initialized.")
else:
print("Desktop: No Steam singleton found. Running in standalone mode.")
func unlock_achievement(id: String) -> void:
if _steam_api and _steam_api.isSteamRunning():
_steam_api.setAchievement(id)
_steam_api.storeStats()
## Expert: Always check 'Engine.has_singleton' before any SDK call.
class_name SecondaryWindowSpawner
extends Node
## Expert multi-window support for tools or secondary displays.
## Requires 'display/window/subwindows/embed_subwindows' to be set to false.
func spawn_floating_window(scene: PackedScene, title: String = "Tool") -> Window:
var window := Window.new()
window.title = title
window.wrap_controls = true
window.transient = false # Allow it to be moved to other monitors
var ui := scene.instantiate()
window.add_child(ui)
add_child(window)
window.popup_centered(Vector2i(800, 600))
return window
## Rule: Multi-window is best for desktop productivity or local-multiplayer status screens.