# ๐ŸŽฏ CLAUDE.md - WhaleTown Project Instructions ## 1. Project Vision & Context - **Project**: "WhaleTown" - A 2D top-down pixel art RPG. - **Engine**: Godot 4.2+ (Strictly NO Godot 3.x syntax). - **Architecture**: Strictly layered: `_Core` (Framework), `Scenes` (Gameplay), `UI` (Interface). - **Core Principle**: "Signal Up, Call Down". High decoupling via `EventSystem`. ## 2. ๐Ÿ›  Command Reference & Setup - **Input Map (Required Configuration)**: - `move_left`, `move_right`, `move_up`, `move_down` (WASD / Arrows) - `interact` (E Key / Space) - `pause` (ESC) - **Run Game**: `godot --path .` - **Run Tests (GUT)**: `godot --headless -s addons/gut/gut_cmdline.gd -gdir=res://tests/ -ginclude_subdirs` - **Init Structure**: `mkdir -p _Core/managers _Core/systems Scenes/Maps Scenes/Entities Scenes/Components UI/Windows UI/HUD Assets/Sprites tests/unit tests/integration` ## 3. ๐Ÿ“‚ File Path Rules (STRICT LOWERCASE) *Claude: Root folders MUST be lowercase. Scripts and Scenes MUST stay together.* - **Core Managers**: `_Core/managers/[Name].gd` - **Core Systems**: `_Core/systems/[Name].gd` - **Entities**: `Scenes/Entities/[EntityName]/[EntityName].tscn` (Script `.gd` in same folder). - **Maps**: `Scenes/Maps/[map_name].tscn` - **Components**: `Scenes/Components/[ComponentName].gd` (Reusable logic nodes). - **UI Windows**: `UI/Windows/[WindowName].tscn` - **Tests**: `tests/[unit|integration]/test_[name].gd` (Folder is lowercase `tests`). ## 4. ๐Ÿ“‹ Coding Standards (The Law) - **Type Safety**: ALWAYS use strict static typing: `var speed: float = 100.0`, `func _ready() -> void`. - **Naming Conventions**: - `class_name PascalCase` at the top of every script. - Variables/Functions: `snake_case`. Constants: `SCREAMING_SNAKE_CASE`. - Private members: Prefix with underscore `_` (e.g., `var _health: int`). - **Node Access**: Use `%UniqueName` for UI and internal scene components. - **Signals**: Use "Signal Up, Call Down". Parent calls child methods; Child emits signals. - **Forbidden Patterns**: - โŒ NO `yield()` -> Use `await`. - โŒ NO `get_node()` in `_process` -> Cache with `@onready`. - โŒ NO Linear Filter -> All Sprite2D/TileMap resources MUST use **Nearest** filter. ## 5. ๐Ÿ› Architecture & Communication - **EventSystem**: Use `_Core/systems/EventSystem.gd` for cross-module messaging. - **Event Registry**: Use `class_name EventNames` in `_Core/EventNames.gd`. ```gdscript class_name EventNames const PLAYER_MOVED = "player_moved" const INTERACT_PRESSED = "interact_pressed" const NPC_TALKED = "npc_talked" Singletons: Only GameManager, SceneManager, EventSystem allowed as Autoloads. Decoupling: Low-level entities MUST NOT reference GameManager. Use events. 6. ๐Ÿ— Implementation Details Player: CharacterBody2D. Must include Camera2D with position_smoothing_enabled = true. NPC/Interactables: Use Area2D named InteractionArea. Trigger via EventSystem. TileMap Layers: Layer 0: Ground (No collision). Layer 1: Obstacles (Physics Layer enabled). Layer 2: Decoration (Y-Sort enabled). Camera: Must auto-calculate limits via TileMap.get_used_rect(). 7. ๐Ÿงช Testing Requirements (MANDATORY) Coverage: Every Manager/System in _Core/ MUST have a GUT test. Naming: Test files must start with test_ and extend GutTest. Example: code Gdscript extends GutTest func test_event_emission(): var sender = Node.new() watch_signals(EventSystem) EventSystem.emit_event(EventNames.PLAYER_MOVED, {}) assert_signal_emitted(EventSystem, "event_raised") 8. ๐Ÿง˜ The Zen of Development Juice or Death: Every interaction (UI popup, NPC talk) MUST have a Tween placeholder. Zero Magic Numbers: All speeds/timers MUST be @export or defined in Config/. Simplicity: If a function does two things, split it. Back of the Fence: Hidden logic (like ResponseHandler.gd) must be as clean as the HUD. 9. ๐Ÿ“ Code Template (Entity Pattern) code Gdscript extends CharacterBody2D class_name Player # 1. Exports & Constants @export var move_speed: float = 200.0 # 2. Node References @onready var sprite: Sprite2D = %Sprite2D # 3. Lifecycle func _physics_process(delta: float) -> void: _move(delta) # 4. Private Methods func _move(_delta: float) -> void: var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down") velocity = dir * move_speed move_and_slide()