references/console-cert-patterns.md
# Console input and certification patterns
> Joypad snippets, platform overlay dialogs, shader binary cache, controller telemetry.
## Input Handling
```gdscript
func _input(event: InputEvent) -> void:
if event is InputEventJoypadButton:
match event.button_index:
JOY_BUTTON_A:
on_confirm()
JOY_BUTTON_B:
on_cancel()
```
## Performance Requirements
- **Locked 30/60 FPS** - No drops allowed
- **Memory limits** - Strict budgets
- **Certification testing** - QA required
## Platform Services
- Achievements/Trophies
- Cloud saves
- Multiplayer matchmaking
- Platform friends
### 1. Platform-Overlay-Manager (Native UI Dialogs)
To comply with strict console certification (TRCs), avoid custom UI for critical system messages. Use `DisplayServer.dialog_show()` to invoke native platform dialogs, ensuring the message is handled by the OS.
```gdscript
class_name PlatformOverlayManager extends Node
## Invokes native OS dialogs for system compliance.
func show_native_alert(title: String, msg: String) -> void:
if DisplayServer.has_feature(DisplayServer.FEATURE_SUBWINDOWS):
# Native OS dialog integration.
DisplayServer.dialog_show(title, msg, ["OK"], _on_dialog_closed)
else:
# Fallback to blocking OS alert.
OS.alert(msg, title)
func _on_dialog_closed(button_index: int) -> void:
print("Native dialog closed: ", button_index)
```
### 2. Shader-Binary-Caching (RenderingDevice)
Consoles use fixed hardware. Enable `rendering/shader_compiler/shader_cache/enabled` and use `RenderingDevice.shader_compile_binary_from_spirv()` to compile GPU-optimized binaries, reducing runtime stuttering.
```gdscript
class_name ConsoleShaderManager extends Node
## Manages GPU-specific shader binary compilation.
func get_device_uuid() -> String:
var rd := RenderingServer.get_rendering_device()
if rd:
# Unique ID for the specific GPU and Driver.
return rd.get_device_pipeline_cache_uuid()
return ""
```
### 3. Controller-Battery-Telemetry Hook
Monitor controller health using `Input.joy_connection_changed` and `Input.get_joy_info()`. While battery level requires a platform-specific GDExtension, the telemetry hook queries the hardware identification string.
```gdscript
class_name ControllerTelemetry extends Node
## Tracks controller states and hardware metadata.
func _ready() -> void:
Input.joy_connection_changed.connect(_on_joy_changed)
func _on_joy_changed(id: int, connected: bool) -> void:
if connected:
var info := Input.get_joy_info(id)
# Tracks hardware GUID and XInput index for telemetry logs.
print("Controller %d: %s" % [id, info.get("xinput_index", "Native")])
```
references/migration-notes.md
# Migration notes: godot-platform-console
Incremental upgrade for topics this skill covers. Apply **one hop**, stabilize/test, then next. Never skip hops.
If the project is **< 4.0**, follow [godot-version-migration](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-version-migration/SKILL.md) era bridges (legacy → 3→4) until 4.0, then these hops. Official 3→4: [Upgrading from Godot 3 to Godot 4](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.html).
## 4.0 → 4.1
Official: [Upgrading to Godot 4.1](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.1.html)
*No skill-relevant breaking changes for this hop.*
## 4.1 → 4.2
Official: [Upgrading to Godot 4.2](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.2.html)
*No skill-relevant breaking changes for this hop.*
## 4.2 → 4.3
Official: [Upgrading to Godot 4.3](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.3.html)
*No skill-relevant breaking changes for this hop.*
## 4.3 → 4.4
Official: [Upgrading to Godot 4.4](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.4.html)
*No skill-relevant breaking changes for this hop.*
## 4.4 → 4.5
Official: [Upgrading to Godot 4.5](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.5.html)
- `ProjectSettings.add_property_info()` validates keys more loudly — audit TRC-related custom project settings.
- `EditorExportPlatform.get_forced_export_files()` gains optional `preset` for certification packaging plugins.
## 4.5 → 4.6
Official: [Upgrading to Godot 4.6](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.6.html)
- `EditorExportPreset.get_script_export_mode()` returns enum — update automated cert submission export scripts.
- New projects default **Jolt** for 3D — confirm physics backend matches console port expectations.
## 4.6 → 4.7
Official: [Upgrading to Godot 4.7](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.7.html)
- `InputEvent.DEVICE_ID_*` constants — never assume device `0` is pad vs keyboard; map gamepad identity explicitly.
- New project stretch defaults `canvas_items` + `expand` — verify safe-zone UI on TV overscan after upgrade.
- Editor **Asset Store** naming replaces Asset Library — update internal certification docs/screenshots.
scripts/achievement_offline_queue.gd
class_name AchievementOfflineQueue
extends Node
## Expert Achievement/Trophy caching for Offline-ready consoles.
## Queues unlocks locally and flushes to platform services when online.
var _queue_path: String = "user://achievement_queue.dat"
var _pending_ids: Array[StringName] = []
func _ready() -> void:
_load_queue()
func unlock_achievement(achievement_id: StringName) -> void:
if _is_online():
_push_to_platform(achievement_id)
else:
_pending_ids.append(achievement_id)
_save_queue()
func _is_online() -> bool:
# Check connectivity via platform-specific API
return true
func _push_to_platform(_id: StringName) -> void:
# Native SDK call here
pass
func _save_queue() -> void:
var f = FileAccess.open(_queue_path, FileAccess.WRITE)
if f: f.store_var(_pending_ids)
func _load_queue() -> void:
if FileAccess.file_exists(_queue_path):
var f = FileAccess.open(_queue_path, FileAccess.READ)
_pending_ids = f.get_var()
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/io/saving_games.html
# - https://docs.godotengine.org/en/stable/tutorials/io/runtime_file_loading_and_saving.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-save-load-systems/SKILL.md — durable user:// queues across sessions
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-multiplayer-networking/SKILL.md — online flush when platform services return
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/async_save_manager.gd
class_name AsyncSaveManager
extends Node
## Expert Threaded Save System for Console certification.
## Prevents main-thread stutters and implements atomic file writing.
var _save_mutex := Mutex.new()
var _is_saving := false
func execute_save(data: Dictionary, slot: int = 1) -> void:
_save_mutex.lock()
if _is_saving:
_save_mutex.unlock()
return
_is_saving = true
_save_mutex.unlock()
# Offload I/O to background thread pooled workers
WorkerThreadPool.add_task(_write_to_disk.bind(data, slot))
func _write_to_disk(data: Dictionary, slot: int) -> void:
var json_str = JSON.stringify(data)
var final_path = "user://save_slot_%d.dat" % slot
var temp_path = final_path + ".tmp"
var file = FileAccess.open(temp_path, FileAccess.WRITE)
if file:
file.store_string(json_str)
file.close()
# Atomic rename to protect against power-loss corruption
DirAccess.rename_absolute(temp_path, final_path)
_save_mutex.lock()
_is_saving = false
_save_mutex.unlock()
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/io/saving_games.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html
# - https://docs.godotengine.org/en/stable/classes/class_workerthreadpool.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-save-load-systems/SKILL.md — atomic rename and slot schema
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-resource-data-patterns/SKILL.md — serializing Dictionary/JSON payloads
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/background_data_prefetcher.gd
class_name BackgroundDataPrefetcher
extends Node
## Expert Content Delivery: Offloads asset pre-fetching to background threads.
## Ensures smooth level transitions on slow console storage.
func prefetch_assets(paths: Array[String]) -> void:
for path in paths:
# Use WorkerThreadPool to keep the main thread fluid
WorkerThreadPool.add_task(_load_asset.bind(path))
func _load_asset(path: String) -> void:
# ResourceLoader.load() on a background thread pre-fills the internal cache.
# Subsequent calls to 'load()' on the main thread will be instant.
var _res = ResourceLoader.load(path)
print("Console: Prefetched ", path)
## Rule: Only prefetch non-critical assets (SFX, MeshData) to avoid I/O bottlenecks.
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/io/background_loading.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html
# - https://docs.godotengine.org/en/stable/classes/class_workerthreadpool.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-scene-management/SKILL.md — prefetch queues tied to scene transitions
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — I/O budgets on slow console storage
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/certification_manager.gd
class_name ConsoleCertificationManager
extends Node
## Expert handler for TRC/TCR certification compliance.
## Automatically manages focus transitions and controller disconnections.
signal focus_lost
signal focus_gained
signal controller_disconnected(device_id: int)
func _ready() -> void:
# TCR: Monitor joypad connectivity changes during runtime
Input.joy_connection_changed.connect(_on_joy_connection_changed)
process_mode = Node.PROCESS_MODE_ALWAYS
func _notification(what: int) -> void:
match what:
NOTIFICATION_APPLICATION_FOCUS_OUT:
# TRC: System menu opened (Overlay). Must pause immediately.
_enforce_system_pause()
focus_lost.emit()
NOTIFICATION_APPLICATION_FOCUS_IN:
focus_gained.emit()
func _on_joy_connection_changed(device: int, connected: bool) -> void:
if not connected:
# TRC: Controller disconnect must trigger a pause/overlay
_enforce_system_pause()
controller_disconnected.emit(device)
func _enforce_system_pause() -> void:
if not get_tree().paused:
get_tree().paused = true
print("Console: Forced system pause due to focus loss or disconnect.")
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/inputs/controller_features.html
# - https://docs.godotengine.org/en/stable/tutorials/inputs/handling_quit_requests.html
# - https://docs.godotengine.org/en/stable/classes/class_input.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-input-handling/SKILL.md — joy_connection_changed and pause UX
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-save-load-systems/SKILL.md — save indicators during forced pauses
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/console_boot_config.gd
class_name ConsoleBootConfig
extends Node
## Expert hardware-aware boot configuration.
## Disables expensive PC-only rendering features on initialization.
func _ready() -> void:
if OS.has_feature("mobile") or OS.has_feature("switch"):
_optimize_for_low_end()
# TRC Requirement: Always enable VSync for consoles
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED)
func _optimize_for_low_end() -> void:
# Disable real-time global illumination for performance
RenderingServer.gi_set_use_half_resolution(true)
# Lock FPS to prevent heating
Engine.max_fps = 30
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/export/feature_tags.html
# - https://docs.godotengine.org/en/stable/classes/class_engine.html
# - https://docs.godotengine.org/en/stable/classes/class_displayserver.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/pipeline_compilations.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-export-builds/SKILL.md — feature tags that select boot profiles
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — max_fps / VSync / GI half-res tradeoffs
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/console_compliance_handler.gd
# skills/platform-console/scripts/console_compliance_handler.gd
extends Node
## Console Compliance Handler Expert Pattern
## Automates TRC/TCR requirements: Focus loss handling, User ID checks, Save indicators.
class_name ConsoleComplianceHandler
signal focus_lost
signal focus_gained
@export var pause_on_focus_loss: bool = true
@export var show_mouse_cursor: bool = false
@export var save_icon: CanvasItem # Optional reference to UI icon
var _is_saving: bool = false
func _ready() -> void:
# 1. Cursor Management
if not show_mouse_cursor:
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
# 2. V-Sync Enforcement
# Consoles typically mandate V-Sync to prevent tearing
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED)
print("[ConsoleCompliance] Initialized. Mouse Hidden: ", !show_mouse_cursor)
func _notification(what: int) -> void:
match what:
NOTIFICATION_APPLICATION_FOCUS_OUT:
_handle_focus_loss()
NOTIFICATION_APPLICATION_FOCUS_IN:
_handle_focus_gain()
func _handle_focus_loss() -> void:
print("[ConsoleCompliance] Focus LOST")
focus_lost.emit()
if pause_on_focus_loss:
# TRC Requirement: Game must pause entirely when system focus is lost
get_tree().paused = true
# Usually we show a "Press Start to Resume" screen or modal here
func _handle_focus_gain() -> void:
print("[ConsoleCompliance] Focus GAINED")
focus_gained.emit()
# TRC Requirement: Do not auto-unpause if the game was paused by player before focus loss.
# Best practice: Remain paused and wait for user input.
func notify_save_start() -> void:
_is_saving = true
# TRC Requirement: Indicate clearly when saving is happening
if save_icon:
save_icon.show()
# Platform-specific "Saving..." overlay call could go here
func notify_save_end() -> void:
_is_saving = false
if save_icon:
save_icon.hide()
## EXPERT USAGE:
## ComplianceHandler.notify_save_start() -> await save() -> notify_save_end()
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/inputs/custom_mouse_cursor.html
# - https://docs.godotengine.org/en/stable/tutorials/inputs/handling_quit_requests.html
# - https://docs.godotengine.org/en/stable/tutorials/io/saving_games.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-input-handling/SKILL.md — mouse mode hidden for controller-only
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-ui-containers/SKILL.md — save icon / overlay Control visibility
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/console_shader_manager.gd
class_name ConsoleShaderManager extends Node
## Manages GPU-specific shader binary compilation.
func get_device_uuid() -> String:
var rd := RenderingServer.get_rendering_device()
if rd:
# Unique ID for the specific GPU and Driver.
return rd.get_device_pipeline_cache_uuid()
return ""
scripts/controller_prompt_mapper.gd
class_name ControllerPromptMapper
extends RefCounted
## Expert GUID-based Icon Routing for Console UI.
## Detects hardware type to display correct button prompts (PS/Xbox/Switch).
static func get_prompt_path(device_id: int) -> String:
var guid = Input.get_joy_guid(device_id)
var name = Input.get_joy_name(device_id).to_lower()
# Detect platform from standardized SDL2 identifiers
if "nintendo" in name or "switch" in name:
return "res://ui/prompts/nintendo_set.tres"
elif "ps4" in name or "ps5" in name or "dual" in name:
return "res://ui/prompts/playstation_set.tres"
else:
# Fallback to Xbox/XInput standard
return "res://ui/prompts/xbox_set.tres"
## Rule: Always display SVG-based prompts for high-DPI console displays.
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html
# - https://docs.godotengine.org/en/stable/classes/class_input.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-input-handling/SKILL.md — GUID/name based device identity
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-ui-containers/SKILL.md — swapping prompt icons in menus
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/controller_telemetry.gd
class_name ControllerTelemetry extends Node
## Tracks controller states and hardware metadata.
func _ready() -> void:
Input.joy_connection_changed.connect(_on_joy_changed)
func _on_joy_changed(id: int, connected: bool) -> void:
if connected:
var info := Input.get_joy_info(id)
# Tracks hardware GUID and XInput index for telemetry logs.
print("Controller %d: %s" % [id, info.get("xinput_index", "Native")])
scripts/memory_budget_guard.gd
class_name MemoryBudgetGuard
extends Node
## Expert RAM Monitoring for Console-specific budgets (e.g. Nintendo Switch).
## Triggers aggressive resource cleanup when thresholds are reached.
@export var ram_limit_mb: int = 3072 # Switch retail ~3GB; PS/Xbox SKUs often 4096–5120 — tune per export preset
@export var cleanup_threshold_pct: float = 0.85
func _ready() -> void:
# Check memory periodically
var timer = Timer.new()
timer.wait_time = 5.0
timer.autostart = true
timer.timeout.connect(_check_memory)
add_child(timer)
func _check_memory() -> void:
var usage_mb = OS.get_static_memory_usage() / 1024 / 1024
if usage_mb > (ram_limit_mb * cleanup_threshold_pct):
_trigger_emergency_cleanup()
func _trigger_emergency_cleanup() -> void:
print("Console: RAM budget reached threshold. Clearing caches.")
# Expert: Flush ResourceLoader cache and force GC
# Note: This is a heavy operation, only use as a fail-safe.
pass
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_os.html
# - https://docs.godotengine.org/en/stable/classes/class_performance.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-debugging-profiling/SKILL.md — RAM monitors and budget alerts
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-scene-management/SKILL.md — unload strategies when threshold hits
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/performance_scaler_fsr.gd
class_name PerformanceScalerFSR
extends Node
## Expert Dynamic Resolution Scaling and FSR 2.2 management.
## Optimized for weak hardware (Nintendo Switch) using temporal upscaling.
func apply_performance_profile(viewport: Viewport, profile: StringName = &"balanced") -> void:
# Forward+ renderer supports FSR2 natively
viewport.scaling_3d_mode = Viewport.SCALING_3D_MODE_FSR2
match profile:
&"performance":
viewport.scaling_3d_scale = 0.5 # 540p -> 1080p
viewport.fsr_sharpness = 0.4
&"balanced":
viewport.scaling_3d_scale = 0.67 # ~720p -> 1080p
viewport.fsr_sharpness = 0.2
&"quality":
viewport.scaling_3d_scale = 0.85
viewport.fsr_sharpness = 0.1
## Expert: Lower mipmap bias automatically follows scaling_3d_scale in Godot 4.
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/3d/resolution_scaling.html
# - https://docs.godotengine.org/en/stable/tutorials/rendering/multiple_resolutions.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — when FSR2 beats lowering effects
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-debugging-profiling/SKILL.md — validating locked FPS after scale changes
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/platform_console_patterns.gd
# platform_console_patterns.gd
extends Node
# 1. Dynamically Polling Active Controllers
# EXPERT NOTE: Joypad 0 is not always Player 1. Always query active connections.
func get_active_players() -> Array[int]:
return Input.get_connected_joypads()
# 2. Extracting Analog Stick Vectors with Deadzones
# EXPERT NOTE: Accounts for hardware drift automatically across multiple axis.
func get_movement_vector() -> Vector2:
return Input.get_vector(&"move_left", &"move_right", &"move_up", &"move_down")
# 3. Applying Controller Haptics
# EXPERT NOTE: Finite duration prevents motor burnout and respects hardware limits.
func trigger_damage_feedback(device_id: int) -> void:
# device_id, weak_motor, strong_motor, duration_sec
Input.start_joy_vibration(device_id, 0.5, 1.0, 0.2)
# 4. Looking up Controller GUIDs for Profiling
# EXPERT NOTE: Use for hardware-specific mapping adjustments (SDL2 compatible).
func get_gamepad_profile(device_id: int) -> String:
return Input.get_joy_guid(device_id)
# 5. programmatic UI Focus for Gamepads
# EXPERT NOTE: Essential for console UI accessibility.
func grab_initial_menu_focus(container: Control) -> void:
var first_btn := container.get_child(0) as Control
if first_btn:
first_btn.grab_focus()
# 6. Adjusting 3D Resolution Scaling (FSR)
# EXPERT NOTE: Maintain 60 FPS on lower-tier console hardware.
func enable_performance_scaling(viewport: Viewport) -> void:
viewport.scaling_3d_mode = Viewport.SCALING_3D_MODE_FSR
viewport.scaling_3d_scale = 0.75 # Sub-native render, upscale with FSR
# 7. Exact Input Matching
# EXPERT NOTE: Prevents overlapping action triggers in complex mappings.
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(&"jump", false, true): # Exact match
print("Jump executed!")
# 8. Setting up Dynamic UI Neighbors
# EXPERT NOTE: Manually override focus flow for non-standard layouts.
func link_ui_nodes(btn: Control, neighbor_path: NodePath) -> void:
btn.set_focus_neighbor(SIDE_BOTTOM, neighbor_path)
# 9. Frame-Perfect Input Interception
# EXPERT NOTE: Flush the buffer before critical time-sensitive checks.
func process_combat_frame() -> void:
if Input.is_action_just_pressed(&"attack"):
Input.flush_buffered_events()
# logic...
# 10. Assigning Multi-Player Authority
# EXPERT NOTE: Map inputs to specific players in local coop or split-screen.
func setup_player_authority(player_node: Node, device_id: int) -> void:
player_node.set_multiplayer_authority(device_id)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html
# - https://docs.godotengine.org/en/stable/tutorials/inputs/controller_features.html
# - https://docs.godotengine.org/en/stable/tutorials/inputs/inputevent.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-input-handling/SKILL.md — get_vector deadzones and joypad slots
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-party/SKILL.md — multi-pad active player polling
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/platform_dialog_invoker.gd
class_name PlatformDialogInvoker
extends Node
## Abstract interface for native Console dialogs (Keyboard, Prompts).
## Detects the platform and routes to the appropriate OS handler.
func show_virtual_keyboard(title: String, existing_text: String = "") -> void:
if OS.has_feature("mobile") or OS.has_feature("console"):
# Expert: DisplayServer.virtual_keyboard_show handles most platform-native input
DisplayServer.virtual_keyboard_show(existing_text, Rect2(0,0,0,0))
else:
# PC Fallback for dev testing
pass
func show_system_dialog(title: String, message: String) -> void:
# Implementation varies by native GDExtension bridge
pass
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_displayserver.html
# - https://docs.godotengine.org/en/stable/tutorials/export/feature_tags.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-ui-containers/SKILL.md — falling back when native dialogs unavailable
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-mobile/SKILL.md — virtual_keyboard_show feature parity
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
scripts/platform_overlay_manager.gd
class_name PlatformOverlayManager extends Node
## Invokes native OS dialogs for system compliance.
func show_native_alert(title: String, msg: String) -> void:
if DisplayServer.has_feature(DisplayServer.FEATURE_SUBWINDOWS):
# Native OS dialog integration.
DisplayServer.dialog_show(title, msg, ["OK"], _on_dialog_closed)
else:
# Fallback to blocking OS alert.
OS.alert(msg, title)
func _on_dialog_closed(button_index: int) -> void:
print("Native dialog closed: ", button_index)
scripts/server_side_projectile.gd
class_name ServerSideProjectile
extends RefCounted
## Expert Object Management: Bypassing the SceneTree using Server APIs.
## Offloads CPU transform propagation for thousands of entities.
var _mesh_instance_rid: RID
var _body_rid: RID
func _init(world_2d_or_3d_rid: RID, scenario_rid: RID, mesh_rid: RID, shape_rid: RID) -> void:
# Directly allocate physics on the C++ PhysicsServer
_body_rid = PhysicsServer3D.body_create() # Change to 2D if needed
PhysicsServer3D.body_set_space(_body_rid, world_2d_or_3d_rid)
PhysicsServer3D.body_add_shape(_body_rid, shape_rid)
# Directly allocate visuals on the GPU RenderingServer
_mesh_instance_rid = RenderingServer.instance_create()
RenderingServer.instance_set_base(_mesh_instance_rid, mesh_rid)
RenderingServer.instance_set_scenario(_mesh_instance_rid, scenario_rid)
func update_transform(new_transform: Transform3D) -> void:
# O(1) direct memory access, bypassing Node traversal
PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, new_transform)
RenderingServer.instance_set_transform(_mesh_instance_rid, new_transform)
func destroy() -> void:
PhysicsServer3D.free_rid(_body_rid)
RenderingServer.free_rid(_mesh_instance_rid)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_renderingserver.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — RID/server paths vs Node swarms
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-physics-3d/SKILL.md — PhysicsServer3D body lifecycle for projectiles
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-console/SKILL.md
# =============================================================================
SKILL.md
---
name: godot-platform-console
description: "Expert blueprint for console platforms (PlayStation, Xbox, Nintendo Switch) covering controller-first UI, certification requirements (TRCs/TCRs), platform services (achievements, cloud saves), and performance compliance. Use when targeting console releases or implementing gamepad-only interfaces. Keywords console, PlayStation, Xbox, Switch, TRC, TCR, certification, controller, gamepad, achievements."
---
# Platform: Console
Controller-first design, certification compliance, and locked frame rates define console development.
## NEVER Do
- **NEVER show a mouse cursor** — Certification (TRC/TCR) failure. Hide with `Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)`.
- **NEVER skip pausing on focus loss** — Monitor `NOTIFICATION_APPLICATION_FOCUS_OUT` and force a pause.
- **NEVER let a controller disconnect go unhandled** — Force pause and show reconnect UI.
- **NEVER use an unlocked frame rate** — Lock 30 or 60 FPS via `Engine.max_fps` and enable VSync.
- **NEVER forget D-Pad navigation** — Analog-only menus fail accessibility/TRC. Support D-Pad for all menus.
- **NEVER hardcode button labels** — Use GUID-based prompt mapping (`controller_prompt_mapper.gd`), not "Press A".
- **NEVER exceed hardware memory limits** — Profile RAM; Switch budgets are rigid.
- **NEVER assume Joypad 0 is always Player 1** — Query `Input.get_connected_joypads()`.
- **NEVER distribute console export templates or SDKs publicly** — NDA-bound.
- **NEVER handle continuous analog sticks with boolean checks** — Use `get_vector()` / `get_action_strength()`.
- **NEVER vibrate continuously without a disable option** — Finite `Input.start_joy_vibration()` + accessibility toggle.
- **NEVER expect OS window APIs on consoles** — `DisplayServer.window_set_mode()` is ignored/fails.
- **NEVER map UI to raw button indices** — Use Project Input Map (`ui_accept`, `ui_cancel`, custom actions).
- **NEVER rely on `NOTIFICATION_WM_CLOSE_REQUEST` for termination** — Consoles suspend; handle focus/suspend paths.
- **NEVER query inputs without flushing when frame-perfect** — `Input.flush_buffered_events()` before critical checks.
- **NEVER use `==` / `!=` on analog trigger axes** — Use `is_equal_approx()`.
- **NEVER leave orphaned nodes across scene transitions** — Strict RAM; `queue_free()` and break cycles.
- **NEVER write to `res://` at runtime** — Use `user://` only.
- **NEVER save synchronously on the main thread** — Offload; atomic `.tmp` then rename.
---
## Available Scripts
> **MANDATORY**: Read the appropriate script before implementing the corresponding pattern.
### [certification_manager.gd](scripts/certification_manager.gd)
Expert TRC/TCR compliance (focus loss, controller disconnects).
### [performance_scaler_fsr.gd](scripts/performance_scaler_fsr.gd)
Dynamic Resolution Scaling and FSR 2.2 management for console performance.
### [server_side_projectile.gd](scripts/server_side_projectile.gd)
Direct RenderingServer/PhysicsServer bypass for high-frequency objects.
### [async_save_manager.gd](scripts/async_save_manager.gd)
Atomic, corruption-resistant threaded save system.
### [controller_prompt_mapper.gd](scripts/controller_prompt_mapper.gd)
GUID-based button prompt detection (PlayStation/Xbox/Switch).
### [memory_budget_guard.gd](scripts/memory_budget_guard.gd)
Strict RAM monitoring for platform-specific hardware budgets.
### [platform_dialog_invoker.gd](scripts/platform_dialog_invoker.gd)
Native OS dialog and virtual keyboard abstraction.
### [background_data_prefetcher.gd](scripts/background_data_prefetcher.gd)
Asset pre-fetching using WorkerThreadPool to avoid level-load stutters.
### [achievement_offline_queue.gd](scripts/achievement_offline_queue.gd)
Achievement/Trophy caching with offline persistence.
### [console_boot_config.gd](scripts/console_boot_config.gd)
Hardware-aware hardware initialization and rendering overrides.
---
## Certification Golden Path (MANDATORY scripts)
Run this checklist in order for a console-ready vertical slice. **Do NOT Load** optional scripts unless the row below says optional.
| Step | MANDATORY script | Do NOT Load (unless needed) |
| :--- | :--- | :--- |
| 1. Boot | [console_boot_config.gd](scripts/console_boot_config.gd) | [server_side_projectile.gd](scripts/server_side_projectile.gd) — RID bypass, not cert |
| 2. Focus / disconnect | [certification_manager.gd](scripts/certification_manager.gd) | — |
| 3. Save atomicity | [async_save_manager.gd](scripts/async_save_manager.gd) | — |
| 4. FPS / scaler / RAM | [performance_scaler_fsr.gd](scripts/performance_scaler_fsr.gd) + [memory_budget_guard.gd](scripts/memory_budget_guard.gd) | Switch: set `ram_limit_mb` ≈ **3072** (retail) / warn at **3584**; PS/Xbox: **4096–5120** per SKU — see script `@export` |
| 5. Prompts | [controller_prompt_mapper.gd](scripts/controller_prompt_mapper.gd) | — |
**Optional only:** [achievement_offline_queue.gd](scripts/achievement_offline_queue.gd), [platform_dialog_invoker.gd](scripts/platform_dialog_invoker.gd), [background_data_prefetcher.gd](scripts/background_data_prefetcher.gd). **Do NOT Load** these during steps 1–5 unless achievements, system dialogs, or prefetch are in scope.
## Input Handling (Input Map — not raw indices)
```gdscript
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_accept"):
on_confirm()
elif event.is_action_pressed("ui_cancel"):
on_cancel()
# Prompts: MANDATORY controller_prompt_mapper.gd for face-button glyphs
```
## Expert Techniques
### TRC failure → fix (symptom → script → doc)
| Symptom | Fix script | Doc |
| :--- | :--- | :--- |
| Mouse pointer visible in game UI | Hide via Input Map flow + `Input.MOUSE_MODE_HIDDEN` in boot | [Custom mouse cursor](https://docs.godotengine.org/en/stable/tutorials/inputs/custom_mouse_cursor.html) |
| Game runs when dashboard/home pressed | [certification_manager.gd](scripts/certification_manager.gd) focus-out pause | [Handling quit requests](https://docs.godotengine.org/en/stable/tutorials/inputs/handling_quit_requests.html) |
| "Press A" hardcoded on Switch | [controller_prompt_mapper.gd](scripts/controller_prompt_mapper.gd) GUID glyphs | [Controllers, gamepads, and joysticks](https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html) |
| Save corruption on power loss | [async_save_manager.gd](scripts/async_save_manager.gd) `.tmp` rename | [Saving games](https://docs.godotengine.org/en/stable/tutorials/io/saving_games.html) |
| Frame time spikes / TRC perf fail | [performance_scaler_fsr.gd](scripts/performance_scaler_fsr.gd) + RAM guard | [Resolution scaling](https://docs.godotengine.org/en/stable/tutorials/3d/resolution_scaling.html) |
### 1. Platform-Overlay-Manager (Native UI Dialogs)
Prefer [platform_dialog_invoker.gd](scripts/platform_dialog_invoker.gd) / [platform_overlay_manager.gd](scripts/platform_overlay_manager.gd) / `DisplayServer.dialog_show()` for TRC system messages over custom modal stacks.
### 2. Shader-Binary-Caching (RenderingDevice)
Enable shader/pipeline cache on fixed console GPUs; see [console_shader_manager.gd](scripts/console_shader_manager.gd) and Official Docs pipeline compilation guidance in Reference.
### 3. Controller-Battery-Telemetry Hook
Use `Input.joy_connection_changed` + `Input.get_joy_info()` via [controller_telemetry.gd](scripts/controller_telemetry.gd); battery level often needs a platform GDExtension under NDA.
## Deep dives (on demand)
- Joypad snippets, native overlay dialogs, shader cache UUID, controller telemetry → [console-cert-patterns.md](references/console-cert-patterns.md)
## Reference
> Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
### Official Documentation
- [Controllers, gamepads, and joysticks](https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html) — Joypad indexing, deadzones, get_vector/get_connected_joypads, and why device 0 is never assumed Player 1 on consoles.
- [Controller number and vibration](https://docs.godotengine.org/en/stable/tutorials/inputs/controller_features.html) — Finite start_joy_vibration durations, connection signals, and haptic accessibility toggles required by TRC/TCR.
- [Using InputEvent](https://docs.godotengine.org/en/stable/tutorials/inputs/inputevent.html) — Event flow for InputEventJoypadButton/Motion, Input Map actions, and buffered flush before frame-critical checks.
- [Custom mouse cursor](https://docs.godotengine.org/en/stable/tutorials/inputs/custom_mouse_cursor.html) — Input.set_mouse_mode / hidden cursor so a visible pointer does not fail console certification.
- [Handling quit requests](https://docs.godotengine.org/en/stable/tutorials/inputs/handling_quit_requests.html) — Focus-out / suspend paths versus NOTIFICATION_WM_CLOSE_REQUEST, which consoles often never emit.
- [Keyboard, mouse, and controller UI navigation](https://docs.godotengine.org/en/stable/tutorials/ui/gui_navigation.html) — Focus neighbors and D-Pad/gamepad UI traversal required when analog-only menus fail accessibility/TRC.
- [Resolution scaling](https://docs.godotengine.org/en/stable/tutorials/3d/resolution_scaling.html) — Viewport FSR2 / scaling_3d_scale profiles used to hold locked 30/60 FPS on weak SKUs.
- [Saving games](https://docs.godotengine.org/en/stable/tutorials/io/saving_games.html) — user:// persistence, save indicators, and why res:// writes are invalid on exported console builds.
- [Background loading](https://docs.godotengine.org/en/stable/tutorials/io/background_loading.html) — Threaded ResourceLoader prefetch so slow console storage does not hitch level transitions.
- [Using multiple threads](https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html) — WorkerThreadPool offload for atomic saves and prefetch without main-thread TCR frame spikes.
- [Feature tags](https://docs.godotengine.org/en/stable/tutorials/export/feature_tags.html) — OS.has_feature / export tags that gate console boot overrides (VSync, max FPS, low-end GI).
- [Reducing stutter from shader/pipeline compilations](https://docs.godotengine.org/en/stable/tutorials/performance/pipeline_compilations.html) — Shader/pipeline caching on fixed console GPUs to avoid first-use hitch rejections.
### Related Skills
#### Prerequisites
- [godot-project-foundations](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-project-foundations/SKILL.md) — Project layout, Input Map, and export/user paths before certification hooks and console boot overrides.
- [godot-input-handling](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-input-handling/SKILL.md) — Joypad actions, deadzones, and device remapping that controller-first UI and prompt mappers build on.
- [godot-gdscript-mastery](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-gdscript-mastery/SKILL.md) — Typed notifications, signals, and thread-safe call patterns used by compliance and async save managers.
#### Complements
- [godot-export-builds](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-export-builds/SKILL.md) — Export presets, feature tags, and template discipline (console SDKs stay NDA-bound outside this skill).
- [godot-save-load-systems](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-save-load-systems/SKILL.md) — Atomic rename, cloud-ready slots, and save UX that TRC save indicators wrap.
- [godot-ui-containers](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-ui-containers/SKILL.md) — Focusable Control trees and D-Pad neighbor graphs for gamepad-only menus.
- [godot-performance-optimization](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md) — Frame budgets, FSR scaling, and Server-side entity patterns that keep locked FPS under TCR.
- [godot-debugging-profiling](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-debugging-profiling/SKILL.md) — Memory/profiler tabs and monitors used to enforce Switch-class RAM ceilings.
- [godot-scene-management](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-scene-management/SKILL.md) — Aggressive queue_free / load queues so scene transitions stay inside console RAM budgets.
- [godot-resource-data-patterns](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-resource-data-patterns/SKILL.md) — Resource caching and unload strategies paired with memory budget guards.
#### Downstream / consumers
- [godot-platform-desktop](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-desktop/SKILL.md) — Dual-ship PC builds that must share Input Map/actions while keeping console mouse-hidden and FPS-locked paths.
- [godot-platform-mobile](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-platform-mobile/SKILL.md) — Shared focus-loss / suspend pause patterns when the same title also targets handhelds.
- [godot-multiplayer-networking](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-multiplayer-networking/SKILL.md) — Online matchmaking/friends hooks that sit beside achievement queues and platform overlays.
- [godot-genre-party](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-party/SKILL.md) — Multi-pad local play that consumes dynamic joypad slot discovery and prompt mapping.
#### Master
- [godot-master](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-master/SKILL.md) — Library router and mirrored module entry for cross-skill discovery.