create-resource
Skill2 starsChanged 6 months agoMITView on GitHub
Generate a custom Resource class for game data — Item, Ability, EnemyStats, DialogueLine, LevelConfig. Provides @export schema, validation, and one example .tres instance. Replaces Dictionary-literal data.
In this repository33 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- bootstrap-godot-projectSkill
- codebase-surveySkill
- create-autoloadSkill
- create-componentSkill
- create-sceneSkill
- create-state-machineSkill
- export-configSkill
- feature-planSkill
- feature-specSkill
- game-brainstormingSkill
- gdd-writerSkill
- genre-pack-3d-actionSkill
- genre-pack-platformerSkill
- genre-pack-topdownSkill
- genre-pack-turnbasedSkill
- godot-patternsSkill
- gut-test-writerSkill
- networking-foundationSkill
- performance-auditSkill
- save-schema-migrationSkill
- setup-collision-layersSkill
- setup-git-godotSkill
- setup-input-mapSkill
- setup-localizationSkill
- setup-save-systemSkill
- sfx-generatorSkill
- shader-writerSkill
- subagent-dev-modeSkill
- ui-patterns-godotSkill
- update-docsSkill
- using-godot-superpowersSkill
- writing-game-planSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Use Dictionary only for transient runtime payloads (state machine state, signal arguments, network packets).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Create Resource
Generate a custom Resource class so designers (or a future you) can author data as .tres files in the editor instead of hardcoded Dictionary literals.
Why Resources over Dictionaries
| Concern | Dictionary | Custom Resource |
| Type safety | none (Variant) | typed @export fields |
| Editor authoring | code only | Inspector with field hints |
| Validation | runtime checks | @export_range, @export_enum, etc. |
| Refactor rename | grep | rename in script, all .tres re-resolve |
| Save/load | fragile | first-class, ResourceSaver.save |
| Diff in git | unstructured | clean key=value text |
Use Dictionary only for transient runtime payloads (state machine state, signal arguments, network packets).
Template — basic Resource
class_name {Name}
extends Resource
@export var id: StringName
@export var display_name: String
# add fields hereSave to scripts/resources/{snake_case}.gd. Then in the FileSystem dock right-click → New Resource → {Name} to author .tres instances under resources/{plural}/.
Common templates
Item
class_name Item
extends Resource
@export var id: StringName
@export var display_name: String
@export_multiline var description: String
@export var icon: Texture2D
@export var max_stack: int = 1
@export var value: int = 0
@export_enum("Common", "Uncommon", "Rare", "Epic", "Legendary") var rarity: int = 0
@export var tags: Array[StringName] = []
@export var on_use: Script ## script that defines a static use(actor: Node) -> voidAbility / Spell
class_name Ability
extends Resource
@export var id: StringName
@export var display_name: String
@export_multiline var description: String
@export var icon: Texture2D
@export var cooldown: float = 1.0
@export var resource_cost: int = 0 ## mana / energy / stamina
@export_range(0.0, 50.0, 0.5) var range: float = 5.0
@export var damage: int = 0
@export var effect_scene: PackedScene
@export var sound: AudioStream
@export var animation_name: StringName = &""
@export var tags: Array[StringName] = [] ## "fire", "ranged", "channeled"EnemyStats
class_name EnemyStats
extends Resource
@export var id: StringName
@export var display_name: String
@export var sprite_frames: SpriteFrames
@export var max_health: int = 30
@export var damage: int = 5
@export var speed: float = 80.0
@export var attack_range: float = 30.0
@export var detect_range: float = 200.0
@export var xp_drop: int = 10
@export var loot_table: LootTable ## another Resource
@export var ai_tree: PackedScene ## behavior tree sceneLootTable
class_name LootTable
extends Resource
@export var entries: Array[LootEntry] = []
func roll(rng: RandomNumberGenerator) -> Array[Item]:
var out: Array[Item] = []
for entry in entries:
if rng.randf() < entry.chance:
out.append(entry.item)
return out
class LootEntry extends Resource:
@export var item: Item
@export_range(0.0, 1.0, 0.01) var chance: float = 0.5
@export var min_count: int = 1
@export var max_count: int = 1DialogueLine
class_name DialogueLine
extends Resource
@export var speaker: StringName
@export_multiline var text: String
@export var portrait: Texture2D
@export var audio: AudioStream
@export var choices: Array[DialogueChoice] = []
@export var next_id: StringName = &"" ## empty = end of conversation
@export var conditions: Dictionary[StringName, Variant] = {}LevelConfig
class_name LevelConfig
extends Resource
@export var id: StringName
@export var display_name: String
@export var scene: PackedScene
@export var music: AudioStream
@export var ambience: AudioStream
@export_range(1, 10) var difficulty: int = 1
@export var enemy_pool: Array[EnemyStats] = []
@export var time_limit_seconds: float = 0.0 ## 0 = unlimited
@export var unlocks_on_complete: Array[StringName] = []CardData (turn-based / card games)
class_name CardData
extends Resource
@export var id: StringName
@export var display_name: String
@export var icon: Texture2D
@export var cost: int = 1
@export var attack: int = 0
@export var health: int = 1
@export var speed: int = 5
@export var card_type: StringName = &"unit" ## "unit", "spell", "trap"
@export var placement: StringName = &"any" ## "any", "own_side", "back_line"
@export var tags: Array[StringName] = []
@export_multiline var rules_text: String
@export var effect_script: Script@export annotation cheatsheet
| Annotation | Use |
@export var x: int | Basic typed export |
@export_range(0, 100) | Numeric slider with range |
@export_range(0.0, 1.0, 0.01) | Float with step |
@export_enum("A", "B", "C") | Picklist (stores int by default; add :String for string) |
@export_multiline var s: String | Multi-line text editor |
@export_file("*.png") | File picker filtered |
@export_dir | Directory picker |
@export_node_path(NodeType) | Typed node path picker |
@export_color_no_alpha | Color without alpha slider |
@export_flags("Fire:1", "Ice:2", "Wind:4") | Bit flags multi-select |
@export_storage | Saved but not shown in editor |
@export_custom(...) | Custom hint (advanced) |
@export_group("Combat") | Group following exports |
@export_subgroup("Attack") | Sub-group |
@export_category("Visual") | Top-level category |
Resource-with-methods
Resources can have logic, not just fields:
class_name Stat
extends Resource
@export var base: float = 10.0
@export var modifiers: Array[StatModifier] = []
func get_value() -> float:
var value := base
var add := 0.0
var mult := 1.0
for m in modifiers:
match m.kind:
StatModifier.Kind.FLAT: value += m.amount
StatModifier.Kind.PERCENT_ADD: add += m.amount
StatModifier.Kind.PERCENT_MULT: mult *= 1.0 + m.amount
return (value + value * add) * mult
class StatModifier extends Resource:
enum Kind { FLAT, PERCENT_ADD, PERCENT_MULT }
@export var kind: Kind = Kind.FLAT
@export var amount: float = 0.0
@export var source: StringName = &""Common gotchas
- Shared instances:
load("res://x.tres")returns the same Resource every call. If you mutate it (e.g. add modifiers to a Stat), you mutate it for everyone. Call.duplicate(true)for deep copy. - Inner classes (
class X extends Resource) work but their.tresfiles become hard to instantiate from the editor — prefer top-levelclass_name. - Resource references in arrays:
@export var arr: Array[Item]works;Array[ItemSubclass]does not (Godot stores the array as base class). - Circular references: A holds B, B holds A — Godot detects cycles in 4.x but the file becomes hard to read. Prefer using IDs and resolving lazily.
- Inspector reload: editing the script while the editor has a
.tresopen can wipe values. Save scripts, close.tres, then re-open.
Authoring .tres instances
- FileSystem dock → right-click in
resources/items/→ New Resource → Item - Save as
iron_sword.tres - Edit fields in Inspector
- Reference from another resource or scene: drag
iron_sword.tresinto an@export var weapon: Itemslot
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

