project-templates

SKILL.md

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 (pause, scene transitions, scoring).

NEVER Do in Project Templates

  • NEVER hardcode scene pathsget_tree().change_scene_to_file("res://levels/level_1.tscn") in 20 places? Nightmare refactoring. Use AutoLoad + constants OR scene registry.
  • NEVER forget AutoLoad registration — Template includes game_manager.gd but not in Project Settings? Script won't load. MUST add to Project → AutoLoad.
  • NEVER use get_tree().paused without groups — Pausing entire tree = pause menu also freezes. Use process mode groups (PROCESS_MODE_PAUSABLE vs PROCESS_MODE_ALWAYS).
  • NEVER skip Input.MOUSE_MODE_CAPTURED in FPS — FPS template without mouse capture = cursor visible during gameplay. Set in player _ready().
  • NEVER copy-paste templates as-is — Using platformer template for RPG? Leads to architectural 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 B

Usage

  1. Copy template structure
  2. Rename project in project.godot
  3. Register AutoLoads
  4. Configure Input Map
  5. Begin development

Reference

Weekly Installs
1
GitHub Stars
35
First Seen
Feb 9, 2026
Installed on
amp1
opencode1
kimi-cli1
codex1
github-copilot1
gemini-cli1