summer-engine 2.6.6 → 2.8.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +4 -1
- package/.codex-plugin/plugin.json +6 -2
- package/.cursor-plugin/plugin.json +5 -1
- package/.opencode/INSTALL.md +1 -1
- package/.opencode/plugins/summer.js +2 -2
- package/AGENTS.md +11 -7
- package/CHANGELOG.md +40 -0
- package/GEMINI.md +9 -7
- package/README.md +63 -21
- package/_persona/summer/SKILL.md +1 -0
- package/assets/autopilot/README.md +51 -0
- package/assets/autopilot/autopilot.gd +222 -0
- package/assets/autopilot/probe_base.gd +262 -0
- package/assets/autopilot/run.sh +78 -0
- package/commands/gameskill.md +11 -2
- package/commands/summer.md +13 -0
- package/dist/bin/summer.js +12 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +53 -0
- package/dist/commands/create.d.ts +1 -0
- package/dist/commands/create.js +38 -6
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +44 -0
- package/dist/commands/doctor.js +112 -8
- package/dist/commands/list.js +1 -1
- package/dist/commands/login.d.ts +19 -0
- package/dist/commands/login.js +123 -36
- package/dist/commands/logout.js +3 -16
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +19 -0
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/open.js +1 -1
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +20 -0
- package/dist/commands/releases.d.ts +2 -0
- package/dist/commands/releases.js +20 -0
- package/dist/commands/run.js +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/lib/api-client.d.ts +15 -4
- package/dist/lib/api-client.js +138 -13
- package/dist/lib/async-op-lifecycle.d.ts +7 -2
- package/dist/lib/async-op-lifecycle.js +32 -9
- package/dist/lib/auth.d.ts +40 -12
- package/dist/lib/auth.js +173 -37
- package/dist/lib/cloud/engine-bridge.d.ts +17 -4
- package/dist/lib/cloud/engine-bridge.js +32 -6
- package/dist/lib/config.d.ts +20 -0
- package/dist/lib/config.js +142 -0
- package/dist/lib/creator.d.ts +93 -0
- package/dist/lib/creator.js +393 -0
- package/dist/lib/debug-report.d.ts +50 -0
- package/dist/lib/debug-report.js +308 -0
- package/dist/lib/engine.d.ts +35 -2
- package/dist/lib/engine.js +240 -6
- package/dist/lib/game-task-plan.js +4 -4
- package/dist/lib/mcp-boot-notice.d.ts +3 -0
- package/dist/lib/mcp-boot-notice.js +7 -0
- package/dist/lib/mcp-log.d.ts +3 -0
- package/dist/lib/mcp-log.js +72 -0
- package/dist/lib/public-surface-paths.d.ts +13 -0
- package/dist/lib/public-surface-paths.js +42 -0
- package/dist/lib/skills-registry.d.ts +33 -1
- package/dist/lib/skills-registry.js +55 -0
- package/dist/lib/store.d.ts +14 -0
- package/dist/lib/store.js +145 -0
- package/dist/lib/summer-compatibility.d.ts +6 -0
- package/dist/lib/summer-compatibility.js +22 -0
- package/dist/mcp/server.d.ts +10 -3
- package/dist/mcp/server.js +104 -11
- package/dist/mcp/tools/asset-tools.js +33 -12
- package/dist/mcp/tools/cloud-tools.js +15 -15
- package/dist/mcp/tools/creator-tools.d.ts +2 -0
- package/dist/mcp/tools/creator-tools.js +105 -0
- package/dist/mcp/tools/debug-tools.js +44 -1
- package/dist/mcp/tools/file-tools.d.ts +2 -0
- package/dist/mcp/tools/file-tools.js +154 -0
- package/dist/mcp/tools/generate-tools.js +159 -11
- package/dist/mcp/tools/project-tools.js +37 -27
- package/dist/mcp/tools/scene-tools.js +106 -29
- package/dist/mcp/tools/visual-tools.js +4 -3
- package/dist/mcp/tools/with-engine.js +4 -4
- package/hooks/session-start.sh +5 -5
- package/package.json +3 -1
- package/references/collaborative-protocol.md +50 -0
- package/references/gd-style.md +121 -0
- package/references/godot-version.md +51 -0
- package/references/mcp-tools-reference.md +199 -0
- package/references/public-surface-language.md +30 -0
- package/references/summer-folder.md +90 -0
- package/references/template-registry.md +73 -0
- package/skills/2d-assets/character-portrait/SKILL.md +17 -12
- package/skills/2d-assets/concept-art/SKILL.md +10 -9
- package/skills/2d-assets/create-asset-sheet/SKILL.md +17 -15
- package/skills/2d-assets/pixel-art/SKILL.md +36 -20
- package/skills/2d-assets/skybox-panorama/SKILL.md +32 -37
- package/skills/2d-assets/sprite-sheet/SKILL.md +40 -35
- package/skills/2d-assets/tileable-texture/SKILL.md +28 -22
- package/skills/2d-assets/ui-graphics/SKILL.md +46 -32
- package/skills/2d-assets/use-widget-asset/SKILL.md +8 -6
- package/skills/3d-assets/character-model/SKILL.md +34 -19
- package/skills/3d-assets/environment-kit/SKILL.md +11 -5
- package/skills/3d-assets/organic-model/SKILL.md +8 -5
- package/skills/3d-assets/prop-model/SKILL.md +9 -3
- package/skills/3d-assets/vehicle-model/SKILL.md +32 -19
- package/skills/README.md +1 -1
- package/skills/ai-and-npcs/design-npc/SKILL.md +31 -13
- package/skills/animation/animation-tree/SKILL.md +39 -15
- package/skills/animation/facial-and-lipsync/SKILL.md +25 -8
- package/skills/animation/generate-motion/SKILL.md +47 -15
- package/skills/animation/procedural-animation/SKILL.md +31 -13
- package/skills/animation/retarget/SKILL.md +127 -79
- package/skills/audio/adaptive-music/SKILL.md +24 -20
- package/skills/audio/ambient-bed/SKILL.md +22 -16
- package/skills/audio/audio-direction/SKILL.md +15 -10
- package/skills/audio/music-track/SKILL.md +18 -12
- package/skills/audio/sound-effect/SKILL.md +17 -12
- package/skills/audio/voice-line/SKILL.md +42 -42
- package/skills/character-controllers/fps-controller/SKILL.md +26 -16
- package/skills/debugging/debug/SKILL.md +74 -20
- package/skills/deployment/export-and-ship/SKILL.md +105 -38
- package/skills/deployment/remote-deploy/SKILL.md +140 -0
- package/skills/gameplay-mechanics/auto-fire-targeting/SKILL.md +26 -1
- package/skills/gameplay-mechanics/design-mechanic/SKILL.md +23 -15
- package/skills/level-design/design-level/SKILL.md +22 -8
- package/skills/level-design/scene-to-level/SKILL.md +13 -7
- package/skills/multiplayer-and-networking/host-authoritative-state/SKILL.md +8 -8
- package/skills/multiplayer-and-networking/peer-to-peer-multiplayer/SKILL.md +2 -7
- package/skills/multiplayer-and-networking/setup-multiplayer/SKILL.md +26 -18
- package/skills/performance/tune-performance/SKILL.md +51 -32
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +34 -5
- package/skills/rendering-and-lighting/art-direction/SKILL.md +6 -8
- package/skills/scene-and-project/brainstorm-game/SKILL.md +7 -9
- package/skills/scene-and-project/make-game/SKILL.md +2 -1
- package/skills/scene-and-project/play/SKILL.md +10 -4
- package/skills/scene-and-project/scene-composition/SKILL.md +21 -8
- package/skills/scene-and-project/summer-cloud/SKILL.md +92 -0
- package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
- package/skills/ui-and-ux/ui-basics/SKILL.md +16 -7
- package/skills/video/animated-loop/SKILL.md +63 -39
- package/skills/video/cinematic-cutscene/SKILL.md +66 -30
- package/skills/video/trailer-shot/SKILL.md +30 -21
- package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +25 -16
- package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +5 -3
- package/skills/visual-effects/game-feel/SKILL.md +51 -33
- package/skills/visual-effects/recipes/dissolve/SKILL.md +51 -9
- package/skills/visual-effects/recipes/fire/SKILL.md +136 -49
- package/skills/visual-effects/recipes/hit-spark/SKILL.md +45 -8
- package/skills/visual-effects/recipes/lightning/SKILL.md +59 -27
- package/skills/visual-effects/recipes/magic-glow/SKILL.md +59 -26
- package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +68 -25
- package/skills/visual-effects/recipes/smoke/SKILL.md +89 -28
- package/skills/visual-effects/recipes/water-ripple/SKILL.md +83 -23
- package/skills/workflow/brainstorming/SKILL.md +1 -1
- package/skills/workflow/debugging-game-feel/SKILL.md +29 -9
- package/skills/workflow/diagnosing-perf-regressions/SKILL.md +46 -21
- package/skills/workflow/gameskill/SKILL.md +11 -2
- package/skills/workflow/headless-scripting/SKILL.md +407 -0
- package/skills/workflow/investigating-bugs/SKILL.md +4 -2
- package/skills/workflow/mcpupdate/SKILL.md +9 -9
- package/skills/workflow/playtesting-a-feature/SKILL.md +94 -21
- package/skills/workflow/skill-create/SKILL.md +7 -7
- package/skills/workflow/skill-test/SKILL.md +3 -3
- package/skills/workflow/using-summer/SKILL.md +32 -3
- package/skills/workflow/verification-before-completion/SKILL.md +2 -0
- package/skills/workflow/writing-plans/SKILL.md +7 -7
- package/skills/workflow/writing-skills/SKILL.md +7 -5
- package/skills/workflow/writing-skills/testing-skills-with-subagents.md +1 -1
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: video
|
|
7
7
|
user-invocable: true
|
|
8
|
-
allowed-tools: Read Grep Glob Write Edit summer_generate_video summer_generate_image summer_generate_audio summer_search_assets summer_import_from_url summer_add_node summer_set_prop
|
|
8
|
+
allowed-tools: Read Grep Glob Write Edit summer_generate_video summer_check_job summer_generate_image summer_generate_audio summer_search_assets summer_import_from_url summer_add_node summer_set_prop
|
|
9
9
|
paths: ["assets/video/**", "cinematics/**", "trailers/**"]
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -38,10 +38,11 @@ If the user wants 5 seconds of marketing footage, that's `video/trailer-shot`. I
|
|
|
38
38
|
|
|
39
39
|
```
|
|
40
40
|
Read .summer/GameSoul.md
|
|
41
|
-
summer_search_assets(query="
|
|
42
|
-
summer_search_assets(query="<character name> reference", filter={ kind: "image" })
|
|
41
|
+
summer_search_assets(query="<character name> reference", assetType="2d_image", source="all")
|
|
43
42
|
```
|
|
44
43
|
|
|
44
|
+
`summer_search_assets` has no video filter — `assetType` is one of `2d_image`, `animation`, `3d_model`, `audio`, `music`, `all`, and there is no video member. To find prior cutscene clips, list your own assets with `summer_list_my_assets(query="cutscene")` and read the titles.
|
|
45
|
+
|
|
45
46
|
If a reference image of the character already exists from a prior `concept-art` or `character-portrait` run, **reuse it** as the `imageUrl` — that single decision is the difference between the character looking like themselves and looking like a stranger.
|
|
46
47
|
|
|
47
48
|
### 2. Plan the shot list
|
|
@@ -58,25 +59,28 @@ For any character or hero scene, generate a reference still with `summer_generat
|
|
|
58
59
|
|
|
59
60
|
```
|
|
60
61
|
summer_generate_image(
|
|
61
|
-
prompt="<subject>, <setting>, cinematic lighting, film still, <art style from GameSoul.md>",
|
|
62
|
-
model="nano-banana-2"
|
|
63
|
-
options={ image_size: "landscape_16_9" }
|
|
62
|
+
prompt="<subject>, <setting>, cinematic lighting, film still, wide 16:9 framing, <art style from GameSoul.md>",
|
|
63
|
+
model="nano-banana-2"
|
|
64
64
|
)
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
`summer_generate_image` has no size or aspect argument — `options.image_size` is dropped without an error and every MCP image comes back at the server's 1:1 default. Ask for the framing in the prompt, or generate the reference in the Summer dashboard (which exposes aspect ratio) and pass its URL. For image-to-video this matters more than usual: the clip's framing is inherited from the reference, so a square reference gives you a square cutscene.
|
|
68
|
+
|
|
67
69
|
Show the user the still and confirm it's the right look before video-ing it. Regenerating a $0.05 still beats regenerating a $0.50 video.
|
|
68
70
|
|
|
69
71
|
### 4. Pick the model
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|---|---|---|---|
|
|
73
|
-
| `ltx` | ~$0.10 | ~30s | Iteration, blocking shots, B-roll, throwaway tests |
|
|
74
|
-
| `kling` | ~$0.50 | 2-4 min | Hero shots, character cutscenes, anything the player will sit and watch |
|
|
75
|
-
| `kling-turbo` | ~$0.30 | 1-2 min | Same as kling when iteration speed matters more than the last 10% of quality |
|
|
76
|
-
| `veo3` | ~$1.00 | 3-5 min | Pitch decks, premium dialogue scenes with synced lip motion, short-form ad |
|
|
77
|
-
| `minimax` | ~$0.40 | 2-3 min | Stylized / anime-leaning content; better at non-photoreal looks than kling |
|
|
73
|
+
**This skill always passes `imageUrl`, which puts every call on the image-to-video route — and that route only accepts three models.** `kling-turbo` and `veo3` are text-to-video only; asking for either with an `imageUrl` set is a 400 `invalid_model`, not a silent downgrade.
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
| Model | i2v? | Cost | Speed | When |
|
|
76
|
+
|---|---|---|---|---|
|
|
77
|
+
| `ltx` | yes | $0.10 | ~30s | Iteration, blocking shots, B-roll, throwaway tests |
|
|
78
|
+
| `kling` | yes | $0.50 | 2-4 min | Hero shots, character cutscenes, anything the player will sit and watch |
|
|
79
|
+
| `minimax` | yes | $0.25 | 2-3 min | Stylized / anime-leaning content; better at non-photoreal looks than kling |
|
|
80
|
+
| `kling-turbo` | **no** | $0.30 | 1-2 min | Text-to-video only — usable only if you drop the reference image |
|
|
81
|
+
| `veo3` | **no** | $1.00 | 3-5 min | Text-to-video only — usable only if you drop the reference image |
|
|
82
|
+
|
|
83
|
+
Default policy: **`ltx` first** to validate the prompt and shot framing. If it lands the composition but quality is rough, escalate to `kling`. `veo3` is a real tradeoff, not an upgrade: reaching for it means giving up `imageUrl`, which is the one thing that holds character identity across shots. Take that trade only when on-camera lip-sync matters more than continuity, and only with the user's approval on cost.
|
|
80
84
|
|
|
81
85
|
### 5. Generate each shot
|
|
82
86
|
|
|
@@ -90,7 +94,19 @@ summer_generate_video(
|
|
|
90
94
|
)
|
|
91
95
|
```
|
|
92
96
|
|
|
93
|
-
|
|
97
|
+
`duration` accepts **only 5 or 10** — the server coerces anything else to 5. There is no 3s, 4s, 7s or 8s clip.
|
|
98
|
+
|
|
99
|
+
Video generation is **asynchronous**. The call returns immediately with `{ success, queued: true, jobId, model, resolvedModel, estimatedCost, duration }` and **no `fileUrl`** — the clip is rendered by a background worker. Poll for it:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
summer_check_job(jobId="<jobId from the generate call>")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Only once the job reports `completed` do you have an asset and a URL. Do not tell the user a shot is done off the back of the generate call — at that moment nothing has rendered yet.
|
|
106
|
+
|
|
107
|
+
`aspectRatio` is applied on the text-to-video path only; on image-to-video the framing comes from the reference image, so a `9:16` cutscene needs a `9:16` reference, not a `9:16` argument.
|
|
108
|
+
|
|
109
|
+
When the job completes, show the user the URL and ask:
|
|
94
110
|
|
|
95
111
|
> Shot 1 of 3 done. Land or regenerate? If land, I'll move to shot 2.
|
|
96
112
|
|
|
@@ -110,20 +126,37 @@ Lip-sync caveat: if the video shows the character clearly mouthing words and the
|
|
|
110
126
|
|
|
111
127
|
### 7. Import and wire as a VideoStreamPlayer
|
|
112
128
|
|
|
129
|
+
**Transcode to Ogg Theora first.** The generated clip is an `.mp4`, and Summer Engine cannot load `.mp4` — the only video container in the build is `.ogv`. Measured against the shipped binary (4.6.1):
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
$ Summer --headless --path <proj> -s res://probe.gd
|
|
133
|
+
VideoStream exts: ["ogv", "tres", "res"]
|
|
134
|
+
ERROR: No loader found for resource: res://clip.mp4 (expected type: unknown)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Nothing transcodes for you — `summer_import_from_url` downloads the bytes, runs Godot's import pipeline, and *fails the import* if the file never becomes a loadable resource. Convert with ffmpeg or DaVinci before importing:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
ffmpeg -i intro_shot_01.mp4 -c:v libtheora -q:v 8 -an intro_shot_01.ogv
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Then:
|
|
144
|
+
|
|
113
145
|
```
|
|
114
|
-
summer_import_from_url(url="<
|
|
146
|
+
summer_import_from_url(url="<hosted .ogv url>", path="res://assets/video/cinematics/intro_shot_01.ogv")
|
|
115
147
|
```
|
|
116
148
|
|
|
117
|
-
Build a controller scene at `cinematics/Intro.tscn`:
|
|
149
|
+
Build a controller scene at `res://cinematics/Intro.tscn`. Every scene-mutating tool takes an explicit `scenePath`, and `summer_set_prop`'s property argument is named `key`, not `property`:
|
|
118
150
|
|
|
119
151
|
```
|
|
120
|
-
|
|
121
|
-
summer_add_node(
|
|
122
|
-
summer_add_node(
|
|
123
|
-
summer_set_prop(path="./
|
|
124
|
-
summer_set_prop(path="./
|
|
125
|
-
summer_set_prop(path="./
|
|
126
|
-
summer_set_prop(path="./
|
|
152
|
+
summer_create_scene(path="res://cinematics/Intro.tscn", rootName="Intro", allow_temporary_scene_mutation=true)
|
|
153
|
+
summer_add_node(scenePath="res://cinematics/Intro.tscn", parent=".", type="ColorRect", name="Fade") # black, alpha 1.0 → 0.0
|
|
154
|
+
summer_add_node(scenePath="res://cinematics/Intro.tscn", parent=".", type="VideoStreamPlayer", name="Video")
|
|
155
|
+
summer_set_prop(scenePath="res://cinematics/Intro.tscn", path="./Video", key="stream", value="res://assets/video/cinematics/intro_shot_01.ogv")
|
|
156
|
+
summer_set_prop(scenePath="res://cinematics/Intro.tscn", path="./Video", key="autoplay", value=true)
|
|
157
|
+
summer_set_prop(scenePath="res://cinematics/Intro.tscn", path="./Video", key="expand", value=true)
|
|
158
|
+
summer_set_prop(scenePath="res://cinematics/Intro.tscn", path="./Fade", key="anchors_preset", value=15)
|
|
159
|
+
summer_save_scene(scenePath="res://cinematics/Intro.tscn")
|
|
127
160
|
```
|
|
128
161
|
|
|
129
162
|
Attach a `Tween` script that fades the `ColorRect` from black to clear over 0.5s on `_ready`, then back to black when `Video.finished` fires, then `queue_free()`s the scene. For multi-shot cutscenes, queue the next `VideoStreamPlayer` in the `finished` signal handler.
|
|
@@ -139,11 +172,11 @@ Pattern: `<subject> + <action> + <camera move> + <lighting> + <stylistic anchor>
|
|
|
139
172
|
| Opening establishing shot | `kling` | `wide shot of a fog-shrouded medieval village at dawn, slow dolly-in toward the church spire, warm low sun, cinematic, anamorphic lens flare` | $0.50 | 5s |
|
|
140
173
|
| Character intro (hero turns to camera) | `kling` | `young witch with raven on shoulder turns slowly toward camera, candlelit interior, shallow depth of field, cinematic film still` | $0.50 | 5s |
|
|
141
174
|
| Dialogue close-up (no synced lips) | `kling` | `close-up of a grizzled knight, eyes downcast then looking up, firelight on his face, dust motes, 16mm film grain` | $0.50 | 5s |
|
|
142
|
-
| Dialogue close-up (synced lips) | `veo3` | `close-up of the witch saying "they will come for you at dawn", candlelight, cinematic, shallow DOF` | $1.00 | 5s |
|
|
175
|
+
| Dialogue close-up (synced lips) | `veo3` — text-to-video only, drop `imageUrl` | `close-up of the witch saying "they will come for you at dawn", candlelight, cinematic, shallow DOF` | $1.00 | 5s |
|
|
143
176
|
| Action beat (village burns) | `kling` | `medium wide of a thatched village engulfed in flames at night, embers rising, silhouettes running through smoke, hand-held camera, cinematic` | $0.50 | 5s |
|
|
144
177
|
| Ending shot (hero walks away) | `kling` | `low wide shot of a cloaked figure walking away across a blasted plain at sunset, slow truck-back, golden hour, dust on the wind` | $0.50 | 5s |
|
|
145
178
|
| Throwaway iteration / blocking | `ltx` | same prompt as above | $0.10 | 5s |
|
|
146
|
-
| Anime / stylized cutscene | `minimax` | `anime-style young swordsman draws blade and steps forward, sakura petals, dramatic wind, Studio Ghibli soft painterly` | $0.
|
|
179
|
+
| Anime / stylized cutscene | `minimax` | `anime-style young swordsman draws blade and steps forward, sakura petals, dramatic wind, Studio Ghibli soft painterly` | $0.25 | 5s |
|
|
147
180
|
|
|
148
181
|
### Bad prompts and why
|
|
149
182
|
|
|
@@ -162,11 +195,14 @@ Pattern: `<subject> + <action> + <camera move> + <lighting> + <stylistic anchor>
|
|
|
162
195
|
- **Asking the video model to render dialogue without `veo3`.** `kling` and `ltx` will animate mouths but the motion does not match any audio. Use `veo3` if dialogue is on-camera, or keep the camera off the speaker.
|
|
163
196
|
- **Using `kling` for blocking iterations.** Burn $0.10 on `ltx` to validate framing and prompt; only spend $0.50 once the composition lands.
|
|
164
197
|
- **Putting the cutscene on a `VideoStreamPlayer` without a fade.** Cuts straight from gameplay to video are jarring. Always wrap in a `ColorRect` fade in/out.
|
|
165
|
-
- **
|
|
198
|
+
- **Treating `summer_generate_video` as synchronous.** It returns `{ queued: true, jobId }` and no URL. You must poll `summer_check_job` before there is anything to show or import.
|
|
199
|
+
- **Importing the `.mp4` as-is.** The engine has no MP4 or WebM loader — only Ogg Theora (`.ogv`). Transcode first; an un-transcoded import fails and is rolled back.
|
|
200
|
+
- **Asking for `duration=3` or `duration=8`.** Only 5 and 10 exist; anything else is silently coerced to 5.
|
|
201
|
+
- **Pairing `imageUrl` with `kling-turbo` or `veo3`.** Neither has an image-to-video endpoint — that combination is a 400.
|
|
166
202
|
|
|
167
203
|
## Edge cases
|
|
168
204
|
|
|
169
|
-
- **Vertical cutscene for a mobile target.**
|
|
205
|
+
- **Vertical cutscene for a mobile target.** On the image-to-video path `aspectRatio` is not applied at all — the clip inherits the reference image's framing. So the reference *must* be 9:16, and MCP image generation cannot produce that: make it in the Summer dashboard, or crop a square generation to 9:16, then pass its URL as `imageUrl`.
|
|
170
206
|
- **Cutscene must match an in-engine character precisely.** No video model will hit pixel-perfect identity. Either (a) accept the artistic license, (b) render the cutscene in-engine with `AnimationPlayer` instead of generating it, or (c) generate a reference image *from* a screenshot of the in-engine character (image-to-image first, then image-to-video).
|
|
171
207
|
- **Dialogue is too long for a 5s shot.** Either trim the line, or split: 5s of speaker, 5s of listener reaction (cheaper because the listener doesn't need synced lips).
|
|
172
208
|
- **Cutscene needs to play and the player isn't looking.** Pause the gameplay timer, push a `Control` overlay with the `VideoStreamPlayer`, restore on finish.
|
|
@@ -179,7 +215,7 @@ If the Studio MCP server isn't running, the user can do all of this through the
|
|
|
179
215
|
1. Generate a reference image in the Image tab.
|
|
180
216
|
2. Open the Video tab, paste the reference URL into the image-to-video field.
|
|
181
217
|
3. Set model, duration, aspect ratio, and prompt as listed above.
|
|
182
|
-
4. Download the `.mp4` and drop
|
|
218
|
+
4. Download the `.mp4`, transcode it to Ogg Theora (`ffmpeg -i in.mp4 -c:v libtheora -q:v 8 -an out.ogv`), and drop the `.ogv` into `assets/video/cinematics/`. Summer Engine has no MP4 or WebM loader — `.ogv` is the only video container it can open.
|
|
183
219
|
|
|
184
220
|
Print the exact prompt + model + duration + aspect ratio so the user can paste it into the dashboard verbatim.
|
|
185
221
|
|
|
@@ -201,4 +237,4 @@ Once the cutscene is generated and wired:
|
|
|
201
237
|
- `audio/music-track` — score the cutscene.
|
|
202
238
|
- `2d-assets/concept-art` — generate the reference image axis if no character reference exists yet.
|
|
203
239
|
- `2d-assets/character-portrait` — produce a high-fidelity locked character portrait for use as `imageUrl`.
|
|
204
|
-
-
|
|
240
|
+
- `../../../references/mcp-tools-reference.md` — `summer_generate_video` parameter schema and error codes.
|
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: video
|
|
7
7
|
user-invocable: true
|
|
8
|
-
allowed-tools: Read Grep Glob Write Edit summer_generate_video summer_generate_image summer_search_assets summer_import_from_url summer_add_node summer_set_prop
|
|
8
|
+
allowed-tools: Read Grep Glob Write Edit summer_generate_video summer_check_job summer_generate_image summer_search_assets summer_import_from_url summer_add_node summer_set_prop
|
|
9
9
|
paths: ["assets/video/**", "trailers/**", "marketing/**"]
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -56,23 +56,26 @@ For shots featuring a specific character, weapon, or environment, generate a ref
|
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
summer_generate_image(
|
|
59
|
-
prompt="<subject>, <archetype-driven framing>, cinematic, dramatic lighting, film still",
|
|
60
|
-
model="nano-banana-2"
|
|
61
|
-
options={ image_size: "landscape_16_9" }
|
|
59
|
+
prompt="<subject>, <archetype-driven framing>, cinematic, dramatic lighting, film still, wide 16:9 framing",
|
|
60
|
+
model="nano-banana-2"
|
|
62
61
|
)
|
|
63
62
|
```
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
`summer_generate_image` has no size or aspect argument — `options.image_size` is dropped without an error and every MCP image comes back at the server's 1:1 default. Ask for the framing in the prompt, or build the reference in the Summer dashboard (which exposes aspect ratio) and pass its URL. Since image-to-video inherits the reference's framing, a square reference gives you a square trailer shot.
|
|
65
|
+
|
|
66
|
+
For pure environment / abstract / VFX shots, you can skip this and prompt text-to-video directly — that also unlocks `aspectRatio`, `kling-turbo`, and `veo3`.
|
|
66
67
|
|
|
67
68
|
### 3. Pick the model
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
|
72
|
-
|
|
73
|
-
| `
|
|
74
|
-
| `ltx` |
|
|
75
|
-
| `minimax` |
|
|
70
|
+
The available models depend on whether you pass `imageUrl`. With a reference image (step 2) the call goes to the image-to-video route, which accepts only `ltx`, `kling`, and `minimax`; `kling-turbo` and `veo3` exist on the text-to-video route only, and pairing either with an `imageUrl` is a 400 `invalid_model`.
|
|
71
|
+
|
|
72
|
+
| Model | Text-to-video | Image-to-video | Cost | Speed | When |
|
|
73
|
+
|---|---|---|---|---|---|
|
|
74
|
+
| `kling` | yes | yes | $0.50 | 2-4 min | Default for trailer hero shots — best motion + composition |
|
|
75
|
+
| `ltx` | yes | yes | $0.10 | ~30s | B-roll, throwaway tests, blocking the composition before committing |
|
|
76
|
+
| `minimax` | yes | yes | $0.25 | 2-3 min | Anime / stylized trailer looks |
|
|
77
|
+
| `kling-turbo` | yes | **no** | $0.30 | 1-2 min | Same look as kling, faster, slight quality dip — but you lose `imageUrl` |
|
|
78
|
+
| `veo3` | yes | **no** | $1.00 | 3-5 min | Pitch deck for investors, the one shot that has to be perfect — but you lose `imageUrl` |
|
|
76
79
|
|
|
77
80
|
Default: **`ltx` first to block the composition, then `kling` for the final**. For the *one* hero shot that drives the Steam page, escalate to `veo3` only if `kling` failed twice.
|
|
78
81
|
|
|
@@ -88,9 +91,11 @@ summer_generate_video(
|
|
|
88
91
|
)
|
|
89
92
|
```
|
|
90
93
|
|
|
91
|
-
|
|
94
|
+
`duration` accepts **only 5 or 10** — anything else is coerced to 5.
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
The call is **asynchronous**: it returns `{ success, queued: true, jobId, model, resolvedModel, estimatedCost, duration }` and **no URL**. Poll `summer_check_job(jobId="<jobId>")` until it reports `completed` before showing the user anything or claiming the shot is done.
|
|
97
|
+
|
|
98
|
+
`aspectRatio` (`16:9`, `9:16`, `1:1`, ...) is applied on the **text-to-video path only**. The moment you pass `imageUrl` it is ignored and the clip inherits the reference image's framing — so vertical social needs a genuinely 9:16 reference, and square needs a square one. MCP image generation is square-only, so build non-square references in the Summer dashboard (which exposes aspect ratio) or crop them before use.
|
|
94
99
|
|
|
95
100
|
### 5. Review against trailer logic
|
|
96
101
|
|
|
@@ -107,10 +112,13 @@ If "regenerate", revise *one* axis (camera move, lighting, or framing) — don't
|
|
|
107
112
|
|
|
108
113
|
### 6. Import for archive (optional)
|
|
109
114
|
|
|
110
|
-
Trailer footage usually lives on the user's local disk and goes straight into the NLE
|
|
115
|
+
Trailer footage usually lives on the user's local disk and goes straight into the NLE, where the generated `.mp4` is exactly what you want.
|
|
116
|
+
|
|
117
|
+
For shots that double as **in-engine** splash content, transcode first — Summer Engine has no MP4 or WebM loader, and `.ogv` (Ogg Theora) is the only video container it can open. `summer_import_from_url` runs Godot's import pipeline and rejects the file if it never becomes a loadable resource, so importing the `.mp4` fails outright rather than half-working.
|
|
111
118
|
|
|
112
119
|
```
|
|
113
|
-
|
|
120
|
+
ffmpeg -i hero_boss_reveal.mp4 -c:v libtheora -q:v 8 -an hero_boss_reveal.ogv
|
|
121
|
+
summer_import_from_url(url="<hosted .ogv url>", path="res://assets/video/trailers/hero_boss_reveal.ogv")
|
|
114
122
|
```
|
|
115
123
|
|
|
116
124
|
For pure trailer use (DaVinci / Premiere), the user can grab the `fileUrl` and download directly.
|
|
@@ -142,7 +150,7 @@ Pattern: `<archetype framing> + <subject> + <action verb> + <camera move> + <lig
|
|
|
142
150
|
| Vertical social hero | `kling` | `vertical close-up of a young witch raising hands, magical wind, hair flowing, candle-warm key, cinematic, framed for 9:16` | $0.50 | 5s |
|
|
143
151
|
| Pitch-deck premium shot | `veo3` | `wide cinematic of a fleet of airships emerging through cloud cover at dawn, slow truck forward, golden god-rays, soaring orchestral cinematic` | $1.00 | 5s |
|
|
144
152
|
| Cheap B-roll iteration | `ltx` | `mid shot of a knight walking through fog, slow truck backward, dawn light, cinematic` | $0.10 | 5s |
|
|
145
|
-
| Anime style hero | `minimax` | `anime-style hero girl draws a katana in slow motion, sakura petals swirling, dramatic side-light, dynamic camera, Ghibli painterly` | $0.
|
|
153
|
+
| Anime style hero | `minimax` | `anime-style hero girl draws a katana in slow motion, sakura petals swirling, dramatic side-light, dynamic camera, Ghibli painterly` | $0.25 | 5s |
|
|
146
154
|
|
|
147
155
|
### Bad prompts and why
|
|
148
156
|
|
|
@@ -160,7 +168,8 @@ Pattern: `<archetype framing> + <subject> + <action verb> + <camera move> + <lig
|
|
|
160
168
|
- **Skipping the reference image for the hero shot.** The boss in the Steam capsule must look like the boss in the game. Always lock identity with `imageUrl`.
|
|
161
169
|
- **Using `veo3` for B-roll.** Burn $0.10 on `ltx` for blocking and B-roll; reserve `veo3` for the one shot that has to be perfect.
|
|
162
170
|
- **Generating shots without composing the trailer first.** Make a 6-shot list before generating shot 1. Otherwise you'll generate shots that don't intercut.
|
|
163
|
-
- **
|
|
171
|
+
- **Assuming `aspectRatio="9:16"` reframed an image-to-video call.** It is ignored whenever `imageUrl` is set — the reference image decides the framing. Pillarboxed 16:9 on TikTok / Reels / Shorts reads as a desktop YouTube embed and gets demoted by the algorithm, so fix the reference, not the argument.
|
|
172
|
+
- **Treating `summer_generate_video` as synchronous.** It returns `{ queued: true, jobId }` and no URL. Poll `summer_check_job` before handing the user a link.
|
|
164
173
|
- **Forgetting that Studio doesn't cut video.** The user has to take the shots into an NLE. Tell them, don't pretend Studio can stitch.
|
|
165
174
|
- **Asking for "the camera does X then Y then Z".** Pick one camera move per shot.
|
|
166
175
|
|
|
@@ -168,7 +177,7 @@ Pattern: `<archetype framing> + <subject> + <action verb> + <camera move> + <lig
|
|
|
168
177
|
|
|
169
178
|
- **Steam capsule animated header (Steam asset).** Steam wants `.webm` at 616x353 or 1920x1080, ≤6s, 30fps, no audio, ≤4MB. Generate at 16:9, transcode in DaVinci, export `.webm` with VP9. The video model gives you the source; format conversion is on you.
|
|
170
179
|
- **Pitch deck for investors.** One shot, `veo3`, money composition (low-angle hero or wide establishing). Worth the $1.00.
|
|
171
|
-
- **Vertical for TikTok / Shorts.**
|
|
180
|
+
- **Vertical for TikTok / Shorts.** The reference image must genuinely be portrait — `aspectRatio` is ignored once `imageUrl` is set. Frame the subject in the upper-middle so titles can sit at the bottom.
|
|
172
181
|
- **Subject is a UGC environment the player built.** Take a screenshot of the in-engine view, run it through `summer_generate_image` as `referenceImageUrl` to "upgrade" the look, then use that as the video reference. The model can stylize a screenshot; it can't invent the user's level.
|
|
173
182
|
- **Logo splash with motion graphics.** Generate a static logo card in `summer_generate_image` (or use the user's existing logo PNG), then prompt video as `static composition of <logo>, only background particles drifting, cinematic, room for title text` — keep the foreground motionless.
|
|
174
183
|
|
|
@@ -178,7 +187,7 @@ If the Studio MCP server isn't running, route the user to the Studio web dashboa
|
|
|
178
187
|
|
|
179
188
|
1. Image tab → generate the reference still.
|
|
180
189
|
2. Video tab → image-to-video with the reference URL, model `kling`, duration 5s, aspect ratio per platform.
|
|
181
|
-
3. Download the `.mp4` directly into the user's editing project (DaVinci / Premiere / CapCut).
|
|
190
|
+
3. Download the `.mp4` directly into the user's editing project (DaVinci / Premiere / CapCut). No transcode needed for an NLE — only in-engine playback requires `.ogv`.
|
|
182
191
|
|
|
183
192
|
Print the exact prompt + model + duration + aspect ratio so the user can paste it into the dashboard verbatim.
|
|
184
193
|
|
|
@@ -200,4 +209,4 @@ Once the shots are generated:
|
|
|
200
209
|
- `audio/music-track` — trailer score.
|
|
201
210
|
- `audio/sound-effect` — cut SFX (whooshes, impacts, stingers).
|
|
202
211
|
- `2d-assets/concept-art` — generate the reference image axis when no asset exists yet.
|
|
203
|
-
-
|
|
212
|
+
- `../../../references/mcp-tools-reference.md` — `summer_generate_video` parameter schema and error codes.
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
# Additive Billboard Particles — Canonical Material Settings
|
|
2
2
|
|
|
3
|
-
Reusable
|
|
3
|
+
Reusable material configuration for additive particle billboards (motes, sparks, glow, ash). Used by `magic-glow`, optionally substitutable in `hit-spark` and `fire` if a custom shader is overkill.
|
|
4
|
+
|
|
5
|
+
`BaseMaterial3D` is abstract — `BaseMaterial3D.new()` is a parse error ("Native class
|
|
6
|
+
"BaseMaterial3D" cannot be constructed as it is abstract"). Instantiate
|
|
7
|
+
`StandardMaterial3D`; the `BaseMaterial3D.*` enum constants below are still the right
|
|
8
|
+
way to name the values.
|
|
4
9
|
|
|
5
10
|
## Settings
|
|
6
11
|
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
```gdscript
|
|
13
|
+
var bm := StandardMaterial3D.new()
|
|
14
|
+
bm.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
|
15
|
+
bm.blend_mode = BaseMaterial3D.BLEND_MODE_ADD
|
|
16
|
+
bm.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
17
|
+
bm.billboard_mode = BaseMaterial3D.BILLBOARD_PARTICLES
|
|
18
|
+
bm.emission_enabled = true
|
|
19
|
+
bm.emission_energy_multiplier = 3.0 # 1.0–5.0 typical; bump for HDR bloom
|
|
20
|
+
bm.disable_receive_shadows = true
|
|
21
|
+
bm.shadow_to_opacity = false
|
|
22
|
+
bm.no_depth_test = false # true only if particles must read on TOP of opaque geometry
|
|
23
|
+
bm.billboard_keep_scale = true # BILLBOARD_PARTICLES drops per-particle scale without this
|
|
24
|
+
bm.albedo_color = Color(R, G, B, 1.0)
|
|
25
|
+
bm.emission = Color(R, G, B) # usually same as albedo for single-color motes
|
|
19
26
|
```
|
|
20
27
|
|
|
21
28
|
## When to use this vs a custom shader
|
|
22
29
|
|
|
23
|
-
- **Use this `
|
|
24
|
-
- **
|
|
30
|
+
- **Use this `StandardMaterial3D` config** when the effect is just a tinted soft-circle mote (magic glow, sparkles, dust). Less code, faster iteration, free Godot-managed billboard math.
|
|
31
|
+
- **Per-particle color over age does NOT need a custom shader.** `ParticleProcessMaterial` has `color_ramp`, `color_initial_ramp`, `alpha_curve` and `emission_curve` (all verified present in 4.6) — those drive the particle's `COLOR` from age and feed straight into a plain `StandardMaterial3D`. Reach for a ramp before reaching for a shader.
|
|
32
|
+
- **Use a custom `ShaderMaterial`** when you need per-fragment shape masks (muzzle flash star burst), noise-distorted UVs (fire, smoke), or anything that varies *within* the quad. Those are what `StandardMaterial3D` genuinely can't express.
|
|
33
|
+
- If a custom shader does need the particle age, note that the age lives in `INSTANCE_CUSTOM.y` (normalized by `INSTANCE_CUSTOM.w`, the lifetime), that `INSTANCE_CUSTOM.x` is the rotation angle — not the age — and that `INSTANCE_CUSTOM` is **vertex-stage only**. Pass it to `fragment()` through a `varying`.
|
|
25
34
|
|
|
26
35
|
## Performance note
|
|
27
36
|
|
|
28
|
-
Additive overdraw is fillrate-bound.
|
|
37
|
+
Additive overdraw is fillrate-bound. `draw_pass_1` is a `Mesh`, so the size dial is on the mesh: keep `QuadMesh.size` at or under `Vector2(0.2, 0.2)` for motes/sparks. Larger quads at full additive intensity destroy mobile fillrate budgets fast.
|
|
@@ -22,8 +22,7 @@ func _process(delta: float) -> void:
|
|
|
22
22
|
if camera == null:
|
|
23
23
|
return
|
|
24
24
|
if trauma > 0.0:
|
|
25
|
-
var s
|
|
26
|
-
var t = Time.get_ticks_msec() * 0.01
|
|
25
|
+
var s := trauma * trauma # perceived intensity grows quadratically
|
|
27
26
|
camera.h_offset = max_offset.x * s * (randf() * 2.0 - 1.0)
|
|
28
27
|
camera.v_offset = max_offset.y * s * (randf() * 2.0 - 1.0)
|
|
29
28
|
camera.rotation.x += max_pitch * s * (randf() * 2.0 - 1.0) * 0.1
|
|
@@ -37,7 +36,10 @@ func add_trauma(amount: float) -> void:
|
|
|
37
36
|
trauma = clamp(trauma + amount, 0.0, 1.0)
|
|
38
37
|
```
|
|
39
38
|
|
|
40
|
-
Register `CameraShake` as autoload in Project Settings.
|
|
39
|
+
Register `CameraShake` as autoload in Project Settings. An autoload is a node at
|
|
40
|
+
`/root/CameraShake`, not an engine singleton — reach it with
|
|
41
|
+
`get_node_or_null("/root/CameraShake")`. `Engine.has_singleton("CameraShake")` is
|
|
42
|
+
always `false` for an autoload (measured), so never gate the call on it.
|
|
41
43
|
|
|
42
44
|
## Usage
|
|
43
45
|
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: game-feel
|
|
3
|
-
description: Use when
|
|
3
|
+
description: Use when a Summer game "feels flat", "lacks impact", "needs juice", or "needs punch", or the user asks for hit feedback, screen shake, camera shake, audio ducking, or general game feel. Walks through Summer Engine's hit-flash, trauma camera shake, and audio-ducking stack, wired so one hit fires all three. Trigger on "vfx", "juice", "punch", "feels flat", "game feel", "hit flash", "screen shake", "camera shake", "ducking".
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: visual-effects
|
|
7
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
|
|
8
|
+
allowed-tools: Read Grep Edit Write summer_write_file summer_read_file summer_get_scene_tree summer_inspect_node summer_inspect_resource summer_add_node summer_set_prop summer_set_resource_property summer_connect_signal summer_project_setting summer_save_scene summer_get_script_errors summer_get_debugger_errors summer_play summer_stop
|
|
9
9
|
paths: ["**/*.gd", "**/*.tscn", "**/*.tres"]
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# /vfx — The Trio That Makes Games Feel Punchy
|
|
13
13
|
|
|
14
|
-
Particles
|
|
14
|
+
Particles do not make a game feel good. Screen shake alone does not either.
|
|
15
|
+
What makes a hit land is three systems firing on the same frame: a sub-frame
|
|
16
|
+
**hit flash** on the body that got hit, **trauma-based camera shake** with
|
|
17
|
+
quadratic falloff so big hits saturate, and **audio ducking** that briefly
|
|
18
|
+
squashes Music/Ambient so the impact SFX punches through. This skill installs
|
|
19
|
+
the canonical Summer Engine stack as three small systems wired to one signal.
|
|
15
20
|
|
|
16
21
|
## Step 1 — Ask what feels flat
|
|
17
22
|
|
|
@@ -62,13 +67,15 @@ World/
|
|
|
62
67
|
HitFlash (Node) # holds the script, no transform
|
|
63
68
|
```
|
|
64
69
|
|
|
65
|
-
**MCP path
|
|
70
|
+
**MCP path** (every scene-mutating call takes an explicit `scenePath`):
|
|
66
71
|
|
|
67
72
|
```
|
|
68
|
-
summer_add_node(parent="./World/Enemy", type="Node", name="HitFlash")
|
|
73
|
+
summer_add_node(scenePath="res://levels/world.tscn", parent="./World/Enemy", type="Node", name="HitFlash")
|
|
74
|
+
summer_set_prop(scenePath="res://levels/world.tscn", path="./World/Enemy/HitFlash", key="script", value="res://scripts/vfx/hit_flash.gd")
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
Then write `scripts/vfx/hit_flash.gd
|
|
77
|
+
Then write `scripts/vfx/hit_flash.gd` (via `summer_write_file`, which requires exactly
|
|
78
|
+
one of `create_only` or `expected_sha256`):
|
|
72
79
|
|
|
73
80
|
```gdscript
|
|
74
81
|
class_name HitFlash
|
|
@@ -110,7 +117,7 @@ func flash() -> void:
|
|
|
110
117
|
|
|
111
118
|
**Tunable knobs:** `duration` 0.06–0.12s — under 0.06 reads as a flicker, over 0.12 looks slow. `emission_energy_multiplier` 1.5–3.0.
|
|
112
119
|
|
|
113
|
-
> CRITICAL: do NOT inline a `StandardMaterial3D` as a `sub_resource` via `summer_set_prop`. Build it in script (as above) or save it to `materials/flash.tres`. Inline sub_resources break `summer_set_resource_property` silently — see
|
|
120
|
+
> CRITICAL: do NOT inline a `StandardMaterial3D` as a `sub_resource` via `summer_set_prop`. Build it in script (as above) or save it to `materials/flash.tres`. Inline sub_resources break `summer_set_resource_property` silently — see `../../../references/mcp-tools-reference.md` § "Trap".
|
|
114
121
|
|
|
115
122
|
## Step 5 — Install Section 2 (Trauma Camera Shake)
|
|
116
123
|
|
|
@@ -121,8 +128,8 @@ func flash() -> void:
|
|
|
121
128
|
**Node tree:** the script attaches to the existing `./World/Player/Camera3D`. No new nodes.
|
|
122
129
|
|
|
123
130
|
```
|
|
124
|
-
summer_inspect_node
|
|
125
|
-
|
|
131
|
+
summer_inspect_node(path="./World/Player/Camera3D")
|
|
132
|
+
summer_set_prop(scenePath="res://levels/world.tscn", path="./World/Player/Camera3D", key="script", value="res://scripts/vfx/camera_shake.gd")
|
|
126
133
|
```
|
|
127
134
|
|
|
128
135
|
`scripts/vfx/camera_shake.gd`:
|
|
@@ -138,6 +145,11 @@ extends Camera3D
|
|
|
138
145
|
var _trauma: float = 0.0
|
|
139
146
|
var _shake_offset: Vector3 = Vector3.ZERO
|
|
140
147
|
|
|
148
|
+
func _ready() -> void:
|
|
149
|
+
# Node has no `groups` property, so there is nothing to set from the outside.
|
|
150
|
+
# Joining the group here is how any actor finds this camera later.
|
|
151
|
+
add_to_group(&"player_camera")
|
|
152
|
+
|
|
141
153
|
func add_trauma(amount: float) -> void:
|
|
142
154
|
_trauma = clamp(_trauma + amount, 0.0, 1.0)
|
|
143
155
|
|
|
@@ -236,12 +248,9 @@ func duck(amount: float, duration: float = 0.5) -> void:
|
|
|
236
248
|
var drop_db := -24.0 * amount * weight
|
|
237
249
|
var target_db := base_db + drop_db
|
|
238
250
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
# NOTE: AudioServer doesn't expose bus volume as an animatable
|
|
243
|
-
# property — use a method tween instead. See actual call below.
|
|
244
|
-
# (The simpler, real implementation:)
|
|
251
|
+
# AudioServer exposes bus volume through a method, not an animatable
|
|
252
|
+
# property, so tween_method is the only form that works here.
|
|
253
|
+
# `tween_property(AudioServer, "bus_volume_db", ...)` errors at runtime.
|
|
245
254
|
_tween.tween_method(_set_bus_db.bind(idx), base_db, target_db, attack)\
|
|
246
255
|
.set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
|
247
256
|
_tween.tween_method(_set_bus_db.bind(idx), target_db, base_db, release)\
|
|
@@ -255,9 +264,12 @@ func _set_bus_db(idx: int, db: float) -> void:
|
|
|
255
264
|
Register it as an autoload:
|
|
256
265
|
|
|
257
266
|
```
|
|
258
|
-
|
|
267
|
+
summer_project_setting(...) # autoload/AudioDucker = "*res://scripts/vfx/audio_ducker.gd"
|
|
259
268
|
```
|
|
260
269
|
|
|
270
|
+
(Equivalently, by hand: Project Settings → Autoload → Add `scripts/vfx/audio_ducker.gd`
|
|
271
|
+
as `AudioDucker`.)
|
|
272
|
+
|
|
261
273
|
**Calling it:**
|
|
262
274
|
|
|
263
275
|
```gdscript
|
|
@@ -290,25 +302,27 @@ func _on_damaged(amount: float) -> void:
|
|
|
290
302
|
# 1. Hit flash on this body.
|
|
291
303
|
_hit_flash.flash()
|
|
292
304
|
# 2. Camera shake on the player's camera, scaled by hit weight.
|
|
293
|
-
|
|
305
|
+
# clampf(), not clamp(): clamp() returns Variant, and inferring a variable from
|
|
306
|
+
# a Variant is an error under Godot's default warning settings.
|
|
307
|
+
var trauma := clampf(0.2 + amount * 0.05, 0.2, 0.9)
|
|
294
308
|
if _player_camera:
|
|
295
309
|
_player_camera.add_trauma(trauma)
|
|
296
310
|
# 3. Audio duck, scaled by hit weight.
|
|
297
|
-
var duck_amount :=
|
|
311
|
+
var duck_amount := clampf(0.3 + amount * 0.04, 0.3, 1.0)
|
|
298
312
|
AudioDucker.duck(duck_amount, 0.45)
|
|
299
313
|
```
|
|
300
314
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
```
|
|
315
|
+
The camera joins `player_camera` from its own `_ready()` (Step 5). `Node` has no
|
|
316
|
+
`groups` property, so `summer_set_prop(key="groups", ...)` cannot do this — and
|
|
317
|
+
`summer_set_prop` only accepts a string, number, or boolean anyway, never an array.
|
|
318
|
+
The two ways that do work are the `add_to_group()` call in `_ready()` or a `groups =
|
|
319
|
+
["player_camera"]` line written into the `.tscn` node header.
|
|
307
320
|
|
|
308
|
-
Or wire the signal explicitly via MCP if you prefer
|
|
321
|
+
Or wire the signal explicitly via MCP if you prefer (`emitter`/`receiver`, not
|
|
322
|
+
`from`/`to`, and `scenePath` is required):
|
|
309
323
|
|
|
310
324
|
```
|
|
311
|
-
summer_connect_signal(
|
|
325
|
+
summer_connect_signal(scenePath="res://levels/world.tscn", emitter="./World/Enemy", signal="damaged", receiver="./World/Enemy/HitFlash", method="flash")
|
|
312
326
|
```
|
|
313
327
|
|
|
314
328
|
## Step 8 — Scaling intensity per hit weight
|
|
@@ -328,10 +342,11 @@ Because trauma is squared inside the camera, the *felt* difference between 0.35
|
|
|
328
342
|
## Step 9 — Verify
|
|
329
343
|
|
|
330
344
|
```
|
|
331
|
-
summer_save_scene
|
|
332
|
-
summer_get_script_errors
|
|
345
|
+
summer_save_scene(scenePath="res://levels/world.tscn")
|
|
346
|
+
summer_get_script_errors # all three scripts parsed?
|
|
333
347
|
summer_play
|
|
334
348
|
# user reproduces a hit
|
|
349
|
+
summer_get_debugger_errors # runtime errors from the tweens / bus lookups
|
|
335
350
|
summer_stop
|
|
336
351
|
```
|
|
337
352
|
|
|
@@ -355,10 +370,12 @@ Tune one knob at a time:
|
|
|
355
370
|
| Equal pitch/yaw shake | `yaw_factor ≤ 0.5` | Eyes are sensitive to vertical motion; equal axes feel mechanical |
|
|
356
371
|
| `Engine.time_scale` for every hit | Reserve hit-stop for big events only (boss hits, deaths) | Time-scale dips on every hit feel laggy, not impactful |
|
|
357
372
|
| Inline `StandardMaterial3D` sub_resource via `summer_set_prop` | Build in script or save standalone `.tres` | Inline sub_resources silently break `summer_set_resource_property` |
|
|
373
|
+
| `summer_set_prop(key="groups", value='["player_camera"]')` | `add_to_group(&"player_camera")` in `_ready()`, or a `groups = [...]` line in the `.tscn` | `Node` has no `groups` property, and `summer_set_prop` takes only string/number/boolean — never an array |
|
|
374
|
+
| `BaseMaterial3D.new()` | `StandardMaterial3D.new()` | `BaseMaterial3D` is abstract; constructing it is a parse error that kills the whole script |
|
|
358
375
|
|
|
359
376
|
## Collaborative protocol
|
|
360
377
|
|
|
361
|
-
This skill writes 3 GDScript files and adds 1 node + 1 autoload entry. Always ask before each section is applied. Group related writes into one ask: "I'm about to add HitFlash + CameraShake + AudioDucker autoload, wire one signal. OK?" See
|
|
378
|
+
This skill writes 3 GDScript files and adds 1 node + 1 autoload entry. Always ask before each section is applied. Group related writes into one ask: "I'm about to add HitFlash + CameraShake + AudioDucker autoload, wire one signal. OK?" See `../../../references/collaborative-protocol.md`.
|
|
362
379
|
|
|
363
380
|
## When NOT to use this skill
|
|
364
381
|
|
|
@@ -369,10 +386,11 @@ This skill writes 3 GDScript files and adds 1 node + 1 autoload entry. Always as
|
|
|
369
386
|
|
|
370
387
|
## See also
|
|
371
388
|
|
|
372
|
-
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
-
|
|
389
|
+
- `../../../references/mcp-tools-reference.md` — full MCP tool list, especially the inline-sub_resource trap
|
|
390
|
+
- `../../../references/godot-version.md` — Summer compatibility and
|
|
391
|
+
version-sensitive API notes
|
|
392
|
+
- `../../../references/collaborative-protocol.md` — "May I write" pattern
|
|
393
|
+
- `../../../references/gd-style.md` — typed GDScript conventions
|
|
376
394
|
- `audio/audio-direction/SKILL.md` — bus layout setup (prerequisite for ducking)
|
|
377
395
|
- `post-processing/screen-shake/SKILL.md` — deeper trauma variants (Perlin noise, stacked sources)
|
|
378
396
|
- `visual-effects/gpuparticles-3d-basics/SKILL.md` — particles to layer on top of the trio
|