Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
thedivergentai avatar

Godot Genre Metroidvania

  • 141 installs
  • 454 repo stars
  • Updated July 28, 2026
  • thedivergentai/gd-agentic-skills

Use godot-genre-metroidvania for development tasks

About

godot-genre-metroidvania: A skill for development. This provides functionality for development workflows.

  • godot-genre-metroidvania

Godot Genre Metroidvania by the numbers

  • 141 all-time installs (skills.sh)
  • +8 installs in the week ending Jul 27, 2026 (Skillselion tracking)
  • Ranked #2,593 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-genre-metroidvania

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs141
repo stars454
Last updatedJuly 28, 2026
Repositorythedivergentai/gd-agentic-skills

What it does

Use godot-genre-metroidvania for development tasks

Files

SKILL.mdMarkdownGitHub ↗

Genre: Metroidvania

Expert blueprint for Metroidvanias balancing exploration, progression, and backtracking rewards.

NEVER Do (Expert Anti-Patterns)

World Design & Exploration

  • NEVER allow "Soft-Locks" where a player is trapped; if they enter via a one-way path ("valve"), they MUST be able to leave using current abilities. Always design fail-safe escape routes.
  • NEVER create empty dead ends; if a player backtracks to a remote area, they MUST be rewarded with a collectible, lore, or currency. Empty rooms are design failures.
  • NEVER make backtracking purely repetitive; as the player gains movement (Dash/Teleport), traversal through old areas MUST become faster. Open shortcuts to bypass long, early routes.
  • NEVER hide the critical path without "crumbs"; use distinct Landmarks, unique lighting, or environmental storytelling to build the player's mental map.
  • NEVER design abilities that serve only one purpose; strictly implement dual-use traversal and combat functionality (e.g., a "Dash" that crosses gaps and dodges attacks).

Persistence & Mapping

  • NEVER forget to save persistent room state; if a player opens a chest or defeats a boss, that state MUST remain saved when they leave and return.
  • NEVER load interconnected rooms synchronously via load(); strictly use ResourceLoader.load_threaded_request() for seamless transitions.
  • NEVER track global progression within localized room scripts; strictly use Autoload Singletons for global ability flags and world state.
  • NEVER use floating-point types for grid coordinates (minimaps/fog); strictly use Vector2i to prevent precision jitter.
  • NEVER manipulate the SceneTree directly from a background loading thread; strictly use call_deferred().

Physics & Controls

  • NEVER calculate jump arcs or dashes inside _process(); strictly use _physics_process() to prevent stutter.
  • NEVER multiply CharacterBody2D velocity by delta before move_and_slide(); the engine handles this internally.
  • NEVER poll is_action_just_pressed() inside _physics_process() for buffering; strictly capture events in _unhandled_input().
  • NEVER use standard strings for high-frequency ability checks; strictly use StringName (&"dashing") for pointer-speed comparisons.
  • NEVER iterate through every node to broadcast updates; strictly use SceneTree.call_group() for efficient mass communication.
  • NEVER delete active room/player nodes via free(); strictly use queue_free() to avoid segmentation faults.

---

🛠 Expert Components (scripts/)

Original Expert Patterns

  • minimap_fog.gd - Grid-based fog of war that tracks visited rooms and persists via global save data.
  • progression_gate_manager.gd - Central manager for ability-gated progression (Locks/Keys) and world persistence.

Modular Components

  • platformer_jump_buffer.gd - Modular coyote time and jump buffering for high-fidelity movement.
  • background_room_streamer.gd - Thread-safe background room preloading using ResourceLoader.
  • safe_scene_switcher.gd - Deferred scene transition pattern for stable cross-room world-state switching.
  • minimap_fog_revealer.gd - Vector2i-based fog-of-war clearing logic synced to player position.
  • persistent_progression_system.gd - Autoload pattern for tracking global ability/collectible flags.
  • ability_state_machine.gd - Optimized StringName pattern matching for traversal/combat states.
  • fast_wall_detector.gd - Direct PhysicsServer queries for performance-optimized wall detection.
  • save_station_broadcast.gd - Group-based entity resetting and healing logic on save interaction.
  • decoupled_hazard_logic.gd - Interface-style pattern for generic damage interaction.
  • smooth_room_camera_transition.gd - Tween-based camera limit interpolation for seamless room movement.

---

Core Loop

1. Exploration: Player explores available rooms until blocked by a "lock" (obstacle). 2. Discovery: Player finds a "key" (ability/item) or boss. 3. Acquisition: Player gains new traversal or combat ability. 4. Backtracking: Player returns to previous locks with new ability. 5. Progression: New areas open up, cycle repeats.

Skill Chain

PhaseSkillsPurpose
1. Charactergodot-characterbody-2d, state-machinesTight, responsive movement (Coyote time, buffers)
2. Worldgodot-tilemap-mastery, level-designInterconnected map, biomes, landmarks
3. Systemsgodot-save-load-systems, godot-scene-managementPersistent world state, room transitions
4. UIui-system, godot-inventory-systemMap system, inventory, HUD
5. PolishjuicinessEffects, atmosphere, environmental storytelling

Architecture Overview

1. Game State & Persistence

Metroidvanias require tracking the state of every collectible and boss across the entire world.

# game_state.gd (AutoLoad)
extends Node

var collected_items: Dictionary = {} # "room_id_item_id": true
var unlocked_abilities: Array[String] = []
var map_visited_rooms: Array[String] = []

