@jarrodmedrano/claude-skills 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.claude/skills/bevy/SKILL.md +406 -0
  2. package/.claude/skills/bevy/references/bevy_specific_tips.md +385 -0
  3. package/.claude/skills/bevy/references/common_pitfalls.md +217 -0
  4. package/.claude/skills/bevy/references/ecs_patterns.md +277 -0
  5. package/.claude/skills/bevy/references/project_structure.md +116 -0
  6. package/.claude/skills/bevy/references/ui_development.md +147 -0
  7. package/.claude/skills/domain-driven-design/SKILL.md +459 -0
  8. package/.claude/skills/domain-driven-design/references/ddd_foundations_and_patterns.md +664 -0
  9. package/.claude/skills/domain-driven-design/references/rich_hickey_principles.md +406 -0
  10. package/.claude/skills/domain-driven-design/references/visualization_examples.md +790 -0
  11. package/.claude/skills/domain-driven-design/references/wlaschin_patterns.md +639 -0
  12. package/.claude/skills/game-design-theory/SKILL.md +102 -0
  13. package/.claude/skills/game-design-theory/design-principles.md +308 -0
  14. package/.claude/skills/game-design-theory/gameplay-elements.md +213 -0
  15. package/.claude/skills/game-design-theory/player-psychology.md +175 -0
  16. package/.claude/skills/game-design-theory/playtesting.md +321 -0
  17. package/.claude/skills/game-design-theory/storytelling.md +219 -0
  18. package/.claude/skills/game-feel/SKILL.md +305 -0
  19. package/.claude/skills/game-feel/references/adsr-tuning.md +271 -0
  20. package/.claude/skills/game-feel/references/classic-profiles.md +279 -0
  21. package/.claude/skills/game-feel/references/perception-thresholds.md +160 -0
  22. package/.claude/skills/game-feel/references/polish-effects.md +246 -0
  23. package/.claude/skills/game-feel/references/simulation-recipes.md +306 -0
  24. package/.claude/skills/game-feel/references/six-metrics.md +239 -0
  25. package/.claude/skills/godot/SKILL.md +728 -0
  26. package/.claude/skills/godot/assets/templates/attribute_template.gd +109 -0
  27. package/.claude/skills/godot/assets/templates/component_template.gd +76 -0
  28. package/.claude/skills/godot/assets/templates/interaction_template.gd +108 -0
  29. package/.claude/skills/godot/assets/templates/item_resource.tres +11 -0
  30. package/.claude/skills/godot/assets/templates/spell_resource.tres +20 -0
  31. package/.claude/skills/godot/references/architecture-patterns.md +608 -0
  32. package/.claude/skills/godot/references/common-pitfalls.md +518 -0
  33. package/.claude/skills/godot/references/file-formats.md +491 -0
  34. package/.claude/skills/godot/references/godot4-physics-api.md +302 -0
  35. package/.claude/skills/godot/scripts/validate_tres.py +145 -0
  36. package/.claude/skills/godot/scripts/validate_tscn.py +170 -0
  37. package/.claude/skills/level-design/SKILL.md +249 -0
  38. package/.claude/skills/level-design/anticipatory-play.md +223 -0
  39. package/.claude/skills/level-design/hiding-linearity.md +181 -0
  40. package/.claude/skills/level-design/indie-practices.md +286 -0
  41. package/.claude/skills/level-design/open-world-planning.md +294 -0
  42. package/.claude/skills/level-design/play-personas.md +240 -0
  43. package/.claude/skills/level-design/procedural-handmade.md +271 -0
  44. package/.claude/skills/level-design/themed-environments.md +264 -0
  45. package/.claude/skills/react-three-fiber/SKILL.md +2055 -0
  46. package/.claude/skills/react-three-fiber/scripts/build-scene.ts +171 -0
  47. package/package.json +3 -1
  48. package/scripts/install.js +16 -1
  49. package/templates/github-actions/README.md +36 -0
  50. /package/.claude/{commands/design-review → agents}/design-review-agent.md +0 -0
  51. /package/.claude/{commands/code-review → agents}/pragmatic-code-review-subagent.md +0 -0
  52. /package/{.claude/commands/code-review → templates/github-actions}/claude-code-review-custom.yml +0 -0
  53. /package/{.claude/commands/code-review → templates/github-actions}/claude-code-review.yml +0 -0
  54. /package/{.claude/commands/security-review → templates/github-actions}/security.yml +0 -0
