summer-engine 0.0.1 → 1.0.0
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.
- package/README.md +72 -8
- package/dist/bin/postinstall.d.ts +2 -0
- package/dist/bin/postinstall.js +3 -0
- package/dist/bin/summer.d.ts +2 -0
- package/dist/bin/summer.js +34 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +99 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +135 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +48 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +75 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +26 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +7 -0
- package/dist/commands/open.d.ts +2 -0
- package/dist/commands/open.js +32 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +69 -0
- package/dist/commands/skills.d.ts +2 -0
- package/dist/commands/skills.js +187 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +43 -0
- package/dist/lib/api-client.d.ts +17 -0
- package/dist/lib/api-client.js +69 -0
- package/dist/lib/auth.d.ts +13 -0
- package/dist/lib/auth.js +39 -0
- package/dist/lib/banner.d.ts +4 -0
- package/dist/lib/banner.js +122 -0
- package/dist/lib/engine.d.ts +12 -0
- package/dist/lib/engine.js +36 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.js +40 -0
- package/dist/mcp/tools/asset-tools.d.ts +2 -0
- package/dist/mcp/tools/asset-tools.js +247 -0
- package/dist/mcp/tools/debug-tools.d.ts +2 -0
- package/dist/mcp/tools/debug-tools.js +49 -0
- package/dist/mcp/tools/project-tools.d.ts +2 -0
- package/dist/mcp/tools/project-tools.js +55 -0
- package/dist/mcp/tools/scene-tools.d.ts +2 -0
- package/dist/mcp/tools/scene-tools.js +139 -0
- package/dist/mcp/tools/with-engine.d.ts +10 -0
- package/dist/mcp/tools/with-engine.js +65 -0
- package/package.json +22 -5
- package/skills/3d-lighting/SKILL.md +103 -0
- package/skills/fps-controller/SKILL.md +131 -0
- package/skills/gdscript-patterns/SKILL.md +96 -0
- package/skills/gdscript-patterns/reference.md +55 -0
- package/skills/scene-composition/SKILL.md +108 -0
- package/skills/ui-basics/SKILL.md +121 -0
- package/bin/summer.js +0 -3
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 3d-lighting
|
|
3
|
+
description: Lighting setup, environment, sky, and shadows for 3D scenes. Use when setting up a 3D scene, adding lights, configuring WorldEnvironment, or adjusting shadows.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility:
|
|
6
|
+
- Cursor
|
|
7
|
+
- Claude Code
|
|
8
|
+
- Windsurf
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# 3D Lighting for Summer Engine
|
|
12
|
+
|
|
13
|
+
Set up lighting and environment for 3D scenes. Follow these patterns for outdoor and indoor setups.
|
|
14
|
+
|
|
15
|
+
## Light Types
|
|
16
|
+
|
|
17
|
+
| Type | Use case |
|
|
18
|
+
|------|----------|
|
|
19
|
+
| DirectionalLight3D | Sun, moon, outdoor primary light |
|
|
20
|
+
| OmniLight3D | Point lights (lamps, torches) |
|
|
21
|
+
| SpotLight3D | Flashlights, stage lights |
|
|
22
|
+
|
|
23
|
+
## Basic Outdoor Setup
|
|
24
|
+
|
|
25
|
+
### 1. Directional Light (Sun)
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
summer_add_node(parent="./World", type="DirectionalLight3D", name="Sun")
|
|
29
|
+
summer_set_prop(path="./World/Sun", key="rotation_degrees", value="Vector3(-45, 30, 0)")
|
|
30
|
+
summer_set_prop(path="./World/Sun", key="light_energy", value="1.0")
|
|
31
|
+
summer_set_prop(path="./World/Sun", key="shadow_enabled", value="true")
|
|
32
|
+
summer_set_prop(path="./World/Sun", key="light_color", value="Color(1, 0.95, 0.9, 1)")
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Warm sunlight: `Color(1, 0.95, 0.9, 1)`. Cool moonlight: `Color(0.8, 0.85, 1, 1)`.
|
|
36
|
+
|
|
37
|
+
### 2. WorldEnvironment (Sky + Ambient)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
summer_add_node(parent="./World", type="WorldEnvironment", name="WorldEnvironment")
|
|
41
|
+
summer_set_prop(path="./World/WorldEnvironment", key="environment", value="Environment")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then configure the Environment's sub-properties. The Environment resource has:
|
|
45
|
+
- `background_mode` — 2 for sky, 1 for color, 3 for canvas
|
|
46
|
+
- `sky` — Sky resource (ProceduralSkyMaterial or PhysicalSkyMaterial)
|
|
47
|
+
- `ambient_light_source` — AMBIENT_SOURCE_SKY or AMBIENT_SOURCE_COLOR
|
|
48
|
+
- `ambient_light_color`
|
|
49
|
+
- `tonemap_mode`
|
|
50
|
+
|
|
51
|
+
For a simple procedural sky:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
summer_set_resource_property(nodePath="./World/WorldEnvironment", resourceProperty="environment", subProperty="background_mode", value="2")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
You may need to create a Sky resource and assign it. In the editor this is done via the inspector; via MCP, SetResourceProperty on nested resources may require the resource to exist first. If `environment` is "Environment", the engine creates a default. For `sky`, you might set `sky` to "ProceduralSkyMaterial" or similar—check Godot docs for the exact property chain.
|
|
58
|
+
|
|
59
|
+
**Simpler path:** Use the 3d-basic template which already has a sky. Copy that structure.
|
|
60
|
+
|
|
61
|
+
### 3. Fill Light (Optional)
|
|
62
|
+
|
|
63
|
+
A second, weaker directional or omni for shadow fill:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
summer_add_node(parent="./World", type="DirectionalLight3D", name="FillLight")
|
|
67
|
+
summer_set_prop(path="./World/FillLight", key="rotation_degrees", value="Vector3(-30, -120, 0)")
|
|
68
|
+
summer_set_prop(path="./World/FillLight", key="light_energy", value="0.3")
|
|
69
|
+
summer_set_prop(path="./World/FillLight", key="shadow_enabled", value="false")
|
|
70
|
+
summer_set_prop(path="./World/FillLight", key="light_color", value="Color(0.7, 0.8, 1, 1)")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Indoor / Point Lights
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
summer_add_node(parent="./World", type="OmniLight3D", name="Lamp")
|
|
77
|
+
summer_set_prop(path="./World/Lamp", key="position", value="Vector3(2, 3, 2)")
|
|
78
|
+
summer_set_prop(path="./World/Lamp", key="light_energy", value="0.8")
|
|
79
|
+
summer_set_prop(path="./World/Lamp", key="light_color", value="Color(1, 0.9, 0.7, 1)")
|
|
80
|
+
summer_set_prop(path="./World/Lamp", key="omni_range", value="8")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Property Reference
|
|
84
|
+
|
|
85
|
+
| Property | Type | Example |
|
|
86
|
+
|----------|------|---------|
|
|
87
|
+
| light_energy | float | `1.0`, `1.5` |
|
|
88
|
+
| light_color | Color | `"Color(1, 0.95, 0.9, 1)"` |
|
|
89
|
+
| shadow_enabled | bool | `true` |
|
|
90
|
+
| rotation_degrees | Vector3 | `"Vector3(-45, 30, 0)"` |
|
|
91
|
+
| position | Vector3 | `"Vector3(0, 10, 0)"` |
|
|
92
|
+
| omni_range | float | `10` (OmniLight3D) |
|
|
93
|
+
| spot_range | float | `10` (SpotLight3D) |
|
|
94
|
+
| spot_angle | float | `45` (degrees, SpotLight3D) |
|
|
95
|
+
|
|
96
|
+
## Color Format
|
|
97
|
+
|
|
98
|
+
Always use `Color(r, g, b, a)` with values 0.0–1.0:
|
|
99
|
+
|
|
100
|
+
- Warm white: `Color(1, 0.95, 0.9, 1)`
|
|
101
|
+
- Cool white: `Color(0.9, 0.95, 1, 1)`
|
|
102
|
+
- Orange (torch): `Color(1, 0.6, 0.2, 1)`
|
|
103
|
+
- Green (alien): `Color(0.5, 1, 0.5, 1)`
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fps-controller
|
|
3
|
+
description: First-person character controller with movement, camera, and physics. Use when building an FPS game, first-person movement, or a 3D character that moves with WASD and looks with mouse.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility:
|
|
6
|
+
- Cursor
|
|
7
|
+
- Claude Code
|
|
8
|
+
- Windsurf
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# FPS Controller for Summer Engine
|
|
12
|
+
|
|
13
|
+
Build a first-person character controller using CharacterBody3D, Camera3D, and proper collision. Follow this structure for reliable movement and camera behavior.
|
|
14
|
+
|
|
15
|
+
## Scene Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Player (CharacterBody3D)
|
|
19
|
+
├── CollisionShape3D # Capsule for body
|
|
20
|
+
├── Camera3D # At head height
|
|
21
|
+
└── RayCast3D # Optional: ground detection
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Step-by-Step Setup via MCP
|
|
25
|
+
|
|
26
|
+
### 1. Add the Player Root
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
summer_add_node(parent="./World", type="CharacterBody3D", name="Player")
|
|
30
|
+
summer_set_prop(path="./World/Player", key="position", value="Vector3(0, 1, 0)")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Add Collision Shape
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
summer_add_node(parent="./World/Player", type="CollisionShape3D", name="CollisionShape3D")
|
|
37
|
+
summer_set_prop(path="./World/Player/CollisionShape3D", key="shape", value="CapsuleShape3D")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Configure capsule size (radius ~0.4, height ~1.6 for typical human):
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
summer_set_resource_property(nodePath="./World/Player/CollisionShape3D", resourceProperty="shape", subProperty="radius", value="0.4")
|
|
44
|
+
summer_set_resource_property(nodePath="./World/Player/CollisionShape3D", resourceProperty="shape", subProperty="height", value="1.6")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Add Camera
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
summer_add_node(parent="./World/Player", type="Camera3D", name="Camera3D")
|
|
51
|
+
summer_set_prop(path="./World/Player/Camera3D", key="position", value="Vector3(0, 1.6, 0)")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Camera at y=1.6 puts the view at roughly eye level (capsule center is at 0.8, so 0.8 + 0.8 = 1.6 for eyes).
|
|
55
|
+
|
|
56
|
+
### 4. InputMap Actions
|
|
57
|
+
|
|
58
|
+
Create movement and look actions:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
summer_input_map_bind(name="move_forward", events=[{type:"key", key:"W"}])
|
|
62
|
+
summer_input_map_bind(name="move_back", events=[{type:"key", key:"S"}])
|
|
63
|
+
summer_input_map_bind(name="move_left", events=[{type:"key", key:"A"}])
|
|
64
|
+
summer_input_map_bind(name="move_right", events=[{type:"key", key:"D"}])
|
|
65
|
+
summer_input_map_bind(name="jump", events=[{type:"key", key:"Space"}])
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
For mouse look, you need a script. The script will use `Input.get_vector` for movement and `InputEventMouseMotion` for look. Attach a script and implement:
|
|
69
|
+
|
|
70
|
+
### 5. GDScript Pattern
|
|
71
|
+
|
|
72
|
+
```gdscript
|
|
73
|
+
extends CharacterBody3D
|
|
74
|
+
|
|
75
|
+
@export var move_speed: float = 5.0
|
|
76
|
+
@export var jump_velocity: float = 4.5
|
|
77
|
+
@export var mouse_sensitivity: float = 0.002
|
|
78
|
+
|
|
79
|
+
func _physics_process(_delta: float) -> void:
|
|
80
|
+
# Movement
|
|
81
|
+
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
|
82
|
+
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
|
83
|
+
if direction:
|
|
84
|
+
velocity.x = direction.x * move_speed
|
|
85
|
+
velocity.z = direction.z * move_speed
|
|
86
|
+
else:
|
|
87
|
+
velocity.x = move_toward(velocity.x, 0, move_speed)
|
|
88
|
+
velocity.z = move_toward(velocity.z, 0, move_speed)
|
|
89
|
+
|
|
90
|
+
# Jump
|
|
91
|
+
if is_on_floor() and Input.is_action_just_pressed("jump"):
|
|
92
|
+
velocity.y = jump_velocity
|
|
93
|
+
|
|
94
|
+
# Gravity
|
|
95
|
+
if not is_on_floor():
|
|
96
|
+
velocity.y -= 9.8 * _delta
|
|
97
|
+
|
|
98
|
+
move_and_slide()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For mouse look, add to a script attached to the Player or Camera:
|
|
102
|
+
|
|
103
|
+
```gdscript
|
|
104
|
+
func _input(event: InputEvent) -> void:
|
|
105
|
+
if event is InputEventMouseMotion:
|
|
106
|
+
rotate_y(-event.relative.x * mouse_sensitivity)
|
|
107
|
+
$Camera3D.rotate_x(-event.relative.y * mouse_sensitivity)
|
|
108
|
+
$Camera3D.rotation.x = clamp($Camera3D.rotation.x, -1.2, 1.2)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Property Values (Godot Format)
|
|
112
|
+
|
|
113
|
+
When using `summer_set_prop`, use these string formats:
|
|
114
|
+
|
|
115
|
+
| Property | Value |
|
|
116
|
+
|----------|-------|
|
|
117
|
+
| position | `"Vector3(0, 1, 0)"` |
|
|
118
|
+
| rotation_degrees | `"Vector3(0, 0, 0)"` |
|
|
119
|
+
| shape | `"CapsuleShape3D"` |
|
|
120
|
+
|
|
121
|
+
For `summer_set_resource_property` on CapsuleShape3D:
|
|
122
|
+
| subProperty | value |
|
|
123
|
+
|-------------|-------|
|
|
124
|
+
| radius | `"0.4"` |
|
|
125
|
+
| height | `"1.6"` |
|
|
126
|
+
|
|
127
|
+
## Common Issues
|
|
128
|
+
|
|
129
|
+
- **Falling through floor:** Ensure the floor has a StaticBody3D or similar with a CollisionShape3D
|
|
130
|
+
- **Camera clipping:** If the camera goes inside geometry, enable `near` on the Camera3D or add collision exception
|
|
131
|
+
- **Mouse capture:** For FPS, you typically need `Input.mouse_mode = Input.MOUSE_MODE_CAPTURED` in `_ready()` and a way to release (e.g., Escape)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gdscript-patterns
|
|
3
|
+
description: Common GDScript idioms, signals, exports, and type hints. Use when writing GDScript, attaching scripts to nodes, connecting signals, or defining exported variables.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility:
|
|
6
|
+
- Cursor
|
|
7
|
+
- Claude Code
|
|
8
|
+
- Windsurf
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# GDScript Patterns for Summer Engine
|
|
12
|
+
|
|
13
|
+
When writing GDScript for Summer Engine projects, follow these patterns. They align with Godot 4.x conventions and work well with MCP scene operations.
|
|
14
|
+
|
|
15
|
+
## Type Hints
|
|
16
|
+
|
|
17
|
+
Always use type hints for clarity and editor support:
|
|
18
|
+
|
|
19
|
+
```gdscript
|
|
20
|
+
var health: int = 100
|
|
21
|
+
var speed: float = 5.0
|
|
22
|
+
var player_name: String = ""
|
|
23
|
+
var velocity: Vector3 = Vector3.ZERO
|
|
24
|
+
var is_alive: bool = true
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For nodes, use typed references:
|
|
28
|
+
|
|
29
|
+
```gdscript
|
|
30
|
+
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
|
|
31
|
+
@onready var camera: Camera3D = $Camera3D
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Signals
|
|
35
|
+
|
|
36
|
+
Define signals at the top of the script, then emit them:
|
|
37
|
+
|
|
38
|
+
```gdscript
|
|
39
|
+
signal died
|
|
40
|
+
signal health_changed(new_health: int)
|
|
41
|
+
signal item_collected(item_name: String)
|
|
42
|
+
|
|
43
|
+
func take_damage(amount: int) -> void:
|
|
44
|
+
health -= amount
|
|
45
|
+
health_changed.emit(health)
|
|
46
|
+
if health <= 0:
|
|
47
|
+
died.emit()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
When connecting via MCP, use `summer_connect_signal` with the emitter path, signal name, receiver path, and method name. The receiver script must have the method defined.
|
|
51
|
+
|
|
52
|
+
## Exports
|
|
53
|
+
|
|
54
|
+
Use `@export` for inspector-editable properties:
|
|
55
|
+
|
|
56
|
+
```gdscript
|
|
57
|
+
@export var move_speed: float = 5.0
|
|
58
|
+
@export var jump_force: float = 10.0
|
|
59
|
+
@export var max_health: int = 100
|
|
60
|
+
@export var can_double_jump: bool = false
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Exports appear in the inspector. MCP can set initial values via `summer_set_prop` after the node exists, but exports are best for values the designer tweaks.
|
|
64
|
+
|
|
65
|
+
## Lifecycle Methods
|
|
66
|
+
|
|
67
|
+
| Method | When it runs | Use for |
|
|
68
|
+
|--------|--------------|---------|
|
|
69
|
+
| `_ready()` | Once when node enters tree | Initialization, getting node references |
|
|
70
|
+
| `_process(delta: float)` | Every frame | UI, non-physics logic |
|
|
71
|
+
| `_physics_process(delta: float)` | Every physics frame (fixed) | Movement, physics, collision |
|
|
72
|
+
|
|
73
|
+
For character movement, use `_physics_process` and `move_and_slide()`.
|
|
74
|
+
|
|
75
|
+
## Node Access
|
|
76
|
+
|
|
77
|
+
```gdscript
|
|
78
|
+
# Prefer $ for direct children
|
|
79
|
+
var camera = $Camera3D
|
|
80
|
+
|
|
81
|
+
# get_node() for dynamic paths
|
|
82
|
+
var target = get_node("../Enemy/HealthBar")
|
|
83
|
+
|
|
84
|
+
# get_parent() / get_children() when needed
|
|
85
|
+
var siblings = get_parent().get_children()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Common Patterns
|
|
89
|
+
|
|
90
|
+
For health systems, input handling, and state machines, see [reference.md](reference.md).
|
|
91
|
+
|
|
92
|
+
## MCP Integration
|
|
93
|
+
|
|
94
|
+
When the AI adds a script via `summer_add_node` and attaches a script, the script path is set via `summer_set_prop(path, "script", "res://path/to/script.gd")`. The script file must exist—use `summer_write_file` to create it first.
|
|
95
|
+
|
|
96
|
+
For signal connections, the receiver must have the handler method. Create the script with the method stub before calling `summer_connect_signal`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# GDScript Patterns — Reference
|
|
2
|
+
|
|
3
|
+
Detailed patterns for common game systems. Load this when implementing health, input, or state logic.
|
|
4
|
+
|
|
5
|
+
## Health System
|
|
6
|
+
|
|
7
|
+
```gdscript
|
|
8
|
+
signal died
|
|
9
|
+
|
|
10
|
+
var health: int = 100
|
|
11
|
+
var max_health: int = 100
|
|
12
|
+
|
|
13
|
+
func take_damage(amount: int) -> void:
|
|
14
|
+
health = maxi(0, health - amount)
|
|
15
|
+
if health <= 0:
|
|
16
|
+
died.emit()
|
|
17
|
+
|
|
18
|
+
func heal(amount: int) -> void:
|
|
19
|
+
health = mini(max_health, health + amount)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Input Handling
|
|
23
|
+
|
|
24
|
+
Use `Input.get_axis()` for movement, `Input.is_action_just_pressed()` for discrete actions:
|
|
25
|
+
|
|
26
|
+
```gdscript
|
|
27
|
+
func _physics_process(_delta: float) -> void:
|
|
28
|
+
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
|
29
|
+
velocity.x = input_dir.x * move_speed
|
|
30
|
+
velocity.z = input_dir.y * move_speed
|
|
31
|
+
|
|
32
|
+
if Input.is_action_just_pressed("jump"):
|
|
33
|
+
velocity.y = jump_force
|
|
34
|
+
|
|
35
|
+
move_and_slide()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Ensure InputMap actions exist via `summer_input_map_bind` before the game runs.
|
|
39
|
+
|
|
40
|
+
## State Machine (Simple)
|
|
41
|
+
|
|
42
|
+
```gdscript
|
|
43
|
+
enum State { IDLE, WALKING, JUMPING, FALLING }
|
|
44
|
+
var current_state: State = State.IDLE
|
|
45
|
+
|
|
46
|
+
func _physics_process(delta: float) -> void:
|
|
47
|
+
match current_state:
|
|
48
|
+
State.IDLE:
|
|
49
|
+
if Input.is_action_just_pressed("jump"):
|
|
50
|
+
current_state = State.JUMPING
|
|
51
|
+
elif input_dir != Vector2.ZERO:
|
|
52
|
+
current_state = State.WALKING
|
|
53
|
+
State.WALKING:
|
|
54
|
+
# ...
|
|
55
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scene-composition
|
|
3
|
+
description: How to structure scenes, when to use sub-scenes, and node hierarchy conventions. Use when building scenes, organizing nodes, or creating reusable prefabs.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility:
|
|
6
|
+
- Cursor
|
|
7
|
+
- Claude Code
|
|
8
|
+
- Windsurf
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Scene Composition for Summer Engine
|
|
12
|
+
|
|
13
|
+
Organize scenes for clarity, reuse, and MCP compatibility. Follow these conventions when building levels, characters, and UI.
|
|
14
|
+
|
|
15
|
+
## Node Hierarchy Conventions
|
|
16
|
+
|
|
17
|
+
### 3D Scenes
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
World (Node3D) # Root or main container
|
|
21
|
+
├── Camera3D # Main camera
|
|
22
|
+
├── DirectionalLight3D # Sun / primary light
|
|
23
|
+
├── WorldEnvironment # Sky, ambient, fog
|
|
24
|
+
├── Level (Node3D) # Level geometry
|
|
25
|
+
│ ├── Ground
|
|
26
|
+
│ ├── Walls
|
|
27
|
+
│ └── Platforms
|
|
28
|
+
├── Props (Node3D) # Placed objects (trees, crates)
|
|
29
|
+
├── Enemies (Node3D) # Enemy instances
|
|
30
|
+
└── Player # Player instance (or instantiated)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2D Scenes
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Level (Node2D)
|
|
37
|
+
├── TileMapLayer # Or TileMap
|
|
38
|
+
├── Characters
|
|
39
|
+
├── Props
|
|
40
|
+
└── Effects
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### UI Scenes
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
CanvasLayer or Control
|
|
47
|
+
├── MarginContainer
|
|
48
|
+
│ ├── VBoxContainer
|
|
49
|
+
│ │ ├── Label
|
|
50
|
+
│ │ ├── Button
|
|
51
|
+
│ │ └── Button
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Parent Paths for MCP
|
|
55
|
+
|
|
56
|
+
Use `./` for paths relative to the scene root:
|
|
57
|
+
|
|
58
|
+
| Path | Meaning |
|
|
59
|
+
|------|---------|
|
|
60
|
+
| `./` | Scene root |
|
|
61
|
+
| `./World` | Child named "World" of root |
|
|
62
|
+
| `./World/Player` | Player under World |
|
|
63
|
+
| `./World/Props/Tree1` | Tree1 under Props under World |
|
|
64
|
+
|
|
65
|
+
**Never use** `/World` (absolute) or `World` (missing `./`). The engine expects `./` prefix.
|
|
66
|
+
|
|
67
|
+
## When to Use Sub-Scenes
|
|
68
|
+
|
|
69
|
+
**Use sub-scenes (separate .tscn files) when:**
|
|
70
|
+
- The same setup appears in multiple places (player, enemy, pickup)
|
|
71
|
+
- The setup has many nodes and would clutter the main scene
|
|
72
|
+
- You want to edit a prefab in isolation
|
|
73
|
+
|
|
74
|
+
**Use inline nodes when:**
|
|
75
|
+
- The node is unique to this scene (main camera, level-specific light)
|
|
76
|
+
- It's a simple one-off (single MeshInstance3D)
|
|
77
|
+
|
|
78
|
+
### Creating a Sub-Scene
|
|
79
|
+
|
|
80
|
+
1. Build the hierarchy in the main scene
|
|
81
|
+
2. Select the root of what you want to extract
|
|
82
|
+
3. Save as scene: `summer_save_scene(path="res://scenes/player.tscn")` — but note: SaveScene saves the *current* scene. To save a branch, you typically save the open scene first, then in the editor you'd use "Save Branch as Scene." MCP doesn't have a direct "save branch" op—so for now, create the sub-scene as its own file via `summer_write_file` or build it in a separate scene and save.
|
|
83
|
+
4. In the main scene, add it with `summer_instantiate_scene(parent="./World", scene="res://scenes/player.tscn", name="Player")`
|
|
84
|
+
|
|
85
|
+
**Practical approach:** Create reusable scenes (player.tscn, enemy.tscn) as separate scene files, then instantiate them into levels.
|
|
86
|
+
|
|
87
|
+
## InstantiateScene vs AddNode
|
|
88
|
+
|
|
89
|
+
| Use | Tool | Example |
|
|
90
|
+
|-----|------|---------|
|
|
91
|
+
| Built-in mesh (Box, Sphere) | AddNode + SetProp | `summer_add_node` type=MeshInstance3D, then `summer_set_prop` mesh=BoxMesh |
|
|
92
|
+
| Existing .tscn prefab | InstantiateScene | `summer_instantiate_scene` scene=res://player.tscn |
|
|
93
|
+
| Imported .glb model | ImportFromUrl then InstantiateScene | Import first, then instantiate |
|
|
94
|
+
|
|
95
|
+
**Do not** use `summer_set_prop` with `mesh` for a .glb path. Use `summer_instantiate_scene` for .tscn and .glb files.
|
|
96
|
+
|
|
97
|
+
## Save Conventions
|
|
98
|
+
|
|
99
|
+
- Always call `summer_save_scene` after changes you want to keep
|
|
100
|
+
- For new scenes: `summer_save_scene(path="res://scenes/level1.tscn")`
|
|
101
|
+
- For existing scenes: `summer_save_scene` (no path, uses current scene path)
|
|
102
|
+
|
|
103
|
+
## Common Mistakes
|
|
104
|
+
|
|
105
|
+
1. **Wrong parent path:** `./NonExistent` fails. Ensure the parent exists before adding children.
|
|
106
|
+
2. **Unnamed scene:** Saving without a path fails if the scene was never saved. Use `path` for new scenes.
|
|
107
|
+
3. **Duplicate names:** Godot auto-renames (Node, Node2, etc.). Use descriptive unique names.
|
|
108
|
+
4. **Mixing 2D and 3D:** Don't put Node2D under Node3D or vice versa in the same hierarchy.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-basics
|
|
3
|
+
description: HUD, menus, health bars, and responsive UI layout. Use when building menus, HUDs, health bars, or Control-based UI in Summer Engine.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility:
|
|
6
|
+
- Cursor
|
|
7
|
+
- Claude Code
|
|
8
|
+
- Windsurf
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# UI Basics for Summer Engine
|
|
12
|
+
|
|
13
|
+
Build menus and HUDs using Godot's Control nodes. Follow these patterns for layout, buttons, and responsive design.
|
|
14
|
+
|
|
15
|
+
## Control Hierarchy
|
|
16
|
+
|
|
17
|
+
Use containers for layout, then add content nodes:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Control or CanvasLayer (root)
|
|
21
|
+
└── MarginContainer
|
|
22
|
+
└── VBoxContainer (or HBoxContainer)
|
|
23
|
+
├── Label
|
|
24
|
+
├── Button
|
|
25
|
+
├── Button
|
|
26
|
+
└── ProgressBar
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Common Containers
|
|
30
|
+
|
|
31
|
+
| Container | Use |
|
|
32
|
+
|-----------|-----|
|
|
33
|
+
| MarginContainer | Padding from edges |
|
|
34
|
+
| VBoxContainer | Stack vertically |
|
|
35
|
+
| HBoxContainer | Stack horizontally |
|
|
36
|
+
| CenterContainer | Center child |
|
|
37
|
+
| GridContainer | Grid layout |
|
|
38
|
+
|
|
39
|
+
## Basic Menu
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
summer_add_node(parent="./", type="Control", name="MainMenu")
|
|
43
|
+
summer_add_node(parent="./MainMenu", type="MarginContainer", name="Margin")
|
|
44
|
+
summer_set_prop(path="./MainMenu/Margin", key="anchors_preset", value="15") # Full rect
|
|
45
|
+
summer_set_prop(path="./MainMenu/Margin", key="theme_override_constants/margin_left", value="50")
|
|
46
|
+
summer_set_prop(path="./MainMenu/Margin", key="theme_override_constants/margin_right", value="50")
|
|
47
|
+
summer_set_prop(path="./MainMenu/Margin", key="theme_override_constants/margin_top", value="50")
|
|
48
|
+
summer_set_prop(path="./MainMenu/Margin", key="theme_override_constants/margin_bottom", value="50")
|
|
49
|
+
|
|
50
|
+
summer_add_node(parent="./MainMenu/Margin", type="VBoxContainer", name="VBox")
|
|
51
|
+
summer_add_node(parent="./MainMenu/Margin/VBox", type="Label", name="Title")
|
|
52
|
+
summer_set_prop(path="./MainMenu/Margin/VBox/Title", key="text", value="My Game")
|
|
53
|
+
summer_add_node(parent="./MainMenu/Margin/VBox", type="Button", name="StartButton")
|
|
54
|
+
summer_set_prop(path="./MainMenu/Margin/VBox/StartButton", key="text", value="Start Game")
|
|
55
|
+
summer_add_node(parent="./MainMenu/Margin/VBox", type="Button", name="QuitButton")
|
|
56
|
+
summer_set_prop(path="./MainMenu/Margin/VBox/QuitButton", key="text", value="Quit")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For nested theme overrides, use `summer_set_resource_property` if the property is on a resource. For `theme_override_constants/margin_left`, it may be a direct node property—check Godot docs. Some constants are set via `add_theme_constant_override`. If `summer_set_prop` accepts `theme_override_constants/margin_left`, use it; otherwise the UI may need a script or theme resource.
|
|
60
|
+
|
|
61
|
+
## HUD (Health Bar)
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
summer_add_node(parent="./", type="CanvasLayer", name="HUD")
|
|
65
|
+
summer_add_node(parent="./HUD", type="MarginContainer", name="TopLeft")
|
|
66
|
+
summer_set_prop(path="./HUD/TopLeft", key="anchors_preset", value="1") # Top-left
|
|
67
|
+
summer_add_node(parent="./HUD/TopLeft", type="HBoxContainer", name="HealthContainer")
|
|
68
|
+
summer_add_node(parent="./HUD/TopLeft/HealthContainer", type="Label", name="HealthLabel")
|
|
69
|
+
summer_set_prop(path="./HUD/TopLeft/HealthContainer/HealthLabel", key="text", value="Health:")
|
|
70
|
+
summer_add_node(parent="./HUD/TopLeft/HealthContainer", type="ProgressBar", name="HealthBar")
|
|
71
|
+
summer_set_prop(path="./HUD/TopLeft/HealthContainer/HealthBar", key="max_value", value="100")
|
|
72
|
+
summer_set_prop(path="./HUD/TopLeft/HealthContainer/HealthBar", key="value", value="100")
|
|
73
|
+
summer_set_prop(path="./HUD/TopLeft/HealthContainer/HealthBar", key="size", value="Vector2(200, 20)")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
ProgressBar uses `value` and `max_value` for the fill. Update `value` from a script when health changes.
|
|
77
|
+
|
|
78
|
+
## Anchors Preset
|
|
79
|
+
|
|
80
|
+
Common preset values (Godot 4):
|
|
81
|
+
|
|
82
|
+
| Preset | Value | Description |
|
|
83
|
+
|--------|-------|-------------|
|
|
84
|
+
| Top Left | 0 | Anchor to top-left |
|
|
85
|
+
| Top Right | 1 | Anchor to top-right |
|
|
86
|
+
| Bottom Left | 2 | Anchor to bottom-left |
|
|
87
|
+
| Bottom Right | 3 | Anchor to bottom-right |
|
|
88
|
+
| Full Rect | 15 | Stretch to fill parent |
|
|
89
|
+
|
|
90
|
+
Set via `summer_set_prop(path, key="anchors_preset", value="15")`.
|
|
91
|
+
|
|
92
|
+
## Connecting Buttons
|
|
93
|
+
|
|
94
|
+
Wire the `pressed` signal to a handler:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
summer_connect_signal(emitter="./MainMenu/Margin/VBox/StartButton", signal="pressed", receiver="./MainMenu", method="_on_start_pressed")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The receiver node must have a script with `func _on_start_pressed() -> void:`.
|
|
101
|
+
|
|
102
|
+
## Property Reference
|
|
103
|
+
|
|
104
|
+
| Node | Property | Example |
|
|
105
|
+
|------|----------|---------|
|
|
106
|
+
| Label | text | `"Score: 0"` |
|
|
107
|
+
| Button | text | `"Start"` |
|
|
108
|
+
| ProgressBar | value | `75` |
|
|
109
|
+
| ProgressBar | max_value | `100` |
|
|
110
|
+
| Control | size | `"Vector2(200, 50)"` |
|
|
111
|
+
| Control | anchors_preset | `15` |
|
|
112
|
+
| Control | custom_minimum_size | `"Vector2(100, 30)"` |
|
|
113
|
+
|
|
114
|
+
## Responsive Layout
|
|
115
|
+
|
|
116
|
+
For UI that scales with window size:
|
|
117
|
+
1. Use `anchors_preset` to anchor to corners or edges
|
|
118
|
+
2. Use `size_flags_horizontal` and `size_flags_vertical` on children (SIZE_EXPAND_FILL, etc.)
|
|
119
|
+
3. MarginContainer with percentage-based margins (may need theme or script)
|
|
120
|
+
|
|
121
|
+
For simple cases, CenterContainer + fixed-size children works. For complex layouts, a Theme resource or script may be needed.
|
package/bin/summer.js
DELETED