summer-engine 1.5.0 → 2.2.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/{marketplace.json → .claude-plugin/marketplace.json} +3 -3
- package/.claude-plugin/plugin.json +52 -11
- package/.codex-plugin/plugin.json +69 -8
- package/.cursor-plugin/plugin.json +53 -12
- package/.factory-plugin/plugin.json +20 -0
- package/.opencode/INSTALL.md +75 -0
- package/.opencode/plugins/summer.js +9 -6
- package/AGENTS.md +51 -0
- package/CHANGELOG.md +31 -1
- package/CLAUDE.md +5 -0
- package/GEMINI.md +56 -0
- package/README.md +409 -80
- package/_persona/summer/SKILL.md +113 -0
- package/dist/bin/summer.js +0 -0
- package/dist/commands/assets.d.ts +2 -0
- package/dist/commands/assets.js +189 -0
- package/dist/commands/create.js +55 -17
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +127 -0
- package/dist/commands/install.js +2 -2
- package/dist/commands/list.js +24 -5
- package/dist/commands/project.d.ts +2 -0
- package/dist/commands/project.js +170 -0
- package/dist/commands/scene.d.ts +2 -0
- package/dist/commands/scene.js +290 -0
- package/dist/lib/banner.js +2 -2
- package/dist/lib/log-filters.d.ts +53 -0
- package/dist/lib/log-filters.js +130 -0
- package/dist/lib/plugin-manifests.test.d.ts +1 -0
- package/dist/lib/plugin-manifests.test.js +134 -0
- package/dist/lib/remote-templates.d.ts +25 -0
- package/dist/lib/remote-templates.js +86 -0
- package/dist/lib/skills-registry.d.ts +283 -3
- package/dist/lib/skills-registry.js +522 -2
- package/dist/lib/telemetry.d.ts +13 -0
- package/dist/lib/telemetry.js +63 -0
- package/dist/lib/with-engine.d.ts +14 -0
- package/dist/lib/with-engine.js +109 -0
- package/dist/mcp/tools/asset-tools.js +12 -13
- package/dist/mcp/tools/debug-tools.js +32 -9
- package/dist/mcp/tools/generate-tools.js +101 -0
- package/dist/mcp/tools/with-engine.js +4 -0
- package/gemini-extension.json +2 -2
- package/hooks/pre-commit-doctor.sh +0 -0
- package/hooks/run-hook.cmd +0 -0
- package/hooks/session-start.sh +0 -0
- package/package.json +11 -5
- package/skills/2d-assets/character-portrait/SKILL.md +196 -0
- package/skills/2d-assets/concept-art/SKILL.md +152 -0
- package/skills/2d-assets/pixel-art/SKILL.md +180 -0
- package/skills/2d-assets/skybox-panorama/SKILL.md +207 -0
- package/skills/2d-assets/sprite-sheet/SKILL.md +239 -0
- package/skills/2d-assets/tileable-texture/SKILL.md +205 -0
- package/skills/2d-assets/ui-graphics/SKILL.md +210 -0
- package/skills/3d-assets/character-model/SKILL.md +225 -0
- package/skills/3d-assets/environment-kit/SKILL.md +164 -0
- package/skills/3d-assets/organic-model/SKILL.md +192 -0
- package/skills/3d-assets/prop-model/SKILL.md +133 -0
- package/skills/3d-assets/vehicle-model/SKILL.md +202 -0
- package/skills/README.md +1 -1
- package/skills/_meta/skill-create/SKILL.md +1 -1
- package/skills/_meta/skill-improve/SKILL.md +1 -1
- package/skills/_meta/skill-test/SKILL.md +1 -1
- package/skills/_meta/using-summer/SKILL.md +130 -0
- package/skills/ai-and-npcs/design-npc/SKILL.md +3 -1
- package/skills/animation/animation-tree/SKILL.md +260 -0
- package/skills/animation/facial-and-lipsync/SKILL.md +282 -0
- package/skills/animation/generate-motion/SKILL.md +129 -0
- package/skills/animation/procedural-animation/SKILL.md +234 -0
- package/skills/animation/retarget/SKILL.md +172 -0
- package/skills/asset-pipeline/asset-strategy/SKILL.md +102 -212
- package/skills/audio/adaptive-music/SKILL.md +326 -0
- package/skills/audio/ambient-bed/SKILL.md +278 -0
- package/skills/audio/music-track/SKILL.md +268 -0
- package/skills/audio/sound-effect/SKILL.md +237 -0
- package/skills/audio/voice-line/SKILL.md +253 -0
- package/skills/catalog.yaml +266 -5
- package/skills/character-controllers/fps-controller/SKILL.md +1 -1
- package/skills/debugging/debug/SKILL.md +102 -82
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +1 -1
- package/skills/scene-and-project/browse-templates/SKILL.md +105 -0
- package/skills/scene-and-project/make-game/SKILL.md +159 -346
- package/skills/scene-and-project/new-project/SKILL.md +106 -0
- package/skills/scene-and-project/scene-composition/SKILL.md +1 -1
- package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
- package/skills/ui-and-ux/ui-basics/SKILL.md +1 -1
- package/skills/video/animated-loop/SKILL.md +200 -0
- package/skills/video/cinematic-cutscene/SKILL.md +204 -0
- package/skills/video/trailer-shot/SKILL.md +203 -0
- package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +28 -0
- package/skills/visual-effects/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
- package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +51 -0
- package/skills/visual-effects/{vfx → game-feel}/SKILL.md +1 -1
- package/skills/visual-effects/recipes/dissolve/SKILL.md +349 -0
- package/skills/visual-effects/recipes/fire/SKILL.md +387 -0
- package/skills/visual-effects/recipes/hit-spark/SKILL.md +330 -0
- package/skills/visual-effects/recipes/lightning/SKILL.md +372 -0
- package/skills/visual-effects/recipes/magic-glow/SKILL.md +377 -0
- package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +326 -0
- package/skills/visual-effects/recipes/smoke/SKILL.md +381 -0
- package/skills/visual-effects/recipes/water-ripple/SKILL.md +340 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: magic-glow
|
|
3
|
+
description: Use when authoring a magic-glow visual effect — a pulsing OmniLight3D plus drifting additive motes plus optional emission shader on the source mesh. Trigger on "magic glow", "enchanted item", "soul gem", "pulsing aura", "rune glow", "magical orb", "summon circle glow", "fairy", "wisp".
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: visual-effects
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: Read Write Edit summer_add_node summer_set_prop summer_set_resource_property summer_inspect_node summer_save_scene
|
|
9
|
+
paths: ["**/*.tscn", "**/*.gd", "**/*.gdshader", "addons/vfx/**"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# magic-glow — Pulsing Light + Drifting Motes
|
|
13
|
+
|
|
14
|
+
Three layered cues that together read as "magical": a pulsing `OmniLight3D` (sin-wave energy), drifting additive billboard motes orbiting the source, and optional emission on the source mesh itself. Used for: enchanted items, soul gems, runes, summoning circles, wisps, fairies, magical waypoints. The recipe writes a single controller that builds and animates all three layers from one node.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- "This sword is enchanted — add a glow."
|
|
19
|
+
- "Make the soul gem pulse with light."
|
|
20
|
+
- "Magic rune on the floor glowing."
|
|
21
|
+
- "Wisp / fairy / firefly companion."
|
|
22
|
+
- "The summoning circle is active."
|
|
23
|
+
- "Quest item glows so the player notices it."
|
|
24
|
+
- Pre-charge phase before casting `lightning` or `muzzle-flash` (charge-up beam).
|
|
25
|
+
|
|
26
|
+
## When NOT to use
|
|
27
|
+
|
|
28
|
+
- The user wants a static, non-animated glow — just enable emission on the mesh's material; this recipe is overkill.
|
|
29
|
+
- The user wants flames, not a glow — use `fire` (or `magic-fire` variant of `fire`).
|
|
30
|
+
- The user wants a beam shooting out, not an aura — use `lightning` with the `plasma-laser` variant.
|
|
31
|
+
- The user wants a screen-space bloom on the whole scene — that's `WorldEnvironment.glow_*`, not a per-object recipe.
|
|
32
|
+
- The user wants a 2D glow on a UI sprite — use `canvas_item` shader with a radial gradient, not this 3D recipe.
|
|
33
|
+
|
|
34
|
+
## Recipe
|
|
35
|
+
|
|
36
|
+
### 1. Files to create
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
addons/vfx/magic-glow/magic_glow.gd
|
|
40
|
+
addons/vfx/magic-glow/magic_glow.tscn
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
No custom shader — uses canonical additive billboard motes (see `_building-blocks/additive-billboard-particles.md`) plus an `OmniLight3D`. Optional: pair with the source mesh's existing material's emission.
|
|
44
|
+
|
|
45
|
+
### 2. GDScript controller
|
|
46
|
+
|
|
47
|
+
`addons/vfx/magic-glow/magic_glow.gd`:
|
|
48
|
+
|
|
49
|
+
```gdscript
|
|
50
|
+
@tool
|
|
51
|
+
class_name MagicGlow
|
|
52
|
+
extends Node3D
|
|
53
|
+
|
|
54
|
+
## Builds: OmniLight3D (pulsing) + GPUParticles3D motes (drifting orbit) + optional mesh emission tween.
|
|
55
|
+
## Add as a child of any glowing object.
|
|
56
|
+
|
|
57
|
+
@export_group("Color")
|
|
58
|
+
@export var glow_color: Color = Color(0.55, 0.85, 1.0)
|
|
59
|
+
@export_range(0.0, 12.0) var light_energy_base: float = 1.4
|
|
60
|
+
@export_range(0.0, 12.0) var light_energy_amplitude: float = 0.8
|
|
61
|
+
|
|
62
|
+
@export_group("Pulse")
|
|
63
|
+
@export_range(0.05, 4.0) var pulse_hz: float = 0.7
|
|
64
|
+
@export var pulse_easing: Curve ## leave null for sine; assign for custom
|
|
65
|
+
|
|
66
|
+
@export_group("Light")
|
|
67
|
+
@export_range(0.5, 30.0) var light_range: float = 4.0
|
|
68
|
+
@export var light_shadow_enabled: bool = false
|
|
69
|
+
|
|
70
|
+
@export_group("Motes")
|
|
71
|
+
@export_range(0, 256) var mote_count: int = 24
|
|
72
|
+
@export_range(0.05, 4.0) var mote_radius: float = 0.6
|
|
73
|
+
@export_range(0.5, 8.0) var mote_lifetime: float = 2.0
|
|
74
|
+
@export_range(0.01, 0.30) var mote_size: float = 0.06
|
|
75
|
+
@export_range(0.0, 8.0) var mote_emission_boost: float = 4.0
|
|
76
|
+
@export var mote_drift_up: float = 0.3 ## meters/sec mean upward drift
|
|
77
|
+
|
|
78
|
+
@export_group("Source mesh emission (optional)")
|
|
79
|
+
@export var pulse_source_mesh: NodePath ## point at a MeshInstance3D to tween its emission_energy_multiplier
|
|
80
|
+
@export_range(0.0, 12.0) var source_emission_base: float = 1.0
|
|
81
|
+
@export_range(0.0, 12.0) var source_emission_amplitude: float = 1.5
|
|
82
|
+
|
|
83
|
+
var _light: OmniLight3D
|
|
84
|
+
var _motes: GPUParticles3D
|
|
85
|
+
var _source_mesh: MeshInstance3D
|
|
86
|
+
var _source_mat: BaseMaterial3D
|
|
87
|
+
var _t: float = 0.0
|
|
88
|
+
|
|
89
|
+
func _ready() -> void:
|
|
90
|
+
_build_light()
|
|
91
|
+
_build_motes()
|
|
92
|
+
_resolve_source_mesh()
|
|
93
|
+
set_process(true)
|
|
94
|
+
|
|
95
|
+
func _build_light() -> void:
|
|
96
|
+
_light = OmniLight3D.new()
|
|
97
|
+
_light.light_color = glow_color
|
|
98
|
+
_light.light_energy = light_energy_base
|
|
99
|
+
_light.omni_range = light_range
|
|
100
|
+
_light.shadow_enabled = light_shadow_enabled
|
|
101
|
+
add_child(_light)
|
|
102
|
+
|
|
103
|
+
func _build_motes() -> void:
|
|
104
|
+
if mote_count <= 0:
|
|
105
|
+
return
|
|
106
|
+
_motes = GPUParticles3D.new()
|
|
107
|
+
_motes.amount = mote_count
|
|
108
|
+
_motes.lifetime = mote_lifetime
|
|
109
|
+
_motes.one_shot = false
|
|
110
|
+
_motes.explosiveness = 0.0
|
|
111
|
+
_motes.local_coords = true
|
|
112
|
+
|
|
113
|
+
var pm := ParticleProcessMaterial.new()
|
|
114
|
+
pm.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE
|
|
115
|
+
pm.emission_sphere_radius = mote_radius
|
|
116
|
+
pm.direction = Vector3.UP
|
|
117
|
+
pm.spread = 180.0
|
|
118
|
+
pm.initial_velocity_min = 0.05
|
|
119
|
+
pm.initial_velocity_max = 0.20
|
|
120
|
+
pm.gravity = Vector3(0, mote_drift_up * 0.5, 0)
|
|
121
|
+
pm.scale_min = mote_size * 0.7
|
|
122
|
+
pm.scale_max = mote_size * 1.3
|
|
123
|
+
pm.color = glow_color
|
|
124
|
+
pm.damping_min = 0.5
|
|
125
|
+
pm.damping_max = 1.2
|
|
126
|
+
_motes.process_material = pm
|
|
127
|
+
|
|
128
|
+
var mesh := QuadMesh.new()
|
|
129
|
+
mesh.size = Vector2.ONE
|
|
130
|
+
var bm := BaseMaterial3D.new()
|
|
131
|
+
bm.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
|
132
|
+
bm.blend_mode = BaseMaterial3D.BLEND_MODE_ADD
|
|
133
|
+
bm.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
134
|
+
bm.billboard_mode = BaseMaterial3D.BILLBOARD_PARTICLES
|
|
135
|
+
bm.albedo_color = glow_color
|
|
136
|
+
bm.emission_enabled = true
|
|
137
|
+
bm.emission = glow_color
|
|
138
|
+
bm.emission_energy_multiplier = mote_emission_boost
|
|
139
|
+
mesh.material = bm
|
|
140
|
+
_motes.draw_pass_1 = mesh
|
|
141
|
+
|
|
142
|
+
add_child(_motes)
|
|
143
|
+
|
|
144
|
+
func _resolve_source_mesh() -> void:
|
|
145
|
+
if pulse_source_mesh.is_empty(): return
|
|
146
|
+
var n := get_node_or_null(pulse_source_mesh)
|
|
147
|
+
if n is MeshInstance3D:
|
|
148
|
+
_source_mesh = n
|
|
149
|
+
var m := _source_mesh.get_active_material(0)
|
|
150
|
+
if m is BaseMaterial3D:
|
|
151
|
+
_source_mat = m
|
|
152
|
+
_source_mat.emission_enabled = true
|
|
153
|
+
if _source_mat.emission == Color.BLACK:
|
|
154
|
+
_source_mat.emission = glow_color
|
|
155
|
+
|
|
156
|
+
func _process(delta: float) -> void:
|
|
157
|
+
_t += delta
|
|
158
|
+
var phase: float = (sin(_t * TAU * pulse_hz) + 1.0) * 0.5 # 0..1
|
|
159
|
+
if pulse_easing:
|
|
160
|
+
phase = pulse_easing.sample(phase)
|
|
161
|
+
|
|
162
|
+
if _light:
|
|
163
|
+
_light.light_energy = light_energy_base + light_energy_amplitude * phase
|
|
164
|
+
if _source_mat:
|
|
165
|
+
_source_mat.emission_energy_multiplier = source_emission_base + source_emission_amplitude * phase
|
|
166
|
+
|
|
167
|
+
func set_intensity(scale: float) -> void:
|
|
168
|
+
## Scale all visible cues 0..1+ (e.g., charge-up: tween from 0 to 1 over a second).
|
|
169
|
+
light_energy_base *= scale
|
|
170
|
+
light_energy_amplitude *= scale
|
|
171
|
+
if _motes:
|
|
172
|
+
_motes.amount_ratio = scale
|
|
173
|
+
|
|
174
|
+
func extinguish(fade_seconds: float = 0.6) -> void:
|
|
175
|
+
var t := create_tween().set_parallel(true)
|
|
176
|
+
t.tween_property(_light, "light_energy", 0.0, fade_seconds)
|
|
177
|
+
if _motes:
|
|
178
|
+
t.tween_property(_motes, "amount_ratio", 0.0, fade_seconds)
|
|
179
|
+
t.chain().tween_callback(queue_free)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 3. Node tree
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
Node3D ("MagicGlow") [script: magic_glow.gd]
|
|
186
|
+
├── OmniLight3D (created at runtime, pulses)
|
|
187
|
+
└── GPUParticles3D (created at runtime, drifting motes)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 4. Wire it in (MCP calls)
|
|
191
|
+
|
|
192
|
+
For an enchanted sword:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
summer_add_node(parent="./Player/Hand/Sword", type="Node3D", name="Glow")
|
|
196
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="script", value="res://addons/vfx/magic-glow/magic_glow.gd")
|
|
197
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="glow_color", value="Color(0.55, 0.85, 1.0)")
|
|
198
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="light_energy_base", value=1.2)
|
|
199
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="light_energy_amplitude", value=0.6)
|
|
200
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="mote_count", value=16)
|
|
201
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="mote_radius", value=0.20)
|
|
202
|
+
summer_set_prop(path="./Player/Hand/Sword/Glow", property="pulse_source_mesh", value="../Blade")
|
|
203
|
+
summer_save_scene
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
For a soul gem on a pedestal:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
summer_add_node(parent="./World/Pedestal/SoulGem", type="Node3D", name="Glow")
|
|
210
|
+
summer_set_prop(path="./World/Pedestal/SoulGem/Glow", property="glow_color", value="Color(0.85, 0.45, 1.0)")
|
|
211
|
+
summer_set_prop(path="./World/Pedestal/SoulGem/Glow", property="pulse_hz", value=0.4)
|
|
212
|
+
summer_set_prop(path="./World/Pedestal/SoulGem/Glow", property="mote_count", value=32)
|
|
213
|
+
summer_set_prop(path="./World/Pedestal/SoulGem/Glow", property="mote_radius", value=0.30)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For a charge-up before casting:
|
|
217
|
+
|
|
218
|
+
```gdscript
|
|
219
|
+
# Spawn at the wizard's hand:
|
|
220
|
+
var glow: MagicGlow = preload("res://addons/vfx/magic-glow/magic_glow.tscn").instantiate()
|
|
221
|
+
$Wizard/HandTip.add_child(glow)
|
|
222
|
+
glow.set_intensity(0.0)
|
|
223
|
+
var t := create_tween()
|
|
224
|
+
t.tween_method(glow.set_intensity, 0.0, 1.0, 0.8)
|
|
225
|
+
t.tween_callback(func() -> void:
|
|
226
|
+
Lightning.cast_lightning($Wizard/HandTip.global_position, target.global_position)
|
|
227
|
+
glow.extinguish(0.3))
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 5. Parameters to tune
|
|
231
|
+
|
|
232
|
+
| Parameter | Range | Effect |
|
|
233
|
+
|---|---|---|
|
|
234
|
+
| `glow_color` | Color | controls light, motes, and (if linked) source emission |
|
|
235
|
+
| `light_energy_base` | 0.0–12.0 | resting light brightness |
|
|
236
|
+
| `light_energy_amplitude` | 0.0–12.0 | pulse swing on top of base |
|
|
237
|
+
| `pulse_hz` | 0.05–4.0 | beats per second; <1 for slow breathing, >2 for buzzing |
|
|
238
|
+
| `light_range` | 0.5–30.0 m | reach of the light cast |
|
|
239
|
+
| `mote_count` | 0–256 | number of motes orbiting (0 = light only) |
|
|
240
|
+
| `mote_radius` | 0.05–4.0 m | spawn sphere radius around the source |
|
|
241
|
+
| `mote_lifetime` | 0.5–8.0 s | how long each mote drifts |
|
|
242
|
+
| `mote_size` | 0.01–0.30 m | per-mote billboard size |
|
|
243
|
+
| `mote_emission_boost` | 0.0–8.0 | bloom strength of motes |
|
|
244
|
+
| `mote_drift_up` | -1.0–3.0 | mean upward drift (negative = sink) |
|
|
245
|
+
| `pulse_source_mesh` | NodePath | optional: pulse a mesh's emission with the same phase |
|
|
246
|
+
|
|
247
|
+
## Cookbook — named variants
|
|
248
|
+
|
|
249
|
+
### enchanted-sword (default)
|
|
250
|
+
|
|
251
|
+
Cool blue, gentle pulse, few tight motes.
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
glow_color = Color(0.55, 0.85, 1.0)
|
|
255
|
+
light_energy_base = 1.2
|
|
256
|
+
light_energy_amplitude = 0.5
|
|
257
|
+
pulse_hz = 0.7
|
|
258
|
+
light_range = 3.0
|
|
259
|
+
mote_count = 16
|
|
260
|
+
mote_radius = 0.15
|
|
261
|
+
mote_size = 0.04
|
|
262
|
+
pulse_source_mesh = "../Blade" # blade emission pulses too
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### soul-gem
|
|
266
|
+
|
|
267
|
+
Deeper purple, slow heartbeat pulse, many motes.
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
glow_color = Color(0.75, 0.30, 1.0)
|
|
271
|
+
light_energy_base = 1.0
|
|
272
|
+
light_energy_amplitude = 0.8
|
|
273
|
+
pulse_hz = 0.4
|
|
274
|
+
light_range = 4.0
|
|
275
|
+
mote_count = 32
|
|
276
|
+
mote_radius = 0.25
|
|
277
|
+
mote_size = 0.05
|
|
278
|
+
mote_drift_up = 0.4
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### summoning-circle
|
|
282
|
+
|
|
283
|
+
Strong, broad, many motes drifting upward.
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
glow_color = Color(0.45, 0.80, 1.0)
|
|
287
|
+
light_energy_base = 0.8
|
|
288
|
+
light_energy_amplitude = 1.6
|
|
289
|
+
pulse_hz = 0.3
|
|
290
|
+
light_range = 8.0
|
|
291
|
+
mote_count = 96
|
|
292
|
+
mote_radius = 1.5
|
|
293
|
+
mote_size = 0.08
|
|
294
|
+
mote_drift_up = 1.0
|
|
295
|
+
mote_lifetime = 3.0
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### wisp-companion
|
|
299
|
+
|
|
300
|
+
Tiny floating orb. Attach to a `PathFollow3D` for the wandering motion.
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
glow_color = Color(0.85, 1.0, 0.65)
|
|
304
|
+
light_energy_base = 0.6
|
|
305
|
+
light_energy_amplitude = 0.3
|
|
306
|
+
pulse_hz = 1.2
|
|
307
|
+
light_range = 2.5
|
|
308
|
+
mote_count = 8
|
|
309
|
+
mote_radius = 0.10
|
|
310
|
+
mote_size = 0.03
|
|
311
|
+
mote_drift_up = 0.0
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### charge-up (paired with lightning/muzzle-flash)
|
|
315
|
+
|
|
316
|
+
Starts at 0 intensity, ramped via `set_intensity`. Set initial values for fully-charged state.
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
glow_color = Color(0.55, 0.75, 1.0)
|
|
320
|
+
light_energy_base = 0.0 # script tweens this up
|
|
321
|
+
light_energy_amplitude = 2.0
|
|
322
|
+
pulse_hz = 2.5 # buzzing
|
|
323
|
+
mote_count = 24
|
|
324
|
+
mote_radius = 0.20
|
|
325
|
+
mote_drift_up = 0.5
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Anti-patterns
|
|
329
|
+
|
|
330
|
+
- **`light_shadow_enabled = true` on every magical item.** A player carrying a glowing sword adds a fast-moving shadow caster; expensive. Default off.
|
|
331
|
+
- **Light range too large** (10+ m for a small item). The glow lights up an entire room and the player loses sense of location. Match `light_range` to the item's importance.
|
|
332
|
+
- **Mote material set to `BLEND_MODE_MIX`.** Motes look like opaque dots, not glowing dust. Always `BLEND_MODE_ADD`.
|
|
333
|
+
- **Motes parented in world space (`local_coords = false`) for an item the player carries.** Motes trail behind as the player walks. Default `local_coords = true`.
|
|
334
|
+
- **Forgetting to enable the source mesh's emission before assigning the glow color.** The shader's emission stays black. The controller's `_resolve_source_mesh` enables it.
|
|
335
|
+
- **`pulse_hz` too high.** Above 3 Hz it strobes — accessibility issue (photosensitivity). Default 0.7 is calm.
|
|
336
|
+
- **Generating an "aura" PNG and using as a billboard sprite.** The misroute. The procedural light + motes are alive and scale to any item.
|
|
337
|
+
|
|
338
|
+
## Performance notes
|
|
339
|
+
|
|
340
|
+
- One glow = 1 light + 16–32 particles. ~0.05 ms total. Cheap.
|
|
341
|
+
- N glowing items in a scene: budget ~12 active `OmniLight3D`s before you should consider `LightOccluder3D` culling. Motes scale linearly to ~512 across all glows.
|
|
342
|
+
- Mobile: drop `mote_count` to 8, `light_range` × 0.5, `light_shadow_enabled = false` always.
|
|
343
|
+
- LOD: in `_process`, scale `_motes.amount_ratio` and `_light.light_energy` by `clamp(1.5 - dist_to_camera / 20.0, 0.10, 1.0)`. Past 20 m, drop motes entirely; keep light.
|
|
344
|
+
|
|
345
|
+
## Edge cases
|
|
346
|
+
|
|
347
|
+
- **Glow on a moving NPC's head (wisp follower).** Set `local_coords = true` (default) and parent under the NPC. The light moves with the character.
|
|
348
|
+
- **Glow on a particle system** (e.g., the wisp is a particle itself). Don't — combine into a single Node3D with the glow attached, or the light won't track the particle's position.
|
|
349
|
+
- **Multiple glows on the same object** (sword pommel + blade). Two MagicGlow children, different `pulse_hz` and slightly offset phases → richer feel. Use `pulse_easing` curve to sync if you want them to beat together.
|
|
350
|
+
- **Glow visible underwater.** Reduce `light_range` 50% (water absorbs light); tint slightly green.
|
|
351
|
+
- **Pulse needs to sync with audio (heartbeat).** Drive `pulse_hz` from your audio system's BPM, or replace `_process` with an `AnimationPlayer` track timed to a music event.
|
|
352
|
+
|
|
353
|
+
## Fallback (no MCP)
|
|
354
|
+
|
|
355
|
+
VFX is code, no MCP required:
|
|
356
|
+
|
|
357
|
+
1. Create `addons/vfx/magic-glow/` with the two files above.
|
|
358
|
+
2. In Godot, add a `Node3D` child to the glowing object, attach `magic_glow.gd`. Save as `magic_glow.tscn` if you want a scene to instantiate.
|
|
359
|
+
3. Tune the exported parameters in the inspector or via script.
|
|
360
|
+
|
|
361
|
+
## Handoff
|
|
362
|
+
|
|
363
|
+
After firing this recipe, suggest:
|
|
364
|
+
|
|
365
|
+
- `summer:visual-effects/recipes/lightning` — perfect pre-cast charge-up. Use the `charge-up` variant and ramp `set_intensity(0→1)` then call `Lightning.cast_lightning`.
|
|
366
|
+
- `summer:visual-effects/recipes/dissolve` — pair `summon-arrival` (materialize_object) with the `summoning-circle` variant.
|
|
367
|
+
- `summer:visual-effects/recipes/fire` (the `magic-fire` variant) — for items that should glow AND flame.
|
|
368
|
+
- `summer:visual-effects/game-feel` — slight time-dilation when picking up a pulsing quest item adds weight.
|
|
369
|
+
- `summer:audio/sound-effect` — generate `magical hum, ethereal shimmer, 2s loop` and play on the same anchor.
|
|
370
|
+
|
|
371
|
+
## See also
|
|
372
|
+
|
|
373
|
+
- `_building-blocks/additive-billboard-particles.md` — canonical additive material settings (this recipe uses them for motes)
|
|
374
|
+
- `summer:visual-effects/recipes/lightning` — pre-cast charge-up partner
|
|
375
|
+
- `summer:visual-effects/recipes/dissolve` — for summon arrival pairing
|
|
376
|
+
- `summer:visual-effects/recipes/fire` — for the `magic-fire` variant
|
|
377
|
+
- `summer:gdscript-patterns` — for the controller idioms (signals, exports, `@tool`)
|