@@ -0,0 +1,608 @@
1
+ # Godot Architecture Patterns
2
+
3
+ Proven architectural patterns for building maintainable Godot projects, especially when working with LLM coding assistants.
4
+
5
+ ## Core Principles
6
+
7
+ ### 1. Component-Based Design
8
+ Break functionality into small, reusable components attached as Node children.
9
+
10
+ **Benefits:**
11
+ - Each component is a focused, understandable file
12
+ - Easy to add/remove features
13
+ - Clear responsibilities
14
+ - LLM-friendly (small files, clear purpose)
15
+
16
+ ### 2. Signal-Driven Communication
17
+ Use signals for loose coupling between systems.
18
+
19
+ **Benefits:**
20
+ - Self-documenting (signals show available events)
21
+ - Easy to connect UI without modifying game logic
22
+ - No complex dependency injection needed
23
+ - Clear event flow
24
+
25
+ ### 3. Resource-Based Data
26
+ Separate logic (.gd) from data (.tres).
27
+
28
+ **Benefits:**
29
+ - Data files are simple and safe to edit
30
+ - Easy to create variants
31
+ - Designer-friendly
32
+ - LLM can edit data without touching logic
33
+
34
+ ---
35
+
36
+ ## Pattern 1: Component-Based Interaction System
37
+
38
+ **Use for:** Objects that can be interacted with in different ways.
39
+
40
+ ### Structure
41
+
42
+ ```
43
+ BaseInteractable.gd (parent script)
44
+ ├─ is_interactable: bool
45
+ ├─ interaction_nodes: Array[InteractionComponent]
46
+ └─ interact(player) -> void
47
+
48
+ InteractionComponent.gd (child node script)
49
+ ├─ interaction_text: String
50
+ ├─ is_enabled: bool
51
+ ├─ interact(player) -> bool
52
+ └─ signal: was_interacted_with
53
+ ```
54
+
55
+ ### Implementation
56
+
57
+ **BaseInteractable.gd:**
58
+ ```gdscript
59
+ extends Node3D
60
+ class_name BaseInteractable
61
+
62
+ @export var is_interactable: bool = true
63
+ var interaction_nodes: Array[InteractionComponent] = []
64
+
65
+ func _ready():
66
+ # Gather all interaction components
67
+ for child in get_children():
68
+ if child is InteractionComponent:
69
+ interaction_nodes.append(child)
70
+
71
+ func interact(player) -> void:
72
+ if not is_interactable:
73
+ return
74
+
75
+ for interaction in interaction_nodes:
76
+ if interaction.is_enabled:
77
+ interaction.interact(player)
78
+ break # Only one interaction per press
79
+ ```
80
+
81
+ **InteractionComponent.gd:**
82
+ ```gdscript
83
+ extends Node
84
+ class_name InteractionComponent
85
+
86
+ signal was_interacted_with(player)
87
+
88
+ @export var interaction_text: String = "Interact"
89
+ @export var is_enabled: bool = true
90
+
91
+ func interact(player) -> bool:
92
+ if not is_enabled:
93
+ return false
94
+
95
+ _perform_interaction(player)
96
+ was_interacted_with.emit(player)
97
+ return true
98
+
99
+ func _perform_interaction(player) -> void:
100
+ # Override in subclasses
101
+ pass
102
+ ```
103
+
104
+ **Example Subclass - PickupInteraction.gd:**
105
+ ```gdscript
106
+ extends InteractionComponent
107
+ class_name PickupInteraction
108
+
109
+ @export var item_resource: ItemResource
110
+
111
+ func _perform_interaction(player) -> void:
112
+ if not item_resource:
113
+ push_error("No item resource assigned")
114
+ return
115
+
116
+ player.inventory.add_item(item_resource)
117
+ get_parent().queue_free() # Remove the pickup
118
+ ```
119
+
120
+ ### Scene Setup (.tscn)
121
+
122
+ ```
123
+ [ext_resource type="Script" path="res://src/base_interactable.gd" id="1"]
124
+ [ext_resource type="Script" path="res://src/pickup_interaction.gd" id="2"]
125
+ [ext_resource type="Resource" path="res://resources/items/key.tres" id="3"]
126
+
127
+ [node name="KeyPickup" type="StaticBody3D"]
128
+ script = ExtResource("1")
129
+
130
+ [node name="PickupInteraction" type="Node" parent="."]
131
+ script = ExtResource("2")
132
+ interaction_text = "Pick up Key"
133
+ item_resource = ExtResource("3")
134
+
135
+ [node name="MeshInstance3D" type="MeshInstance3D" parent="."]
136
+ # ... mesh configuration
137
+ ```
138
+
139
+ ### Usage Benefits
140
+ - Single object can have multiple interaction types
141
+ - Easy to add new interaction types (just create new subclass)
142
+ - Interactions can be enabled/disabled dynamically
143
+ - Clear separation of concerns
144
+
145
+ ---
146
+
147
+ ## Pattern 2: Attribute System
148
+
149
+ **Use for:** Health, mana, stamina, or any numeric attribute with min/max values.
150
+
151
+ ### Structure
152
+
153
+ ```
154
+ Attribute.gd (base class)
155
+ ├─ attribute_name: String
156
+ ├─ value_current: float (with setter)
157
+ ├─ value_max: float
158
+ ├─ value_start: float
159
+ ├─ signal: attribute_changed(name, current, max, increased)
160
+ └─ signal: attribute_reached_zero(name)
161
+
162
+ HealthAttribute.gd (specialized)
163
+ ├─ extends Attribute
164
+ ├─ signal: damage_taken(amount)
165
+ └─ signal: death()
166
+ ```
167
+
168
+ ### Implementation
169
+
170
+ **Attribute.gd:**
171
+ ```gdscript
172
+ extends Node
173
+ class_name Attribute
174
+
175
+ signal attribute_changed(attribute_name: String, value_current: float, value_max: float, value_increased: bool)
176
+ signal attribute_reached_zero(attribute_name: String)
177
+
178
+ @export var attribute_name: String = "Attribute"
179
+ @export var value_max: float = 100.0
180
+ @export var value_start: float = 100.0
181
+
182
+ var value_current: float:
183
+ set(value):
184
+ var old_value = value_current
185
+ value_current = clamp(value, 0, value_max)
186
+ var increased = value_current > old_value
187
+
188
+ attribute_changed.emit(attribute_name, value_current, value_max, increased)
189
+
190
+ if value_current <= 0:
191
+ attribute_reached_zero.emit(attribute_name)
192
+
193
+ func _ready():
194
+ value_current = value_start
195
+
196
+ func add(amount: float) -> void:
197
+ value_current += amount
198
+
199
+ func subtract(amount: float) -> void:
200
+ value_current -= amount
201
+ ```
202
+
203
+ **HealthAttribute.gd:**
204
+ ```gdscript
205
+ extends Attribute
206
+ class_name HealthAttribute
207
+
208
+ signal damage_taken(amount: float)
209
+ signal death()
210
+
211
+ func _ready():
212
+ super._ready()
213
+ attribute_name = "Health"
214
+ attribute_reached_zero.connect(_on_death)
215
+
216
+ func take_damage(amount: float) -> void:
217
+ subtract(amount)
218
+ damage_taken.emit(amount)
219
+
220
+ func heal(amount: float) -> void:
221
+ add(amount)
222
+
223
+ func _on_death() -> void:
224
+ death.emit()
225
+ ```
226
+
227
+ ### Parent Integration
228
+
229
+ **BaseEnemy.gd:**
230
+ ```gdscript
231
+ extends CharacterBody3D
232
+ class_name BaseEnemy
233
+
234
+ var attributes: Dictionary = {}
235
+
236
+ func _ready():
237
+ # Gather all attributes
238
+ for child in get_children():
239
+ if child is Attribute:
240
+ attributes[child.attribute_name] = child
241
+ child.attribute_changed.connect(_on_attribute_changed)
242
+
243
+ # Connect to health-specific signals
244
+ if attributes.has("Health"):
245
+ attributes["Health"].death.connect(_on_death)
246
+
247
+ func _on_attribute_changed(attr_name: String, current: float, max_val: float, increased: bool):
248
+ # Update UI or trigger effects
249
+ pass
250
+
251
+ func _on_death():
252
+ # Drop loot, play animation, etc.
253
+ queue_free()
254
+ ```
255
+
256
+ ### Scene Setup (.tscn)
257
+
258
+ ```
259
+ [ext_resource type="Script" path="res://src/base_enemy.gd" id="1"]
260
+ [ext_resource type="Script" path="res://src/health_attribute.gd" id="2"]
261
+
262
+ [node name="Enemy" type="CharacterBody3D"]
263
+ script = ExtResource("1")
264
+
265
+ [node name="HealthAttribute" type="Node" parent="."]
266
+ script = ExtResource("2")
267
+ value_max = 50.0
268
+ value_start = 50.0
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Pattern 3: Resource-Based Effect System
274
+
275
+ **Use for:** Spells, abilities, items, or any combinable effects.
276
+
277
+ ### Structure
278
+
279
+ ```
280
+ SpellEffect.gd (individual effect)
281
+ ├─ effect_type: enum
282
+ ├─ magnitude_min/max: float
283
+ ├─ duration: float
284
+ └─ apply_effect(target, caster)
285
+
286
+ SpellResource.gd (combines effects)
287
+ ├─ effects: Array[SpellEffect]
288
+ ├─ mana_cost: float
289
+ ├─ projectile_speed: float
290
+ └─ spell_color: Color
291
+ ```
292
+
293
+ ### Implementation
294
+
295
+ **SpellEffect.gd:**
296
+ ```gdscript
297
+ extends Resource
298
+ class_name SpellEffect
299
+
300
+ enum EffectType {
301
+ DAMAGE,
302
+ HEAL,
303
+ RESTORE_MANA,
304
+ DAMAGE_OVER_TIME,
305
+ HEAL_OVER_TIME,
306
+ SLOW,
307
+ SPEED_BOOST,
308
+ STUN,
309
+ # ... more types
310
+ }
311
+
312
+ @export var effect_type: EffectType = EffectType.DAMAGE
313
+ @export var magnitude_min: float = 10.0
314
+ @export var magnitude_max: float = 10.0
315
+ @export var duration: float = 0.0
316
+ @export var tick_rate: float = 1.0 # For over-time effects
317
+
318
+ func apply_effect(target: Node, caster: Node) -> void:
319
+ var magnitude = randf_range(magnitude_min, magnitude_max)
320
+
321
+ match effect_type:
322
+ EffectType.DAMAGE:
323
+ _apply_damage(target, magnitude)
324
+ EffectType.HEAL:
325
+ _apply_heal(target, magnitude)
326
+ EffectType.SLOW:
327
+ _apply_slow(target, magnitude, duration)
328
+ # ... handle other types
329
+
330
+ func _apply_damage(target: Node, amount: float) -> void:
331
+ if target.has_method("take_damage"):
332
+ target.take_damage(amount)
333
+
334
+ func _apply_heal(target: Node, amount: float) -> void:
335
+ if target.has_node("HealthAttribute"):
336
+ target.get_node("HealthAttribute").heal(amount)
337
+
338
+ func _apply_slow(target: Node, percent: float, dur: float) -> void:
339
+ # Apply slow effect logic
340
+ pass
341
+ ```
342
+
343
+ **SpellResource.gd:**
344
+ ```gdscript
345
+ extends Resource
346
+ class_name SpellResource
347
+
348
+ @export var spell_id: String = ""
349
+ @export var spell_name: String = "Spell"
350
+ @export var mana_cost: float = 10.0
351
+ @export var effects: Array[SpellEffect] = []
352
+ @export var projectile_speed: float = 20.0
353
+ @export var spell_color: Color = Color.WHITE
354
+
355
+ func cast(caster: Node, target_position: Vector3) -> void:
356
+ # Spawn projectile or apply effects immediately
357
+ pass
358
+
359
+ func apply_effects(target: Node, caster: Node) -> void:
360
+ for effect in effects:
361
+ effect.apply_effect(target, caster)
362
+ ```
363
+
364
+ ### Data File (.tres)
365
+
366
+ ```tres
367
+ [gd_resource type="Resource" script_class="SpellResource" load_steps=4 format=3]
368
+
369
+ [ext_resource type="Script" path="res://src/spells/spell_resource.gd" id="1"]
370
+ [ext_resource type="Script" path="res://src/spells/spell_effect.gd" id="2"]
371
+
372
+ [sub_resource type="Resource" id="Effect_damage"]
373
+ script = ExtResource("2")
374
+ effect_type = 0
375
+ magnitude_min = 15.0
376
+ magnitude_max = 25.0
377
+
378
+ [sub_resource type="Resource" id="Effect_slow"]
379
+ script = ExtResource("2")
380
+ effect_type = 12
381
+ magnitude_min = 50.0
382
+ magnitude_max = 50.0
383
+ duration = 3.0
384
+
385
+ [resource]
386
+ script = ExtResource("1")
387
+ spell_name = "Ice Bolt"
388
+ spell_id = "ice_bolt"
389
+ mana_cost = 20.0
390
+ spell_color = Color(0.5, 0.7, 1, 1)
391
+ projectile_speed = 15.0
392
+ effects = Array[ExtResource("2")]([SubResource("Effect_damage"), SubResource("Effect_slow")])
393
+ ```
394
+
395
+ ### Benefits
396
+ - Create new spells with just data (no code changes)
397
+ - Combinable effects create emergent gameplay
398
+ - Easy for LLM to generate new spell variants
399
+ - Designer-friendly (edit in Inspector)
400
+
401
+ ---
402
+
403
+ ## Pattern 4: Inventory System
404
+
405
+ **Use for:** Player/enemy inventories, containers, shops.
406
+
407
+ ### Structure
408
+
409
+ ```
410
+ ItemResource.gd (data)
411
+ ├─ item_id: String
412
+ ├─ item_name: String
413
+ ├─ description: String
414
+ ├─ icon: Texture2D
415
+ └─ stackable: bool
416
+
417
+ Inventory.gd (logic)
418
+ ├─ items: Array[ItemResource]
419
+ ├─ add_item(item)
420
+ ├─ remove_item(item_id)
421
+ ├─ has_item(item_id) -> bool
422
+ └─ signal: item_added/removed
423
+ ```
424
+
425
+ ### Implementation
426
+
427
+ **ItemResource.gd:**
428
+ ```gdscript
429
+ extends Resource
430
+ class_name ItemResource
431
+
432
+ @export var item_id: String = ""
433
+ @export var item_name: String = "Item"
434
+ @export var description: String = ""
435
+ @export var icon: Texture2D
436
+ @export var stackable: bool = false
437
+ @export var max_stack: int = 99
438
+ ```
439
+
440
+ **Inventory.gd:**
441
+ ```gdscript
442
+ extends Node
443
+ class_name Inventory
444
+
445
+ signal item_added(item: ItemResource)
446
+ signal item_removed(item_id: String)
447
+
448
+ var items: Array[ItemResource] = []
449
+
450
+ func add_item(item: ItemResource) -> bool:
451
+ if not item:
452
+ return false
453
+
454
+ items.append(item)
455
+ item_added.emit(item)
456
+ return true
457
+
458
+ func remove_item(item_id: String) -> bool:
459
+ for i in range(items.size()):
460
+ if items[i].item_id == item_id:
461
+ var removed = items[i]
462
+ items.remove_at(i)
463
+ item_removed.emit(item_id)
464
+ return true
465
+ return false
466
+
467
+ func has_item(item_id: String) -> bool:
468
+ for item in items:
469
+ if item.item_id == item_id:
470
+ return true
471
+ return false
472
+
473
+ func get_item(item_id: String) -> ItemResource:
474
+ for item in items:
475
+ if item.item_id == item_id:
476
+ return item
477
+ return null
478
+ ```
479
+
480
+ ---
481
+
482
+ ## Pattern 5: State Machine
483
+
484
+ **Use for:** AI behavior, player states, animation control.
485
+
486
+ ### Structure
487
+
488
+ ```
489
+ StateMachine.gd
490
+ ├─ current_state: State
491
+ ├─ states: Dictionary
492
+ ├─ change_state(state_name)
493
+ └─ _process/_physics_process
494
+
495
+ State.gd (base)
496
+ ├─ enter()
497
+ ├─ exit()
498
+ ├─ process(delta)
499
+ └─ physics_process(delta)
500
+ ```
501
+
502
+ ### Implementation
503
+
504
+ **State.gd:**
505
+ ```gdscript
506
+ extends Node
507
+ class_name State
508
+
509
+ signal state_finished(next_state: String)
510
+
511
+ func enter() -> void:
512
+ pass
513
+
514
+ func exit() -> void:
515
+ pass
516
+
517
+ func process(delta: float) -> void:
518
+ pass
519
+
520
+ func physics_process(delta: float) -> void:
521
+ pass
522
+ ```
523
+
524
+ **StateMachine.gd:**
525
+ ```gdscript
526
+ extends Node
527
+ class_name StateMachine
528
+
529
+ @export var initial_state: String = ""
530
+
531
+ var states: Dictionary = {}
532
+ var current_state: State = null
533
+
534
+ func _ready():
535
+ # Gather all state children
536
+ for child in get_children():
537
+ if child is State:
538
+ states[child.name] = child
539
+ child.state_finished.connect(_on_state_finished)
540
+
541
+ if initial_state and states.has(initial_state):
542
+ change_state(initial_state)
543
+
544
+ func _process(delta: float):
545
+ if current_state:
546
+ current_state.process(delta)
547
+
548
+ func _physics_process(delta: float):
549
+ if current_state:
550
+ current_state.physics_process(delta)
551
+
552
+ func change_state(new_state_name: String) -> void:
553
+ if current_state:
554
+ current_state.exit()
555
+
556
+ current_state = states.get(new_state_name)
557
+
558
+ if current_state:
559
+ current_state.enter()
560
+
561
+ func _on_state_finished(next_state: String) -> void:
562
+ change_state(next_state)
563
+ ```
564
+
565
+ **Example State - IdleState.gd:**
566
+ ```gdscript
567
+ extends State
568
+ class_name IdleState
569
+
570
+ @export var idle_time: float = 2.0
571
+
572
+ var timer: float = 0.0
573
+
574
+ func enter() -> void:
575
+ timer = 0.0
576
+ print("Entering idle state")
577
+
578
+ func process(delta: float) -> void:
579
+ timer += delta
580
+ if timer >= idle_time:
581
+ state_finished.emit("Patrol")
582
+ ```
583
+
584
+ ---
585
+
586
+ ## Combining Patterns
587
+
588
+ These patterns work together naturally:
589
+
590
+ ```gdscript
591
+ # Enemy with attributes, state machine, and loot
592
+ BaseEnemy (CharacterBody3D)
593
+ ├─ HealthAttribute (Attribute component)
594
+ ├─ ManaAttribute (Attribute component)
595
+ ├─ StateMachine
596
+ │ ├─ IdleState
597
+ │ ├─ PatrolState
598
+ │ ├─ ChaseState
599
+ │ └─ AttackState
600
+ └─ LootDropper (Component)
601
+ └─ loot_table: Array[LootEntry]
602
+ ```
603
+
604
+ Each component handles one responsibility, making the system:
605
+ - Easy to understand
606
+ - Simple to modify
607
+ - Clear to debug
608
+ - LLM-friendly to work with