func register_collectible(id: String) -> void:
    collected_items[id] = true
    save_game()

func has_ability(ability_name: String) -> bool:
    return ability_name in unlocked_abilities

2. Room Transitions

Seamless transitions are key. Use a SceneManager to handle instancing new rooms and positioning the player.

# door.gd
extends Area2D

@export_file("*.tscn") var target_scene_path: String
@export var target_door_id: String

func _on_body_entered(body: Node2D) -> void:
    if body.is_in_group("player"):
        SceneManager.change_room(target_scene_path, target_door_id)

3. Ability System (State Machine Integration)

Abilities should be integrated into the player's State Machine.

# player_state_machine.gd
func _physics_process(delta):
    if Input.is_action_just_pressed("jump") and is_on_floor():
        transition_to("Jump")
    elif Input.is_action_just_pressed("jump") and not is_on_floor() and GameState.has_ability("double_jump"):
        transition_to("DoubleJump")
    elif Input.is_action_just_pressed("dash") and GameState.has_ability("dash"):
        transition_to("Dash")

Key Mechanics Implementation

Map System

A grid-based or node-based map is essential for navigation.

  • Grid Map: Auto-fill cells based on player position.
  • Room State: Track "visited" status to reveal map chunks.
# map_system.gd
func update_map(player_pos: Vector2) -> void:
    var grid_pos = local_to_map(player_pos)
    if not grid_map_data.has(grid_pos):
        grid_map_data[grid_pos] = VISITED
        ui_map.reveal_cell(grid_pos)

Ability Gating (The "Lock")

Obstacles that check for specific abilities.

# breakable_wall.gd
extends StaticBody2D

@export var required_ability: String = "super_missile"

func take_damage(amount: int, ability_type: String) -> void:
    if ability_type == required_ability:
        destroy()
    else:
        play_deflect_sound()

Common Pitfalls

1. Softlocks: Ensure the player cannot get stuck in an area without the ability to leave. Design "valves" (one-way drops) carefully. 2. Backtracking Tedium: Make backtracking interesting by changing enemies, opening shortcuts, or making traversal faster with new abilities. 3. Empty Rewards: Every dead end should have a reward (health upgrade, lore, currency). 4. Lost Players: Use visual landmarks and environmental storytelling to guide players without explicit markers (e.g., "The Statue Room").

Godot-Specific Tips

  • Camera2D: Use limit_left, limit_top, etc., to confine the camera to the current room bounds. Update these limits on room transition.
  • Resource Preloading: Preload adjacent rooms for seamless open-world feel if not using hard transitions.
  • RemoteTransform2D: Use this to have the camera follow the player but stay detached from the player's rotation/scale.
  • TileMap Layers: Use separate layers for background (parallax), gameplay (collisions), and foreground (visual depth).

Design Principles (from Dreamnoid)

  • Ability Versatility: Abilities should serve both traversal and combat (e.g., a dash that dodges attacks and crosses gaps).
  • Practice Rooms: Introduce a mechanic in a safe environment before testing the player in a dangerous one.
  • Landmarks: Distinct visual features help players build a mental map.
  • Item Descriptions: Use them for "micro-stories" to build lore without interrupting gameplay.

Advanced Exploration Systems

Professional implementation of world persistence, sequence-breaking prevention, and seamless navigation.

1. Room-Metadata Resource (Persistence)

To persist room states efficiently, create a custom Resource that holds exported variables like is_cleared or items_found. Setting the resource_local_to_scene property to true ensures that the resource is uniquely duplicated upon scene instantiation, allowing each room to maintain its own state while being serializable via ResourceSaver.

class_name RoomMetadata extends Resource

@export var is_cleared: bool = false
@export var collected_item_ids: Array[StringName] = []
@export var enemy_positions: Array[Vector3] = []

func save_room_state(node: Node) -> void:
    # Logic to populate resource from current room state
    ResourceSaver.save(self, node.scene_file_path + ".tres")

2. Sequence-Breaking Protection (Ability Checks)

Prevent unintended progression by using a Singleton (Autoload) to track global player progression. Interactable objects and gates should perform safe checks against this central authority to verify prerequisites before allowing passage.

# progression_manager.gd (Autoload)
class_name ProgressionManager extends Node

var unlocked_abilities: Dictionary = {
    "double_jump": false,
    "dash": false,
    "wall_slide": false
}

func check_gate(ability_name: String) -> bool:
    return unlocked_abilities.get(ability_name, false)

func unlock_ability(id: String) -> void:
    if unlocked_abilities.has(id):
        unlocked_abilities[id] = true

3. Fast-Travel Logic

Implement fast-travel by utilizing ResourceLoader to asynchronously load target room scenes. This avoids main-thread hitches and allows for smooth transitions between distant points in the interconnected world.

class_name FastTravelSystem extends Node

func travel_to_node(scene_path: String, spawn_id: StringName) -> void:
    # Load the packed scene resource
    var room_scene := ResourceLoader.load(scene_path) as PackedScene
    if room_scene:
        # Cache the spawn ID for the next scene's _ready() call
        GlobalState.target_spawn_id = spawn_id
        get_tree().change_scene_to_packed(room_scene)

Architectural Tip: For "Rooms", use the resource_local_to_scene flag on your metadata resource to ensure that instanced rooms don't share data accidentally, which is critical for unique item pickups.

Reference

  • Master Skill: godot-master

Reference

  • Master Skill: godot-master

Related skills

Backend & APIsbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.