summer-engine 1.3.1 → 1.3.2

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.
@@ -0,0 +1,210 @@
1
+ ---
2
+ name: brainstorm-game
3
+ description: Use when the user wants help deciding what game to make, scoping a new project, or turning a vague idea into a buildable plan. Walks through genre, scope, core loop, mechanics, and art direction, then writes a 1-page brief to `.summer/GameSoul.md`. Trigger on "brainstorm a game", "what should I make", "I want to make a game", "help me scope", "new game idea".
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: scene-and-project
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Glob Write Edit summer_get_project_context summer_get_scene_tree
9
+ paths: [".summer/**", "project.godot", "**/*.md"]
10
+ ---
11
+
12
+ # /brainstorm-game — Decide What Game to Build
13
+
14
+ ## Overview
15
+
16
+ Most game projects fail because they were never scoped. This skill turns "I want to make a game" into a 1-page brief that names the pitch, the core loop, three mechanics max, the art direction, and the scope (jam / vertical slice / full game). The brief lands at `.summer/GameSoul.md` — the file Summer's onboarding pipeline and every future `summer:` skill reads on first turn.
17
+
18
+ **Core principle:** Constrain ruthlessly. A buildable bad idea beats an un-buildable great idea. Three mechanics, one art direction, one scope. Anything else gets parked in a "Later" list.
19
+
20
+ ## Steps
21
+
22
+ ### 1. Open with the one question
23
+
24
+ Ask exactly this and wait:
25
+
26
+ > One sentence — what kind of game do you want to make?
27
+
28
+ Don't pre-pitch genres. Don't list options. Read what they say. The first sentence is signal.
29
+
30
+ If they freeze ("I don't know"), offer 4 reference points only:
31
+
32
+ > No worries. Pick the one that pulls you most: a) something cozy and exploratory (Stardew, A Short Hike), b) something tight and skill-based (Celeste, Hades), c) something story-led (Disco Elysium, Citizen Sleeper), d) something silly and short (Goat Sim, Untitled Goose). Or describe a different vibe.
33
+
34
+ ### 2. Branch on genre signal
35
+
36
+ Read their answer for a genre anchor and pick **one** branch. Don't ask multiple questions in parallel.
37
+
38
+ | Anchor word(s) | Branch |
39
+ |---|---|
40
+ | "shooter", "FPS", "TPS", "combat" | Action-Combat branch |
41
+ | "platformer", "metroidvania", "souls-like" | Skill-Platforming branch |
42
+ | "RPG", "story", "narrative", "dialogue" | Narrative branch |
43
+ | "roguelike", "deckbuilder", "auto-battler" | Run-Based branch |
44
+ | "sim", "cozy", "farming", "city-builder" | Sim branch |
45
+ | "puzzle", "physics", "sandbox" | Puzzle branch |
46
+ | "horror", "atmospheric" | Horror branch |
47
+ | "multiplayer", "PvP", "co-op" | Multiplayer branch (forces the multiplayer-or-not call before scope) |
48
+
49
+ If unclear, ask the smallest disambiguating question:
50
+
51
+ > Tighter on this — is it more "tense and dangerous" or "calm and exploratory"?
52
+
53
+ ### 3. Pin the core loop
54
+
55
+ A core loop is what the player does for 30 seconds, repeated. State a candidate and ask them to refine. Examples per branch:
56
+
57
+ | Branch | Candidate core loop |
58
+ |---|---|
59
+ | Action-Combat | "Enter room, read enemy patterns, kill, loot, advance." |
60
+ | Skill-Platforming | "See obstacle, attempt, fail, learn, retry, clear, next." |
61
+ | Narrative | "Walk to character, choose dialogue, see consequence, walk to next." |
62
+ | Run-Based | "Pick a card/weapon/build, fight, die, unlock, repeat with edge." |
63
+ | Sim | "Plan day, execute, harvest reward, plan next day." |
64
+ | Puzzle | "See state, form theory, test, observe, solve or rethink." |
65
+ | Horror | "Hear cue, locate threat, hide or flee, advance space." |
66
+
67
+ State your candidate. Ask:
68
+
69
+ > The 30-second loop I'm hearing: <candidate>. Does that match what you have in your head, or is the actual moment-to-moment different?
70
+
71
+ ### 4. Constrain to three mechanics maximum
72
+
73
+ Force the trade. State the rule:
74
+
75
+ > Three mechanics, no more. What are the three things this game has that other games in this genre don't?
76
+
77
+ If they pitch five, push back. Not "we'll add it later" — actually cut. Two examples for them to react to:
78
+
79
+ > Hades has three: dash-attack-cast, room reward choice, and run-end conversation. Everything else (mirror upgrades, weapon variants, bosses) is content built on those three. What are yours?
80
+
81
+ Common new-dev mistake: listing features ("inventory, crafting, quests") instead of mechanics ("a single resource that's both currency and ammo"). Push them toward verbs and decisions, not nouns and systems.
82
+
83
+ ### 5. Pick an art direction in one phrase
84
+
85
+ Not a paragraph. Examples to anchor:
86
+
87
+ - "Lo-fi PS1 polygons + dithered shader"
88
+ - "Hand-drawn 2D, single bold outline, 4-color palette"
89
+ - "Toon-shaded Nintendo-bright, no realistic lighting"
90
+ - "Pixel art, 16x16 tiles, GameBoy 4-shade green"
91
+
92
+ Ask:
93
+
94
+ > One phrase for the look. If a stranger asked your screenshot's style in 6 words, what do you say?
95
+
96
+ Don't go deeper here — `/summer:art-direction` is where the bible gets built. This is one phrase to seed it.
97
+
98
+ ### 6. Pin the scope
99
+
100
+ State the choices flat:
101
+
102
+ > Scope. Pick one: (a) a 4-hour jam-sized prototype — one mechanic, one level, one art direction, ships in a weekend. (b) a vertical slice — 30-60 minutes of polished play that proves the core loop, ships in 2-4 weeks. (c) a full game — 4-20 hours of content, ships in 6+ months.
103
+
104
+ If they flinch at (c), recommend (b). New devs almost always overestimate scope. Default recommendation if they're unsure: **vertical slice**.
105
+
106
+ ### 7. Sanity-check the combination
107
+
108
+ Do this in your head, not out loud unless something fails:
109
+
110
+ - Is the core loop achievable with the three mechanics + the chosen art direction in the chosen scope? If not, name what has to flex (usually scope down or merge two mechanics into one).
111
+ - Is there a hidden multiplayer requirement? ("4-player" or "co-op" anywhere = stop, multiplayer is its own scope explosion.)
112
+ - Is the art direction generatable / sourceable for a solo dev? (Photoreal 3D for a 4-week vertical slice is a red flag.)
113
+
114
+ If you spot a problem, raise it once, plainly:
115
+
116
+ > One concern: <X>. Suggest <flex Y>. OK or do you want to push through anyway?
117
+
118
+ ### 8. Draft the brief
119
+
120
+ Compose the 1-page brief. Format:
121
+
122
+ ```markdown
123
+ # <Game Name or "Untitled">
124
+
125
+ **Pitch:** <One sentence the player would tell a friend.>
126
+
127
+ **Core loop (30s):** <What the player does, repeated.>
128
+
129
+ **Three mechanics:**
130
+ 1. <Verb-led: "Parry to convert damage into mana" not "Combat system">
131
+ 2. <…>
132
+ 3. <…>
133
+
134
+ **Art direction (one phrase):** <…>
135
+
136
+ **Scope:** <Jam | Vertical slice | Full game>
137
+
138
+ **Win condition:** <How the player knows they succeeded — ending? Score? Unlock?>
139
+
140
+ **One thing this is NOT:** <Define by negation. Cuts scope creep later.>
141
+
142
+ **Inspirations:** <2-4 specific games, films, or images.>
143
+
144
+ **Parked for later:** <Things they pitched that didn't make the three.>
145
+ ```
146
+
147
+ ### 9. Ask permission and write
148
+
149
+ **Preferred (Summer MCP + host file write):**
150
+
151
+ > May I create `.summer/GameSoul.md` with this brief?
152
+
153
+ On yes, use `Write` (host file tool) — `.summer/GameSoul.md` is plain markdown, no engine import needed:
154
+
155
+ ```
156
+ Write .summer/GameSoul.md
157
+ ```
158
+
159
+ If `.summer/GameSoul.md` already exists, read it first, show what would change, ask:
160
+
161
+ > `.summer/GameSoul.md` already exists. May I overwrite it, or merge into a "Revision 2" section below the existing brief?
162
+
163
+ **Fallback (no host write tool — agent is read-only):**
164
+
165
+ Print the full brief to the user with the explicit instruction:
166
+
167
+ > Save this as `.summer/GameSoul.md` in your project root. Every Summer skill reads it.
168
+
169
+ ### 10. Route to the next step
170
+
171
+ End every successful brainstorm with a routing question:
172
+
173
+ > Brief saved. Next step:
174
+ > - `/summer:design-mechanic` — design the core loop in detail (recommended for vertical slice).
175
+ > - `/summer:design-level` — sketch level 1 / the tutorial.
176
+ > - `/summer:art-direction` — turn the one-phrase look into an art bible.
177
+ > - Or pick up `/summer:make-game` to start scaffolding the project.
178
+
179
+ Don't auto-pick. Let them decide.
180
+
181
+ ## Anti-patterns (don't do these)
182
+
183
+ | Anti-pattern | Why it fails |
184
+ |---|---|
185
+ | Asking 6 questions in a row before any branching | User feels interviewed, not collaborated with. Branch after each answer. |
186
+ | Letting them list 5+ mechanics | Three is the constraint. Without the constraint, the brief is useless. |
187
+ | Skipping the "one thing this is NOT" line | This is the single best scope-protection in the brief. Future "let's add X" gets compared against it. |
188
+ | Writing the brief without showing it first | They have to react to it. They'll catch their own bad fits when they read it back. |
189
+ | Defaulting to "full game" scope | New devs overestimate. Default to vertical slice; let them upgrade if they push. |
190
+ | Pitching a genre they didn't ask for | The first sentence they typed is signal. Don't override it. |
191
+ | Including art direction details | One phrase. Bible-building is `/summer:art-direction`. |
192
+ | Saving without asking | Always ask "May I create `.summer/GameSoul.md`?" — see collaborative-protocol. |
193
+
194
+ ## Collaborative protocol
195
+
196
+ This skill writes one file (`.summer/GameSoul.md`). Always ask before writing. Always show the brief inline before saving so the user can react. See `_shared/collaborative-protocol.md`.
197
+
198
+ ## Want a working starter?
199
+
200
+ No template — this is a workflow that produces the brief that drives template selection later. Once `.summer/GameSoul.md` exists, `/summer:make-game` can match it against `_shared/template-registry.md`.
201
+
202
+ ## See also
203
+
204
+ - `_shared/collaborative-protocol.md` — "May I write?" pattern
205
+ - `_shared/template-registry.md` — templates the brief will be matched against later
206
+ - `gameplay-mechanics/design-mechanic/SKILL.md` — design the core loop in detail
207
+ - `level-design/design-level/SKILL.md` — sketch level 1
208
+ - `rendering-and-lighting/art-direction/SKILL.md` — turn the one-phrase look into a full bible
209
+ - `audio/audio-direction/SKILL.md` — sonic identity
210
+ - `scene-and-project/make-game/SKILL.md` — scaffold the project once the brief is locked
@@ -0,0 +1,280 @@
1
+ ---
2
+ name: vfx
3
+ description: Use when the user says the game "feels flat", "needs juice", "lacks impact", or asks for particles, hit feedback, screen shake, camera juice, muzzle flashes, explosions, or pickup effects. Walks the user through a guided 30-minute polish pass that adds visible feedback to combat, movement, pickups, damage, and casting. Trigger on "vfx", "juice", "feels flat", "polish", "particles", "screen shake", "hit flash", "feedback".
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: visual-effects
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Edit Write summer_get_scene_tree summer_inspect_node summer_inspect_resource summer_add_node summer_set_prop summer_set_resource_property summer_connect_signal summer_save_scene summer_get_script_errors summer_play summer_stop
9
+ paths: ["**/*.gd", "**/*.tscn", "**/*.tres"]
10
+ ---
11
+
12
+ # /vfx — Visible Polish in 30 Minutes
13
+
14
+ A game with bad VFX feels like a tech demo. A game with good VFX feels alive even before the mechanics are deep. This skill is a guided polish pass: you ask the user *what feels flat*, then deliver one or two tight recipes that add immediately-visible feedback. No vague "add particles". Specific node, specific values, specific signal hookup, verified result.
15
+
16
+ ## Steps
17
+
18
+ ### 1. Ask which thing feels flat
19
+
20
+ Open with one focused question. Wait for the answer.
21
+
22
+ > What feels flat? Pick one to start: combat hits / movement / pickups / damage taken / explosions / spell casts / something else.
23
+
24
+ If the user says "all of it", anchor on **combat hits** — it gives the loudest perceived improvement per minute spent.
25
+
26
+ ### 2. Read the current scene state
27
+
28
+ Before adding anything, see what's there.
29
+
30
+ **Preferred (Summer MCP):**
31
+
32
+ ```
33
+ summer_get_scene_tree
34
+ summer_inspect_node "./World/Player" # or whichever node owns the action
35
+ ```
36
+
37
+ You're looking for: where the trigger lives (e.g. `body_entered` signal on a Hurtbox), whether a Camera3D exists for shake, whether the target has a MeshInstance3D for a flash material override.
38
+
39
+ **Fallback (no MCP):** ask the user to paste the relevant `.tscn` snippet or describe the parent of the actor.
40
+
41
+ ### 3. Pick the recipe and propose it explicitly
42
+
43
+ Each recipe is a tight bundle of (node + property + signal + script). Don't mix recipes — add one, see it land, stack later.
44
+
45
+ > I want to add a hit flash + 0.04s camera shake bound to the `damaged` signal on `./World/Enemy`. About 6 lines of GDScript and one Camera3D shake node. May I proceed?
46
+
47
+ ### 4. Apply the recipe
48
+
49
+ See **Recipes** below. Each is end-to-end: node tree, property values, signal hookup, GDScript stub.
50
+
51
+ ### 5. Verify
52
+
53
+ ```
54
+ summer_save_scene
55
+ summer_get_script_errors
56
+ summer_play
57
+ # user reproduces the trigger
58
+ summer_stop
59
+ ```
60
+
61
+ If it doesn't read on screen, the values are wrong (flash too dim, shake too short, particle lifetime too long). Tune one knob at a time.
62
+
63
+ ## Recipes
64
+
65
+ ### Recipe A — Hit flash (mesh albedo flicker)
66
+
67
+ **Goal:** when an enemy takes damage, the mesh flashes white for 80 ms. Single biggest-bang-for-buck VFX. Read instantly even at 60 fps.
68
+
69
+ **Approach:** swap to a flash material via `material_override`, then back. Use Tween for the timing.
70
+
71
+ **MCP path:**
72
+
73
+ ```
74
+ summer_add_node(parent="./World/Enemy", type="Node", name="HitFlash")
75
+ # attach script (see below) — script holds reference to MeshInstance3D and a flash StandardMaterial3D
76
+ ```
77
+
78
+ Script (`scripts/hit_flash.gd`):
79
+
80
+ ```gdscript
81
+ class_name HitFlash
82
+ extends Node
83
+
84
+ @export var mesh: MeshInstance3D
85
+ @export var flash_color: Color = Color(1.0, 1.0, 1.0)
86
+ @export var duration: float = 0.08
87
+
88
+ var _flash_mat: StandardMaterial3D
89
+ var _orig_mat: Material
90
+
91
+ func _ready() -> void:
92
+ if mesh == null:
93
+ push_warning("HitFlash: mesh export not assigned")
94
+ return
95
+ _orig_mat = mesh.get_surface_override_material(0)
96
+ _flash_mat = StandardMaterial3D.new()
97
+ _flash_mat.albedo_color = flash_color
98
+ _flash_mat.emission_enabled = true
99
+ _flash_mat.emission = flash_color
100
+ _flash_mat.emission_energy_multiplier = 2.0
101
+
102
+ func flash() -> void:
103
+ if mesh == null:
104
+ return
105
+ mesh.set_surface_override_material(0, _flash_mat)
106
+ var tween := create_tween()
107
+ tween.tween_interval(duration)
108
+ tween.tween_callback(func(): mesh.set_surface_override_material(0, _orig_mat))
109
+ ```
110
+
111
+ Wire the trigger:
112
+
113
+ ```
114
+ summer_connect_signal(from="./World/Enemy", signal="damaged", to="./World/Enemy/HitFlash", method="flash")
115
+ ```
116
+
117
+ **Tunable knobs:** `duration` (0.06–0.12 sec — under 0.06 reads as a flicker, over 0.12 looks slow), `emission_energy_multiplier` (1.5–3.0).
118
+
119
+ > CRITICAL: do NOT inline the StandardMaterial3D as a sub_resource via `summer_set_prop`. Build it in script (as above) or save it to `materials/flash.tres` and load. Inline sub_resources break `summer_set_resource_property` silently — see `_shared/mcp-tools-reference.md` § "Trap".
120
+
121
+ ### Recipe B — Screen shake (Camera3D wobble)
122
+
123
+ **Goal:** punchy 40–80 ms camera shake on impact. Ties hits to the player's body.
124
+
125
+ **Approach:** attach a shake script to the existing Camera3D. Don't spawn a new camera; reuse the player's.
126
+
127
+ ```
128
+ summer_inspect_node "./World/Player/Camera3D" # confirm the path
129
+ ```
130
+
131
+ Script (`scripts/camera_shake.gd`):
132
+
133
+ ```gdscript
134
+ class_name CameraShake
135
+ extends Camera3D
136
+
137
+ @export var trauma_decay: float = 5.0
138
+ @export var max_offset: Vector2 = Vector2(0.15, 0.15)
139
+ @export var max_roll: float = 0.05
140
+
141
+ var _trauma: float = 0.0
142
+ var _base_position: Vector3
143
+
144
+ func _ready() -> void:
145
+ _base_position = position
146
+
147
+ func add_trauma(amount: float) -> void:
148
+ _trauma = clamp(_trauma + amount, 0.0, 1.0)
149
+
150
+ func _process(delta: float) -> void:
151
+ if _trauma <= 0.0:
152
+ position = _base_position
153
+ rotation.z = 0.0
154
+ return
155
+ var shake := _trauma * _trauma # quadratic — feels punchy, not noisy
156
+ position = _base_position + Vector3(
157
+ randf_range(-max_offset.x, max_offset.x) * shake,
158
+ randf_range(-max_offset.y, max_offset.y) * shake,
159
+ 0.0
160
+ )
161
+ rotation.z = randf_range(-max_roll, max_roll) * shake
162
+ _trauma = max(_trauma - trauma_decay * delta, 0.0)
163
+ ```
164
+
165
+ Trigger from the player or any damage handler:
166
+
167
+ ```gdscript
168
+ $Camera3D.add_trauma(0.5) # 0.3 light hit, 0.5 normal, 0.8 heavy
169
+ ```
170
+
171
+ **Tunable knobs:** `max_offset` (0.05 subtle, 0.2 punchy, 0.4 cinematic), `trauma_decay` (3 long, 5 standard, 8 snappy). Quadratic falloff is the trick — linear feels twitchy.
172
+
173
+ ### Recipe C — Pickup sparkle (GPUParticles3D one-shot)
174
+
175
+ **Goal:** when a pickup is collected, emit a quick burst of particles where it disappeared.
176
+
177
+ **Approach:** GPUParticles3D set to `one_shot = true`, `emitting = true` triggered from script. Particle material **must** be a standalone `.tres` (inline sub_resource trap).
178
+
179
+ ```
180
+ summer_add_node(parent="./World/Pickup", type="GPUParticles3D", name="Sparkle")
181
+ summer_set_prop(path="./World/Pickup/Sparkle", key="one_shot", value="true")
182
+ summer_set_prop(path="./World/Pickup/Sparkle", key="amount", value="24")
183
+ summer_set_prop(path="./World/Pickup/Sparkle", key="lifetime", value="0.5")
184
+ summer_set_prop(path="./World/Pickup/Sparkle", key="explosiveness", value="0.95")
185
+ ```
186
+
187
+ For the `process_material`, save a `ParticleProcessMaterial.tres` first (see `asset-pipeline/asset-strategy/SKILL.md` for the pattern), then:
188
+
189
+ ```
190
+ summer_set_prop(path="./World/Pickup/Sparkle", key="process_material", value="res://materials/sparkle_particles.tres")
191
+ ```
192
+
193
+ In the pickup's collection handler:
194
+
195
+ ```gdscript
196
+ func _on_picked_up() -> void:
197
+ $Sparkle.restart()
198
+ $Sparkle.emitting = true
199
+ $Mesh.visible = false
200
+ await get_tree().create_timer(0.6).timeout
201
+ queue_free()
202
+ ```
203
+
204
+ `explosiveness = 0.95` is the difference between a continuous trickle and a satisfying *poof*. `0.0` = constant emission, `1.0` = all particles spawn at frame zero.
205
+
206
+ ### Recipe D — Muzzle flash (light + sprite + sound)
207
+
208
+ **Goal:** when a weapon fires, a brief OmniLight3D flash + Sprite3D billboard + audio cue. Sells the shot more than the projectile does.
209
+
210
+ ```
211
+ summer_add_node(parent="./World/Player/Weapon", type="OmniLight3D", name="MuzzleLight")
212
+ summer_set_prop(path="./World/Player/Weapon/MuzzleLight", key="light_color", value="Color(1.0, 0.85, 0.4)")
213
+ summer_set_prop(path="./World/Player/Weapon/MuzzleLight", key="light_energy", value="0.0")
214
+ summer_set_prop(path="./World/Player/Weapon/MuzzleLight", key="omni_range", value="2.5")
215
+ ```
216
+
217
+ Trigger from the fire function:
218
+
219
+ ```gdscript
220
+ func fire() -> void:
221
+ var light: OmniLight3D = $MuzzleLight
222
+ light.light_energy = 4.0
223
+ var tween := create_tween()
224
+ tween.tween_property(light, "light_energy", 0.0, 0.06)
225
+ $MuzzleSound.play()
226
+ $Camera3D.add_trauma(0.3) # if camera shake recipe applied
227
+ ```
228
+
229
+ Do NOT keep the light always-on at low energy — that costs a real-time light slot. Tween from 4.0 to 0.0 over 60 ms.
230
+
231
+ ### Recipe E — Explosion (5-element stack)
232
+
233
+ **Goal:** one Big Boom, all senses. Stack five small effects on the same trigger.
234
+
235
+ 1. **Light flash:** OmniLight3D, `light_energy` 0 → 8 → 0 over 200 ms
236
+ 2. **Particles:** GPUParticles3D one-shot, `amount` 64, `lifetime` 0.8, `explosiveness` 1.0
237
+ 3. **Camera shake:** `add_trauma(0.8)`
238
+ 4. **Audio:** AudioStreamPlayer3D, layered explosion
239
+ 5. **Hit-stop:** `Engine.time_scale = 0.05` for 60 ms, then 1.0
240
+
241
+ Hit-stop is the secret weapon. 60 ms of 0.05 time scale = the explosion lands. Use sparingly; once per "big" event. Reset with:
242
+
243
+ ```gdscript
244
+ Engine.time_scale = 0.05
245
+ await get_tree().create_timer(0.06).timeout
246
+ Engine.time_scale = 1.0
247
+ ```
248
+
249
+ ## Anti-patterns
250
+
251
+ | Don't | Do | Why |
252
+ |---|---|---|
253
+ | Inline sub_resource for ParticleProcessMaterial via `summer_set_prop` | Save standalone `.tres`, reference by path | `summer_set_resource_property` silently fails on inline sub_resources |
254
+ | Hit flash for 0.3 sec | Hit flash for 0.06–0.12 sec | Anything over ~120 ms reads as a "stay" not a flash |
255
+ | Camera shake with linear falloff | Quadratic falloff (`_trauma * _trauma`) | Linear feels jittery; quadratic feels weighty |
256
+ | `OmniLight3D` always on at low energy | Tween from off → on → off in 60–80 ms | Real-time lights have hard count limits per frame |
257
+ | GPUParticles3D `one_shot = false` for pickups | `one_shot = true`, `restart()` to fire | Otherwise particles trickle continuously and look wrong |
258
+ | Tween every property at once | Tween one or two; let the others snap | Over-animated polish reads as noise |
259
+ | `Engine.time_scale` < 0.1 for > 100 ms | `time_scale = 0.05` for 40–80 ms | Longer hit-stop feels broken, not satisfying |
260
+ | Particles with `lifetime > 1.0` for hits | `lifetime = 0.3–0.6` | Hit feedback should resolve before the next swing |
261
+
262
+ ## Collaborative protocol
263
+
264
+ This skill writes scripts and adds nodes. Always ask before each recipe is applied. Group related writes into one ask: "I'm about to add HitFlash + CameraShake + connect 2 signals. OK?" See `_shared/collaborative-protocol.md`.
265
+
266
+ ## Want a working starter?
267
+
268
+ No template — this is a workflow that bolts onto any existing scene. For a project that already has these recipes pre-wired, see `template-3d-fps` (hit flash + muzzle flash) and `template-3d-platformer` (pickup sparkle).
269
+
270
+ ## See also
271
+
272
+ - `_shared/mcp-tools-reference.md` — full MCP tool list, especially the inline-sub_resource trap
273
+ - `_shared/godot-version.md` — Godot 4.5 API notes
274
+ - `_shared/collaborative-protocol.md` — "May I write" pattern
275
+ - `_shared/gd-style.md` — typed GDScript conventions
276
+ - `post-processing/screen-shake/SKILL.md` — deeper camera-shake techniques (Perlin noise, trauma stacks)
277
+ - `visual-effects/gpuparticles-3d-basics/SKILL.md` — particle setup details
278
+ - `visual-effects/hit-impact-flashes/SKILL.md` — flash material variations
279
+ - `visual-effects/muzzle-flashes/SKILL.md` — muzzle flash deep dive
280
+ - `audio/sfx-pipeline/SKILL.md` — pairing audio with VFX