
Godot Project Templates
- 192 installs
- 454 repo stars
- Updated July 28, 2026
- thedivergentai/gd-agentic-skills
Bootstrap Godot games from curated project templates with scenes, scripts, and folder conventions suited to rapid prototyping.
About
Supplies Godot project templates with prewired scenes, scripts, and directory conventions for faster game prototyping. Helps teams skip boilerplate setup and start iterating on mechanics, UI, and export settings immediately.
- Godot 4 project scaffolds
- Scene and node hierarchy presets
- Script and autoload conventions
- Export and platform folder layout
- Rapid gameplay prototype starters
Godot Project Templates by the numbers
- 192 all-time installs (skills.sh)
- +9 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #96 of 247 Game Development 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-project-templatesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 192 |
|---|---|
| repo stars | ★ 454 |
| Last updated | July 28, 2026 |
| Repository | thedivergentai/gd-agentic-skills ↗ |
What it does
Bootstrap Godot games from curated project templates with scenes, scripts, and folder conventions suited to rapid prototyping.
Files
Project Templates
Genre-specific scaffolding, AutoLoad patterns, and modular architecture define rapid prototyping.
Available Scripts
base_game_manager.gd
Expert AutoLoad template for game state management.
base_level.gd
Abstract base class for all loaded levels with structured lifecycle hooks.
base_actor.gd
Expert foundation for all gameplay agents (Player, NPC, Enemies).
base_menu.gd
UI foundation for focus persistence, animations, and input blocking.
subsystem_locator.gd
Decoupled alternative to monolithic managers for modular registration.
multi_platform_input.gd
Template-driven Input Mapping for hardware-aware profile overrides.
platform_feature_config.gd
Conditional platform logic using Godot Feature Tags.
scene_state_machine.gd
Node-based State Machine boilerplate for visual state logic.
state_machine_node.gd
Abstract state node foundation for specialized state components.
accessibility_tts_manager.gd
Accessibility & Localization foundation using native TTS API.
level_steamer_manager.gd
Background level-loading template using load_threaded_request.
NEVER Do (Expert Anti-Patterns)
Directory & Scaffolding
- NEVER hardcode scene paths —
get_tree().change_scene_to_file("res://levels/level_1.tscn")in 20 places? Nightmare refactoring. Use AutoLoad + constants OR scene registry. - NEVER skip .gdignore for asset folders — Designer internal project files should never be imported into res:// directly.
Architecture & Lifecycle
- NEVER use `get_tree().paused` without groups — Pausing entire tree = pause menu freezes. Use process mode
PROCESS_MODE_ALWAYSon UI. - NEVER skip virtual lifecycle hooks — In base classes, always provide
_initialize_X()hooks instead of just_ready()to allow child overrides without breaking parents. - NEVER rely on monolithic "God" singletons — Decouple systems using a Signal Bus or Subsystem Locator.
Platform & UI
- NEVER skip Input.MOUSE_MODE_CAPTURED in FPS — Set in player
_ready()to ensure focus. - NEVER use floating point constants for UI layout — Leads to drift. Use anchors and containers.
- NEVER ignore i18n Translation Context — "Lead" (Metal) vs "Lead" (Action). Strictly use contexts in
translate().
Performance
- NEVER load massive levels synchronously — Causes frame freezes. Strictly use
ResourceLoader.load_threaded_request(). - NEVER copy-paste templates as-is — Using platformer template for RPG? Leads to debt. UNDERSTAND the structure, then adapt.
---
Directory Structure
my_platformer/
├── project.godot
├── autoloads/
│ ├── game_manager.gd
│ ├── audio_manager.gd
│ └── scene_transitioner.gd
├── scenes/
│ ├── main_menu.tscn
│ ├── game.tscn
│ └── pause_menu.tscn
├── entities/
│ ├── player/
│ │ ├── player.tscn
│ │ ├── player.gd
│ │ └── player_states/
│ └── enemies/
│ ├── base_enemy.gd
│ └── goblin/
├── levels/
│ ├── level_1.tscn
│ └── tilesets/
├── ui/
│ ├── hud.tscn
│ └── themes/
├── audio/
│ ├── music/
│ └── sfx/
└── resources/
└── data/Core Scripts
game_manager.gd:
extends Node
signal game_started
signal game_paused(paused: bool)
signal level_completed
var current_level: int = 1
var score: int = 0
var is_paused: bool = false
func start_game() -> void:
score = 0
current_level = 1
SceneTransitioner.change_scene("res://levels/level_1.tscn")
game_started.emit()
func pause_game(paused: bool) -> void:
is_paused = paused
get_tree().paused = paused
game_paused.emit(paused)
func complete_level() -> void:
current_level += 1
level_completed.emit()---
Top-Down RPG Template
Directory Structure
my_rpg/
├── autoloads/
│ ├── game_data.gd
│ ├── dialogue_manager.gd
│ └── inventory_manager.gd
├── entities/
│ ├── player/
│ ├── npcs/
│ └── interactables/
├── maps/
│ ├── overworld/
│ ├── dungeons/
│ └── interiors/
├── systems/
│ ├── combat/
│ ├── dialogue/
│ ├── quests/
│ └── inventory/
├── ui/
│ ├── inventory_ui.tscn
│ ├── dialogue_box.tscn
│ └── quest_log.tscn
└── resources/
├── items/
├── quests/
└── dialogues/Core Systems
inventory_manager.gd:
extends Node
signal item_added(item: Resource)
signal item_removed(item: Resource)
var inventory: Array[Resource] = []
func add_item(item: Resource) -> void:
inventory.append(item)
item_added.emit(item)
func remove_item(item: Resource) -> bool:
if item in inventory:
inventory.erase(item)
item_removed.emit(item)
return true
return false
func has_item(item_id: String) -> bool:
for item in inventory:
if item.id == item_id:
return true
return false---
3D FPS Template
Directory Structure
my_fps/
├── autoloads/
│ ├── game_manager.gd
│ └── weapon_manager.gd
├── player/
│ ├── player.tscn
│ ├── player.gd
│ ├── camera_controller.gd
│ └── weapons/
│ ├── weapon_base.gd
│ ├── pistol/
│ └── rifle/
├── enemies/
│ ├── ai_controller.gd
│ └── soldier/
├── levels/
│ ├── level_1/
│ └── level_2/
├── ui/
│ ├── hud.tscn
│ └── crosshair.tscn
└── resources/
├── weapons/
└── pickups/Player Controller
player.gd:
extends CharacterBody3D
@export var speed := 5.0
@export var jump_velocity := 4.5
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
@onready var camera: Camera3D = $Camera3D
@onready var weapon_holder: Node3D = $Camera3D/WeaponHolder
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y -= gravity * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_backward")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
move_and_slide()---
Input Map Template
# All templates should include these actions:
[input]
move_left=Keys: A, Left, Gamepad Left
move_right=Keys: D, Right, Gamepad Right
move_up=Keys: W, Up, Gamepad Up
move_down=Keys: S, Down, Gamepad Down
jump=Keys: Space, Gamepad A
interact=Keys: E, Gamepad X
pause=Keys: Escape, Gamepad Start
ui_accept=Keys: Enter, Gamepad A
ui_cancel=Keys: Escape, Gamepad BUsage
1. Copy template structure 2. Rename project in project.godot 3. Register AutoLoads 4. Configure Input Map 5. Begin development
Expert Template Patterns
1. Folder-by-Feature (Entity-Centric)
The professional standard for scalable Godot project organization.
- The Rule: Keep all resources related to a game entity (scripts, scenes, textures, local resources) in the same directory (e.g.,
res://entities/player/). - Benefit: Simplifies refactoring, enables easier asset migration between projects, and prevents the "monolithic scripts folder" bottleneck.
2. Standard-Export-Presets (Platform Stability)
Optimized configurations for high-fidelity exports.
- VRAM Compression: Ensure
textures/vram_compression/import_etc2_astcis enabled for Android/mobile compatibility. - Architecture: Target
x86_64for Windows/Linux desktop andarm64-v8afor modern Android devices. - Feature Tags: Use custom feature tags (e.g.,
mobile,low_end) to conditionally load lower-resolution assets or simplified shaders at runtime.
- Versioning: Add
.importfiles to version control; they contain the vital metadata that tells Godot how to process your raw assets.
4. CI/CD-Ready Pipeline (GitHub Actions)
Automate builds headlessly using CLI flags. This ensures consistent binaries and early detection of export errors [3, 16, 17].
# .github/workflows/export.yml
jobs:
export:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Export Windows
run: godot --headless --export-release "Windows Desktop" build/game.exe5. Modular-DLC Structure (PCK Mounting)
Deliver content updates or patches without exposing source code. Use ProjectSettings.load_resource_pack() to mount external assets into res:// [4, 6].
func load_dlc(path: String):
if ProjectSettings.load_resource_pack(path):
# Assets in PCK override existing res:// paths
var new_scene = load("res://dlc_level.tscn")6. System-Bootstrap-Priority
Control AutoLoad initialization order using a central BootstrapManager. This replaces the linear Project Settings list with a prioritized script [19, 20].
# BootstrapManager.gd (The only Autoload)
func _ready():
# 1. Start Critical Systems (Network, Config)
_add_system(NetworkManager.new())
# 2. Start Secondary Systems (Audio, UI)
_add_system(AudioManager.new())Reference
- GDSkills godot-project-foundations
Related
- Master Skill: godot-master
class_name AccessibilityTTSManager
extends Node
## Accessibility & Localization foundation for modern templates.
## Utilizes DisplayServer for native TTS and TranslationServer for i18n context.
func speak_ui_element(text: String, context: StringName = &"") -> void:
# Use context to ensure the correct translation (e.g. "Lead" metal vs "Lead" action)
var translated := TranslationServer.translate(text, context)
if DisplayServer.tts_is_speaking():
DisplayServer.tts_stop()
# Trigger system-level screen reader / TTS
var voices = DisplayServer.tts_get_voices()
if not voices.is_empty():
DisplayServer.tts_speak(translated, voices[0]["id"])
## Tool tip for templates: Use 'set_input_as_handled' in accessibility overlays.
class_name BaseActor
extends CharacterBody2D # or CharacterBody3D
## Template foundation for all gameplay agents (Player, NPC, Enemies).
## Enforces a consistent lifecycle for state transitions and combat.
signal state_changed(new_state: StringName)
signal damaged(amount: int, source: Node)
@export var actor_name: String = "Agent"
@export var faction: StringName = &"neutral"
var current_state: StringName = &"idle"
func _physics_process(delta: float) -> void:
_process_logic(delta)
## Virtual: Override for AI or input logic
func _process_logic(_delta: float) -> void:
pass
## Expert Tip: Use a dedicated method for damage to centralize logging and effects
func take_damage(amount: int, source: Node = null) -> void:
damaged.emit(amount, source)
_on_damage_received(amount, source)
func _on_damage_received(_amount: int, _source: Node) -> void:
pass
# skills/project-templates/code/base_game_manager.gd
extends Node
## Project Templates Expert Pattern
## Implements the 'Template Method' pattern for core game loops.
signal state_changed(old_state: String, new_state: String)
var _current_state: String = "INIT"
func _ready() -> void:
# 1. Abstract Initialization Loop
# Expert logic: Define the skeleton of the algorithm,
# letting subclasses override specific steps.
_bootstrap_systems()
_enter_initial_state()
# --- Template Methods (To be overridden) ---
func _bootstrap_systems() -> void:
# Logic for dependency injection, singleton checks, etc.
pass
func _enter_initial_state() -> void:
change_state("MAIN_MENU")
# --- Core Logic ---
func change_state(new_state: String) -> void:
if _current_state == new_state: return
var old_state = _current_state
_current_state = new_state
# 2. Lifecycle Hooks
# Professional pattern: Separate 'Internal Logic' from 'Extensible Hooks'.
_on_state_exit(old_state)
_on_state_enter(new_state)
state_changed.emit(old_state, new_state)
func _on_state_exit(_state: String) -> void: pass
func _on_state_enter(_state: String) -> void: pass
## EXPERT NOTE:
## Use 'Modular Initialization': Don't put everything in one script.
## Create separate 'System' nodes (e.g. SaveSystem, AudioSystem) and
## have the BaseGameManager coordinate their 'start()' and 'stop()'
## sequences to ensure correct boot order.
## NEVER hardcode scene transitions; use a centralized 'SceneLoader'
## singleton called via the 'BaseGameManager' state hooks.
## For 'project-templates', pre-configure a 'test/' directory with
## a simple GUT test that verifies the 'change_state' logic works
## before any new logic is added.
class_name BaseLevel
extends Node
## Abstract base class for all loaded levels.
## Provides structured lifecycle hooks for initialization and completion.
signal level_initialized
signal level_completed(next_level_id: StringName)
@export var level_id: StringName
func _ready() -> void:
# Standardize startup sequence
_initialize_level()
level_initialized.emit()
## Virtual method: Override for level-specific setup (NPC spawning, etc.)
func _initialize_level() -> void:
pass
## Expert: Use call_deferred to safely transition scenes and avoid physics-mid-frame errors.
func complete_level(next_id: StringName = &"") -> void:
call_deferred(&"_deferred_completion", next_id)
func _deferred_completion(next_id: StringName) -> void:
level_completed.emit(next_id if not next_id.is_empty() else level_id)
class_name BaseMenu
extends Control
## Expert foundation for all UI menus.
## Handles focus persistence, animations, and input blocking.
signal menu_closed
@onready var first_focus_node: Control = null
func open_menu() -> void:
show()
_on_menu_opened()
if first_focus_node:
first_focus_node.grab_focus()
func close_menu() -> void:
hide()
menu_closed.emit()
_on_menu_closed()
## Virtual hooks for juice (animations/sounds)
func _on_menu_opened() -> void:
pass
func _on_menu_closed() -> void:
pass
## Expert: Handle 'ui_cancel' (Escape/B) natively to close menus
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(&"ui_cancel") and is_visible_in_tree():
close_menu()
get_viewport().set_input_as_handled()
# bootstrap_config.gd
# Expert pattern for managing initialization priority and AutoLoad order.
# Grounded in architectural best practices for Godot 4.x.
extends RefCounted
class_name BootstrapConfig
## Priority list for global system initialization.
# Lower numbers initialize first.
const BOOTSTRAP_PRIORITY := {
"ConfigManager": 1,
"SaveManager": 10,
"PlayerManager": 20,
"SceneTransitioner": 30,
"AudioManager": 40,
"InputRecorder": 50
}
## Validates the current AutoLoad order against the intended bootstrap priority.
static func validate_autoload_order() -> void:
# Note: Accessing ProjectSettings via code allows runtime verification,
# but actual order is defined in project.godot.
print("Bootstrap Config: Validating initialization order...")
# Expert logic: In a real tool, this would parse project.godot
# and ensure [autoload] entries match the sorted BOOTSTRAP_PRIORITY.
for system in BOOTSTRAP_PRIORITY.keys():
print("- System: %s (Priority: %d)" % [system, BOOTSTRAP_PRIORITY[system]])
class_name LevelStreamerManager
extends Node
## Expert Dynamic Background Level-Loading.
## Streams scenes across background CPU cores using ResourceLoader.load_threaded_request.
var _loading_path: String = ""
func load_level_async(path: String) -> void:
_loading_path = path
var err = ResourceLoader.load_threaded_request(path, "", true)
if err != OK:
push_error("Streamer: Failed to request " + path)
func _process(_delta: float) -> void:
if _loading_path.is_empty(): return
var progress = []
var status = ResourceLoader.load_threaded_get_status(_loading_path, progress)
match status:
ResourceLoader.THREAD_LOAD_LOADED:
var packed = ResourceLoader.load_threaded_get(_loading_path) as PackedScene
# Standard transition in professional templates: use change_scene_to_packed
get_tree().change_scene_to_packed(packed)
_loading_path = ""
ResourceLoader.THREAD_LOAD_FAILED, ResourceLoader.THREAD_LOAD_INVALID_RESOURCE:
push_error("Streamer: Failed to load " + _loading_path)
_loading_path = ""
# modular_dlc_loader.gd
# Expert pattern for mounting external .pck files (DLC/Mods) at runtime.
# Grounded in Godot 4.x ProjectSettings.load_resource_pack.
extends Node
class_name ModularDLCLoader
## Loads a resource pack (.pck or .zip) into the virtual filesystem.
static func load_dlc(path: String, replace_files: bool = true) -> bool:
if not FileAccess.file_exists(path):
push_error("DLC Loader: File not found at %s" % path)
return false
# Mount the PCK
var success = ProjectSettings.load_resource_pack(path, replace_files)
if success:
print("DLC Loader: Successfully mounted %s" % path)
else:
push_error("DLC Loader: Failed to mount %s" % path)
return success
## Scans a folder for DLC packs and loads them all.
static func load_all_dlc_in_folder(folder_path: String) -> void:
var dir = DirAccess.open(folder_path)
if dir:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if file_name.ends_with(".pck"):
load_dlc(folder_path + "/" + file_name)
file_name = dir.get_next()
class_name MultiPlatformInput
extends Node
## Template-driven Input Mapping for varied hardware (Console, Mobile, VR).
## Dynamically adds actions or modifies deadzones based on detected platform.
func _ready() -> void:
_configure_platform_inputs()
func _configure_platform_inputs() -> void:
if OS.has_feature("mobile"):
# Mobile specific gestures would be handled in a touch layer
pass
elif OS.has_feature("pc"):
# Ensure mouse-specific actions exist
_add_or_update_action(&"click", InputEventMouseButton.new())
# Console-specific deadzone tuning
_tune_deadzones()
func _add_or_update_action(action: StringName, event: InputEvent) -> void:
if not InputMap.has_action(action):
InputMap.add_action(action)
InputMap.action_add_event(action, event)
func _tune_deadzones() -> void:
# Iterate through all actions and apply a global threshold for gamepads
for action in InputMap.get_actions():
# Expert: Apply specific deadzones to joypad axes
pass
class_name PlatformFeatureConfig
extends Node
## Use Godot's built-in Feature Tags to conditionally execute logic.
## Strips server logic from client builds and manages mobile-specific overrides.
@export var mobile_max_fps: int = 60
@export var desktop_max_fps: int = 144
func _ready() -> void:
_apply_platform_overrides()
func _apply_platform_overrides() -> void:
if OS.has_feature("dedicated_server"):
# Start headless multiplayer server
_initialize_server_logic()
elif OS.has_feature("mobile"):
# Lower rendering overhead for Android/iOS
_apply_mobile_profile()
elif OS.has_feature("pc"):
_apply_desktop_profile()
func _apply_mobile_profile() -> void:
# Disable heavy post-processing
get_viewport().use_taa = false
Engine.max_fps = mobile_max_fps
func _apply_desktop_profile() -> void:
Engine.max_fps = desktop_max_fps
func _initialize_server_logic() -> void:
# Disable visual processing in headless mode
set_process(false)
set_physics_process(true)
class_name SceneStateMachine
extends Node
## Node-based State Machine boilerplate.
## Delegates engine callbacks (_physics_process, _input) from parent to active state.
@export var initial_state: StateMachineNode
@onready var current_state: StateMachineNode = initial_state
func _ready() -> void:
# Auto-register this machine into all child states
for child in get_children():
if child is StateMachineNode:
child.state_machine = self
if current_state:
current_state.enter()
func _physics_process(delta: float) -> void:
if current_state:
current_state.physics_update(delta)
func _unhandled_input(event: InputEvent) -> void:
if current_state:
current_state.handle_input(event)
func transition_to(target_name: StringName) -> void:
if not has_node(str(target_name)):
push_error("StateMachine: State %s not found." % target_name)
return
current_state.exit()
current_state = get_node(str(target_name))
current_state.enter()
class_name StateMachineNode
extends Node
## Abstract state node to be used inside a SceneStateMachine.
## Override these methods in specific state scenes/scripts.
var state_machine: SceneStateMachine
func enter() -> void:
pass
func exit() -> void:
pass
func physics_update(_delta: float) -> void:
pass
func handle_input(_event: InputEvent) -> void:
pass
## Expert: Call state_machine.transition_to(&"NewState") to switch.
## Subsystem Locator Pattern (Autoload: Subsystems)
## A decoupled alternative to monolithic managers.
## Allows systems to register themselves without requiring hard-coded paths.
extends Node
var _registry: Dictionary = {}
func register(id: StringName, instance: Node) -> void:
_registry[id] = instance
print("Subsystem Registered: ", id)
func unregister(id: StringName) -> void:
_registry.erase(id)
func get_system(id: StringName) -> Node:
return _registry.get(id)
## Usage Example:
## Subsystems.get_system(&"Inventory").add_item(loot)