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.
Files changed (168) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +4 -1
  3. package/.codex-plugin/plugin.json +6 -2
  4. package/.cursor-plugin/plugin.json +5 -1
  5. package/.opencode/INSTALL.md +1 -1
  6. package/.opencode/plugins/summer.js +2 -2
  7. package/AGENTS.md +11 -7
  8. package/CHANGELOG.md +40 -0
  9. package/GEMINI.md +9 -7
  10. package/README.md +63 -21
  11. package/_persona/summer/SKILL.md +1 -0
  12. package/assets/autopilot/README.md +51 -0
  13. package/assets/autopilot/autopilot.gd +222 -0
  14. package/assets/autopilot/probe_base.gd +262 -0
  15. package/assets/autopilot/run.sh +78 -0
  16. package/commands/gameskill.md +11 -2
  17. package/commands/summer.md +13 -0
  18. package/dist/bin/summer.js +12 -0
  19. package/dist/commands/config.d.ts +2 -0
  20. package/dist/commands/config.js +53 -0
  21. package/dist/commands/create.d.ts +1 -0
  22. package/dist/commands/create.js +38 -6
  23. package/dist/commands/debug.d.ts +2 -0
  24. package/dist/commands/debug.js +44 -0
  25. package/dist/commands/doctor.js +112 -8
  26. package/dist/commands/list.js +1 -1
  27. package/dist/commands/login.d.ts +19 -0
  28. package/dist/commands/login.js +123 -36
  29. package/dist/commands/logout.js +3 -16
  30. package/dist/commands/logs.d.ts +2 -0
  31. package/dist/commands/logs.js +19 -0
  32. package/dist/commands/mcp.js +7 -2
  33. package/dist/commands/open.js +1 -1
  34. package/dist/commands/publish.d.ts +2 -0
  35. package/dist/commands/publish.js +20 -0
  36. package/dist/commands/releases.d.ts +2 -0
  37. package/dist/commands/releases.js +20 -0
  38. package/dist/commands/run.js +1 -1
  39. package/dist/commands/skills.js +1 -1
  40. package/dist/lib/api-client.d.ts +15 -4
  41. package/dist/lib/api-client.js +138 -13
  42. package/dist/lib/async-op-lifecycle.d.ts +7 -2
  43. package/dist/lib/async-op-lifecycle.js +32 -9
  44. package/dist/lib/auth.d.ts +40 -12
  45. package/dist/lib/auth.js +173 -37
  46. package/dist/lib/cloud/engine-bridge.d.ts +17 -4
  47. package/dist/lib/cloud/engine-bridge.js +32 -6
  48. package/dist/lib/config.d.ts +20 -0
  49. package/dist/lib/config.js +142 -0
  50. package/dist/lib/creator.d.ts +93 -0
  51. package/dist/lib/creator.js +393 -0
  52. package/dist/lib/debug-report.d.ts +50 -0
  53. package/dist/lib/debug-report.js +308 -0
  54. package/dist/lib/engine.d.ts +35 -2
  55. package/dist/lib/engine.js +240 -6
  56. package/dist/lib/game-task-plan.js +4 -4
  57. package/dist/lib/mcp-boot-notice.d.ts +3 -0
  58. package/dist/lib/mcp-boot-notice.js +7 -0
  59. package/dist/lib/mcp-log.d.ts +3 -0
  60. package/dist/lib/mcp-log.js +72 -0
  61. package/dist/lib/public-surface-paths.d.ts +13 -0
  62. package/dist/lib/public-surface-paths.js +42 -0
  63. package/dist/lib/skills-registry.d.ts +33 -1
  64. package/dist/lib/skills-registry.js +55 -0
  65. package/dist/lib/store.d.ts +14 -0
  66. package/dist/lib/store.js +145 -0
  67. package/dist/lib/summer-compatibility.d.ts +6 -0
  68. package/dist/lib/summer-compatibility.js +22 -0
  69. package/dist/mcp/server.d.ts +10 -3
  70. package/dist/mcp/server.js +104 -11
  71. package/dist/mcp/tools/asset-tools.js +33 -12
  72. package/dist/mcp/tools/cloud-tools.js +15 -15
  73. package/dist/mcp/tools/creator-tools.d.ts +2 -0
  74. package/dist/mcp/tools/creator-tools.js +105 -0
  75. package/dist/mcp/tools/debug-tools.js +44 -1
  76. package/dist/mcp/tools/file-tools.d.ts +2 -0
  77. package/dist/mcp/tools/file-tools.js +154 -0
  78. package/dist/mcp/tools/generate-tools.js +159 -11
  79. package/dist/mcp/tools/project-tools.js +37 -27
  80. package/dist/mcp/tools/scene-tools.js +106 -29
  81. package/dist/mcp/tools/visual-tools.js +4 -3
  82. package/dist/mcp/tools/with-engine.js +4 -4
  83. package/hooks/session-start.sh +5 -5
  84. package/package.json +3 -1
  85. package/references/collaborative-protocol.md +50 -0
  86. package/references/gd-style.md +121 -0
  87. package/references/godot-version.md +51 -0
  88. package/references/mcp-tools-reference.md +199 -0
  89. package/references/public-surface-language.md +30 -0
  90. package/references/summer-folder.md +90 -0
  91. package/references/template-registry.md +73 -0
  92. package/skills/2d-assets/character-portrait/SKILL.md +17 -12
  93. package/skills/2d-assets/concept-art/SKILL.md +10 -9
  94. package/skills/2d-assets/create-asset-sheet/SKILL.md +17 -15
  95. package/skills/2d-assets/pixel-art/SKILL.md +36 -20
  96. package/skills/2d-assets/skybox-panorama/SKILL.md +32 -37
  97. package/skills/2d-assets/sprite-sheet/SKILL.md +40 -35
  98. package/skills/2d-assets/tileable-texture/SKILL.md +28 -22
  99. package/skills/2d-assets/ui-graphics/SKILL.md +46 -32
  100. package/skills/2d-assets/use-widget-asset/SKILL.md +8 -6
  101. package/skills/3d-assets/character-model/SKILL.md +34 -19
  102. package/skills/3d-assets/environment-kit/SKILL.md +11 -5
  103. package/skills/3d-assets/organic-model/SKILL.md +8 -5
  104. package/skills/3d-assets/prop-model/SKILL.md +9 -3
  105. package/skills/3d-assets/vehicle-model/SKILL.md +32 -19
  106. package/skills/README.md +1 -1
  107. package/skills/ai-and-npcs/design-npc/SKILL.md +31 -13
  108. package/skills/animation/animation-tree/SKILL.md +39 -15
  109. package/skills/animation/facial-and-lipsync/SKILL.md +25 -8
  110. package/skills/animation/generate-motion/SKILL.md +47 -15
  111. package/skills/animation/procedural-animation/SKILL.md +31 -13
  112. package/skills/animation/retarget/SKILL.md +127 -79
  113. package/skills/audio/adaptive-music/SKILL.md +24 -20
  114. package/skills/audio/ambient-bed/SKILL.md +22 -16
  115. package/skills/audio/audio-direction/SKILL.md +15 -10
  116. package/skills/audio/music-track/SKILL.md +18 -12
  117. package/skills/audio/sound-effect/SKILL.md +17 -12
  118. package/skills/audio/voice-line/SKILL.md +42 -42
  119. package/skills/character-controllers/fps-controller/SKILL.md +26 -16
  120. package/skills/debugging/debug/SKILL.md +74 -20
  121. package/skills/deployment/export-and-ship/SKILL.md +105 -38
  122. package/skills/deployment/remote-deploy/SKILL.md +140 -0
  123. package/skills/gameplay-mechanics/auto-fire-targeting/SKILL.md +26 -1
  124. package/skills/gameplay-mechanics/design-mechanic/SKILL.md +23 -15
  125. package/skills/level-design/design-level/SKILL.md +22 -8
  126. package/skills/level-design/scene-to-level/SKILL.md +13 -7
  127. package/skills/multiplayer-and-networking/host-authoritative-state/SKILL.md +8 -8
  128. package/skills/multiplayer-and-networking/peer-to-peer-multiplayer/SKILL.md +2 -7
  129. package/skills/multiplayer-and-networking/setup-multiplayer/SKILL.md +26 -18
  130. package/skills/performance/tune-performance/SKILL.md +51 -32
  131. package/skills/rendering-and-lighting/3d-lighting/SKILL.md +34 -5
  132. package/skills/rendering-and-lighting/art-direction/SKILL.md +6 -8
  133. package/skills/scene-and-project/brainstorm-game/SKILL.md +7 -9
  134. package/skills/scene-and-project/make-game/SKILL.md +2 -1
  135. package/skills/scene-and-project/play/SKILL.md +10 -4
  136. package/skills/scene-and-project/scene-composition/SKILL.md +21 -8
  137. package/skills/scene-and-project/summer-cloud/SKILL.md +92 -0
  138. package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
  139. package/skills/ui-and-ux/ui-basics/SKILL.md +16 -7
  140. package/skills/video/animated-loop/SKILL.md +63 -39
  141. package/skills/video/cinematic-cutscene/SKILL.md +66 -30
  142. package/skills/video/trailer-shot/SKILL.md +30 -21
  143. package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +25 -16
  144. package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +5 -3
  145. package/skills/visual-effects/game-feel/SKILL.md +51 -33
  146. package/skills/visual-effects/recipes/dissolve/SKILL.md +51 -9
  147. package/skills/visual-effects/recipes/fire/SKILL.md +136 -49
  148. package/skills/visual-effects/recipes/hit-spark/SKILL.md +45 -8
  149. package/skills/visual-effects/recipes/lightning/SKILL.md +59 -27
  150. package/skills/visual-effects/recipes/magic-glow/SKILL.md +59 -26
  151. package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +68 -25
  152. package/skills/visual-effects/recipes/smoke/SKILL.md +89 -28
  153. package/skills/visual-effects/recipes/water-ripple/SKILL.md +83 -23
  154. package/skills/workflow/brainstorming/SKILL.md +1 -1
  155. package/skills/workflow/debugging-game-feel/SKILL.md +29 -9
  156. package/skills/workflow/diagnosing-perf-regressions/SKILL.md +46 -21
  157. package/skills/workflow/gameskill/SKILL.md +11 -2
  158. package/skills/workflow/headless-scripting/SKILL.md +407 -0
  159. package/skills/workflow/investigating-bugs/SKILL.md +4 -2
  160. package/skills/workflow/mcpupdate/SKILL.md +9 -9
  161. package/skills/workflow/playtesting-a-feature/SKILL.md +94 -21
  162. package/skills/workflow/skill-create/SKILL.md +7 -7
  163. package/skills/workflow/skill-test/SKILL.md +3 -3
  164. package/skills/workflow/using-summer/SKILL.md +32 -3
  165. package/skills/workflow/verification-before-completion/SKILL.md +2 -0
  166. package/skills/workflow/writing-plans/SKILL.md +7 -7
  167. package/skills/workflow/writing-skills/SKILL.md +7 -5
  168. package/skills/workflow/writing-skills/testing-skills-with-subagents.md +1 -1
@@ -13,7 +13,15 @@ paths: ["assets/**", "art/pixel/**", "sprites/**"]
13
13
 
14
14
  This skill generates pixel-art assets — sprites, items, tiles, icons, portraits — at a target resolution (32×32, 64×64, 128×128, etc.). Pixel art has hard constraints (grid alignment, limited palette, no anti-aliased edges) that diffusion models violate by default. This skill encodes the prompt patterns and post-processing discipline that makes the output actually look like pixel art and not "blurry small image."
15
15
 
16
- **Backing tool:** `summer_generate_image` with `style: "pixel"` and an explicit pixel-art prompt. Pass `options.image_size: "square_hd"` and have the agent enforce pixel-perfect by setting the project's default texture filter to Nearest (and downscaling to the target resolution post-gen). Output is upscaled by the model — you generally request a small generation (or downscale post-gen) to get crisp pixels.
16
+ **Backing tool:** `summer_generate_image` with an explicit pixel-art prompt.
17
+
18
+ Two things about that tool you have to know before writing a call, because both silently do nothing:
19
+
20
+ - **There is no `"pixel"` style preset.** `style` accepts exactly `realistic`, `cartoon`, `anime`, `none`; anything else is coerced to `none`. Only `cartoon` and `anime` do anything at all (they append a short suffix); `realistic` and `none` append nothing. So `style: "pixel"` is identical to `style: "none"` — the pixel look has to come entirely from the prompt. Use `style: "none"` and say so honestly.
21
+ - **`options` is not a general passthrough.** The MCP tool forwards `options` to the server, which only recognizes Nano Banana provider keys: `seed`, `outputFormat`, `safetyTolerance`, `syncMode`, `systemPrompt`, `limitGenerations`, `thinkingLevel`. `image_size` and `negative_prompt` are not among them and are dropped without an error. There is no size or aspect-ratio argument on this tool at all — MCP images come back at the server's 1:1 default. Put framing and exclusions in the prompt text instead.
22
+
23
+ Pixel-perfect output is enforced in Summer Engine with Nearest texture filtering
24
+ and by downscaling to the target resolution after generation.
17
25
 
18
26
  ## When to use
19
27
 
@@ -54,7 +62,7 @@ shading: 3-tone (light, mid, shadow), no gradients, no AA
54
62
  ### 2. Search for existing assets
55
63
 
56
64
  ```
57
- summer_search_assets(query="<subject> pixel", filter={ kind: "image" })
65
+ summer_search_assets(query="<subject> pixel", assetType="2d_image", source="all")
58
66
  ```
59
67
 
60
68
  ### 3. Build the prompt
@@ -71,17 +79,17 @@ The model can't actually generate at 32×32 — it generates at 1024×1024 with
71
79
 
72
80
  ```
73
81
  summer_generate_image(
74
- prompt="pixel art slime monster, 32x32 sprite, PICO-8 palette, hard 1px outline in palette's darkest color, 3-tone shading, no anti-aliasing, no blur, sharp pixel edges, transparent background, front-facing",
82
+ prompt="pixel art slime monster, 32x32 sprite, PICO-8 palette, hard 1px outline in palette's darkest color, 3-tone shading, no anti-aliasing, no blur, sharp pixel edges, front-facing. Not blurry, no smooth gradients, no soft edges, not photorealistic, no 3D render.",
75
83
  model="nano-banana-2",
76
- style="pixel",
77
- options={
78
- image_size: "square_hd",
79
- negative_prompt: "blurry, smooth gradients, anti-aliasing, photorealistic, 3D render, soft edges"
80
- }
84
+ style="none",
85
+ options={ removeBackground: true }
81
86
  )
82
87
  ```
83
88
 
84
- `negative_prompt` is critical for pixel art — without it the model smuggles in soft edges and gradients.
89
+ Two deliberate choices there:
90
+
91
+ - **The negations live in the prompt.** There is no `negative_prompt` argument — putting one in `options` is dropped silently. Diffusion models honor in-prompt negations less reliably than a real negative-prompt field, so state them as plain sentences at the end and expect to regenerate more often than you would on a provider UI that exposes the field.
92
+ - **`options.removeBackground: true` is real** and is the only `options` key in this skill that does anything: it runs a real background-removal pass after generation and returns a PNG with true alpha. Prefer it over asking for "transparent background" in the prompt, which is what makes models paint a literal checkerboard.
85
93
 
86
94
  ### 5. Downscale to target resolution
87
95
 
@@ -89,7 +97,9 @@ The generated image is 1024×1024 pixel-style. To get true crisp pixels at 32×3
89
97
 
90
98
  - Import to the engine, then in the import dock set `Filter: Nearest` (no smoothing).
91
99
  - For a true 32×32 atlas/icon, downscale in an external editor (Aseprite, GIMP "nearest neighbor") to 32×32 before importing. Aseprite's "Sprite > Sprite Size" with Nearest gives the cleanest result.
92
- - In Godot, set `Project Settings → Rendering → Textures → Default Texture Filter: Nearest` if the entire game is pixel-art. This kills bilinear smoothing project-wide.
100
+ - In Summer Engine, set `Project Settings → Rendering → Textures → Default
101
+ Texture Filter: Nearest` if the entire game is pixel art. This disables
102
+ bilinear smoothing project-wide.
93
103
 
94
104
  ### 6. Import and wire
95
105
 
@@ -100,13 +110,16 @@ summer_import_from_url(url="<fileUrl>", path="res://sprites/slime.png")
100
110
  For a `Sprite2D`:
101
111
 
102
112
  ```
103
- summer_set_resource_property(
104
- nodePath="/root/Game/Slime/Sprite2D",
105
- resourceProperty="texture",
113
+ summer_set_prop(
114
+ scenePath="res://main.tscn",
115
+ path="./Slime/Sprite2D",
116
+ key="texture",
106
117
  value="res://sprites/slime.png"
107
118
  )
108
119
  ```
109
120
 
121
+ `texture` is a property **on the node**, so it is `summer_set_prop`. `summer_set_resource_property` is for reaching *inside* a resource the node already holds (mesh size, material albedo) and needs all five of `scenePath`, `nodePath`, `resourceProperty`, `subProperty`, `value` — there is no two-argument form.
122
+
110
123
  Confirm `Filter: Nearest` is set in the import dock OR project-wide.
111
124
 
112
125
  ## Prompt patterns
@@ -126,15 +139,16 @@ Confirm `Filter: Nearest` is set in the import dock OR project-wide.
126
139
  |---|---|
127
140
  | `8-bit sword` | "8-bit" is interpreted loosely. Returns a smooth render of a sword with vague pixel feel. Specify resolution + palette + "no AA" explicitly. |
128
141
  | `pixel art knight, photorealistic` | Conflicting directives. Model averages and gives you neither. |
129
- | `pixel art at 32x32` (no negative_prompt) | Model adds soft edges and gradient shading. Always add negative prompt for AA / blur / gradients. |
142
+ | `pixel art at 32x32` with no negations | Model adds soft edges and gradient shading. Always spell out "no anti-aliasing, no blur, no smooth gradients" in the prompt itself — there is no negative-prompt argument to fall back on. |
130
143
  | `pixel sprite walk cycle` | Walk cycles need consistent frames — single-prompt sprite sheets fail. Route to `summer:2d-assets/sprite-sheet`. |
131
144
  | `cute pixel art` | "Cute" without subject is undefined. Specify what. |
132
145
 
133
146
  ## Anti-patterns
134
147
 
135
148
  - **Skipping the downscale.** The model returns a 1024×1024 pixel-style image. If you import that as a 1024 texture, the "pixels" are actually 32-pixel blocks of soft color. Downscale to true target resolution OR set `Filter: Nearest` so the up-rendering doesn't smooth.
136
- - **No `Filter: Nearest`.** Default Godot texture filtering is bilinear. Pixel art bilinearly filtered looks like garbage. Set it on import or project-wide.
137
- - **No negative prompt.** Without `blurry, anti-aliasing, gradients, soft edges` in the negative, ~50% of generations are off-style.
149
+ - **No `Filter: Nearest`.** The default texture filtering is bilinear. Set
150
+ Nearest on import or project-wide for pixel art.
151
+ - **Reaching for `negative_prompt` or `image_size`.** Neither exists on this tool; both are dropped without an error, so the call looks like it worked and the output is off-style. Negations go in the prompt text; size is fixed.
138
152
  - **Inconsistent palette across the cast.** Pick a named palette (PICO-8, NES, custom hex list) and re-use across every asset in the project. Different palettes = the project doesn't read as one game.
139
153
  - **Generating walk-cycle frames as one image.** Sprite sheets via single-prompt are unreliable. Route to `summer:2d-assets/sprite-sheet`.
140
154
 
@@ -152,13 +166,15 @@ Print the call:
152
166
 
153
167
  ```
154
168
  summer_generate_image(
155
- prompt="<pixel art prompt with full anchor>",
169
+ prompt="<pixel art prompt with full anchor>. Not blurry, no smooth gradients, no anti-aliasing.",
156
170
  model="nano-banana-2",
157
- style="pixel",
158
- options={ image_size: "square_hd", negative_prompt: "blurry, smooth gradients, anti-aliasing" }
171
+ style="none",
172
+ options={ removeBackground: true }
159
173
  )
160
174
  ```
161
175
 
176
+ The Summer dashboard *does* expose size and negative-prompt controls that the MCP tool does not — if the user is running it there, tell them to set square + a real negative prompt.
177
+
162
178
  Tell the user to run via the Summer dashboard, downscale in Aseprite/GIMP to true target resolution with nearest-neighbor, then `summer_import_from_url` (or drop into `res://sprites/`) and set `Filter: Nearest`.
163
179
 
164
180
  If MCP is offline entirely: open Aseprite or Piskel and hand-author the asset. For pixel art at small resolutions, hand-authoring is often faster than fixing a generation.
@@ -177,4 +193,4 @@ After the asset is wired:
177
193
  - `summer:2d-assets/sprite-sheet` — animated pixel frames.
178
194
  - `summer:2d-assets/character-portrait` — high-res counterpart.
179
195
  - `summer:asset-pipeline/asset-strategy` — meta-router.
180
- - `references/mcp-tools-reference.md` — `summer_generate_image` schema.
196
+ - `../../../references/mcp-tools-reference.md` — `summer_generate_image` schema.
@@ -11,7 +11,10 @@ paths: ["assets/**", "art/sky/**", "environments/**"]
11
11
 
12
12
  # skybox-panorama — 360° Sky for WorldEnvironment
13
13
 
14
- This skill generates a single equirectangular panoramic image (2:1 aspect, e.g. 2048×1024 or 4096×2048) suitable for Godot's `PanoramaSkyMaterial`. Wires it into a `Sky` resource on a `WorldEnvironment` node so the sky is visible from every camera angle in your 3D scene.
14
+ This skill generates a single equirectangular panoramic image (2:1 aspect,
15
+ e.g. 2048×1024 or 4096×2048) suitable for Summer Engine's
16
+ `PanoramaSkyMaterial`. It wires the image into a `Sky` resource on a
17
+ `WorldEnvironment` node so the sky is visible from every camera angle.
15
18
 
16
19
  The single biggest failure mode is **non-equirectangular output**. Diffusion models default to flat 2D scenes; if you don't explicitly demand "equirectangular projection," the result looks fine in a thumbnail but distorts brutally when wrapped onto a sphere — horizon bows, zenith pinches, the sun stretches into a smear. This skill encodes the prompt suffix and the import discipline that produces a usable sky on the first or second try.
17
20
 
@@ -35,7 +38,7 @@ The single biggest failure mode is **non-equirectangular output**. Diffusion mod
35
38
  ### 1. Search for an existing sky
36
39
 
37
40
  ```
38
- summer_search_assets(query="<vibe> sky panorama", filter={ kind: "image" })
41
+ summer_search_assets(query="<vibe> sky panorama", assetType="2d_image", source="all")
39
42
  ```
40
43
 
41
44
  Polyhaven (`polyhaven.com/hdris`) hosts hundreds of free CC0 HDRIs that beat AI generation for realism and provide IBL data. For realistic exterior scenes, prefer Polyhaven; for stylized / fantasy / sci-fi, AI generation wins.
@@ -55,22 +58,25 @@ Load-bearing phrases:
55
58
  - **`no foreground objects, no ground horizon line`** — skies show only sky. If you include a horizon, it warps weirdly when sphere-mapped and kills the illusion that the sky is at infinite distance.
56
59
  - **`distortion-correct for sphere mapping`** — reminds the model that the top/bottom of the image map to the zenith/nadir.
57
60
 
58
- ### 3. Generate at 2:1 aspect
61
+ ### 3. Generate, then fix the aspect yourself
62
+
63
+ Equirectangular MUST be 2:1 (width = 2× height). **`summer_generate_image` cannot give you that.** The tool takes only `prompt`, `model`, `style`, `referenceImageUrl`, and `options` — there is no aspect or size argument, so every MCP image comes back at the server's 1:1 default. `aspectRatio` and `image_size` inside `options` are not recognized and are dropped without an error; the underlying provider does support 2:1-class aspect ratios, but nothing on this surface lets you request one.
59
64
 
60
65
  ```
61
66
  summer_generate_image(
62
- prompt="dramatic fantasy sky, golden hour, large purple-orange clouds, distant mountains silhouetted at very bottom, soft god-rays, 360 degree panoramic equirectangular projection, seamless horizontal wrap, no visible seam, no foreground objects, sky only",
67
+ prompt="dramatic fantasy sky, golden hour, large purple-orange clouds, distant mountains silhouetted at very bottom, soft god-rays, 360 degree panoramic equirectangular projection, wide 2:1 panoramic framing, seamless horizontal wrap, no visible seam, no foreground objects, sky only. No vertical seam, no ground objects, no horizon-level detail, not distorted or warped, no characters, no buildings.",
63
68
  model="nano-banana-2",
64
- style="realistic",
65
- options={
66
- aspectRatio: "2:1",
67
- image_size: "landscape_16_9",
68
- negative_prompt: "vertical seam, ground objects, horizon-level details, distorted, warped, characters, buildings"
69
- }
69
+ style="realistic"
70
70
  )
71
71
  ```
72
72
 
73
- `aspectRatio: "2:1"` is critical. Equirectangular MUST be 2:1 (width = 2× height). If the model returns 16:9 or 4:3, the wrap will be wrong.
73
+ Asking for "2:1 panoramic framing" in the prompt biases the composition; it does not change the returned pixel dimensions. So one of these has to happen before the image is usable as a panorama:
74
+
75
+ - **Generate in the Summer dashboard instead**, which does expose aspect ratio, and bring the 2:1 result back with `summer_import_from_url`. This is the right path when the sky matters.
76
+ - **Or crop the 1:1 result to 2:1** in any image editor before importing. You lose the top and bottom, which is usually acceptable for sky-only content — the zenith and nadir are the least informative regions — but it will clip a sun placed high in frame.
77
+ - **Or use a Polyhaven HDRI**, already 2:1 and better for realistic exteriors.
78
+
79
+ Do not import a 1:1 image as a `PanoramaSkyMaterial` panorama and call it done — it wraps with obvious horizontal compression.
74
80
 
75
81
  ### 4. Verify the seam and projection
76
82
 
@@ -97,38 +103,28 @@ In the import dock:
97
103
 
98
104
  ### 6. Wire into WorldEnvironment (3 lines)
99
105
 
100
- ```
101
- summer_add_node(parentPath="/root/Game", type="WorldEnvironment", name="WorldEnvironment")
106
+ This is not three tool calls. `summer_set_resource_property` reaches exactly **one** level into a resource — it takes `scenePath`, `nodePath`, `resourceProperty`, `subProperty`, `value`, and there is no `"a:b:c"` colon-path form for walking Environment → Sky → SkyMaterial. Write the `Environment` (with its `Sky` and `PanoramaSkyMaterial` as sub-resources) as a `.tres`, then attach it in one property set:
102
107
 
103
- summer_set_resource_property(
104
- nodePath="/root/Game/WorldEnvironment",
105
- resourceProperty="environment:background_mode",
106
- value=2 # BG_SKY
108
+ ```
109
+ summer_write_file(
110
+ path="res://environments/fantasy_sunset.tres",
111
+ content="<Environment .tres: background_mode = 2 (BG_SKY), sky = Sky with a PanoramaSkyMaterial whose panorama is res://art/sky/fantasy_sunset.png, ambient_light_source = 3 (AMBIENT_SOURCE_SKY) if you want IBL>",
112
+ create_only=true
107
113
  )
108
114
 
109
- summer_set_resource_property(
110
- nodePath="/root/Game/WorldEnvironment",
111
- resourceProperty="environment:sky:sky_material",
112
- value="<new PanoramaSkyMaterial with panorama: res://art/sky/fantasy_sunset.png>"
113
- )
115
+ summer_add_node(scenePath="res://main.tscn", parent=".", type="WorldEnvironment", name="WorldEnvironment")
116
+ summer_set_prop(scenePath="res://main.tscn", path="./WorldEnvironment", key="environment", value="res://environments/fantasy_sunset.tres")
117
+ summer_save_scene(scenePath="res://main.tscn")
114
118
  ```
115
119
 
116
- Then, if the user wants the sky to also light the scene (image-based lighting):
117
-
118
- ```
119
- summer_set_resource_property(
120
- nodePath="/root/Game/WorldEnvironment",
121
- resourceProperty="environment:ambient_light_source",
122
- value=3 # AMBIENT_SOURCE_SKY
123
- )
124
- ```
120
+ Every scene-mutating tool takes an explicit `scenePath`; node paths are relative to that scene's root (`./`), not absolute `/root/...` runtime paths.
125
121
 
126
122
  Note: AI-generated panoramas are LDR (8-bit per channel). For physically-correct IBL with bright suns, the lighting is muted compared to true HDRI. Mention this to the user if they expect strong IBL.
127
123
 
128
124
  ### 7. Verify in scene
129
125
 
130
126
  ```
131
- summer_inspect_node(path="/root/Game/WorldEnvironment")
127
+ summer_inspect_node(path="WorldEnvironment")
132
128
  ```
133
129
 
134
130
  Then `summer_play` and look around. Sun in the right place? Seam invisible? Top/bottom okay?
@@ -158,7 +154,7 @@ Then `summer_play` and look around. Sun in the right place? Seam invisible? Top/
158
154
  ## Anti-patterns
159
155
 
160
156
  - **Including foreground or horizon.** Mountains, trees, buildings at horizon level warp weirdly when sphere-mapped (the "swimming horizon" effect). Skies show ONLY sky. If the level needs distant mountains, model them as low-poly meshes in the scene, not in the sky texture.
161
- - **Not specifying 2:1 aspect.** A 16:9 panorama wrapped equirectangular has obvious horizontal compression. Always `aspectRatio: "2:1"`.
157
+ - **Assuming `options.aspectRatio` gave you 2:1.** It is silently ignored — the call succeeds and hands you a square image. A 1:1 or 16:9 panorama wrapped equirectangular has obvious horizontal compression. Crop it, or generate in the dashboard where the control exists.
162
158
  - **Tight features at zenith/nadir.** Anything in the top or bottom 10% of the image gets pinched. Bias toward soft, diffuse features there.
163
159
  - **Expecting HDR / IBL quality.** AI panoramas are 8-bit. If the user needs realistic environment lighting from the sky, point them at Polyhaven HDRIs (CC0). AI is for visual sky, not for lighting.
164
160
  - **Forgetting `Repeat: Disabled` on import.** Panoramas wrap once via the material; if `Repeat` is on, you can get duplicate-tile artifacts at the seam.
@@ -180,12 +176,11 @@ Print the call:
180
176
  summer_generate_image(
181
177
  prompt="<sky> 360 degree panoramic equirectangular projection, seamless horizontal wrap, no visible seam, no foreground objects, sky only",
182
178
  model="nano-banana-2",
183
- style="realistic",
184
- options={ aspectRatio: "2:1", negative_prompt: "vertical seam, foreground, distorted, warped, characters, buildings" }
179
+ style="realistic"
185
180
  )
186
181
  ```
187
182
 
188
- User runs via Summer dashboard, then `summer_import_from_url` to `res://art/sky/<name>.png`, sets `Repeat: Disabled`, and wires the WorldEnvironment manually.
183
+ The dashboard is actually the *better* surface for this skill, not just the fallback: it exposes aspect ratio and a real negative prompt, which MCP does not. Tell the user to set 2:1 and a negative of `vertical seam, foreground, distorted, warped, characters, buildings`, then `summer_import_from_url` to `res://art/sky/<name>.png`, set `Repeat: Disabled`, and wire the WorldEnvironment.
189
184
 
190
185
  If MCP is offline entirely: Polyhaven (`polyhaven.com/hdris`) has hundreds of free CC0 HDRIs ready to drop into `PanoramaSkyMaterial`. Often a better choice than AI for realistic exteriors anyway.
191
186
 
@@ -204,4 +199,4 @@ After the sky is wired:
204
199
  - `summer:2d-assets/tileable-texture` — ground/floor counterpart.
205
200
  - `summer:scene-composition` — WorldEnvironment placement and configuration.
206
201
  - `summer:asset-pipeline/asset-strategy` — meta-router.
207
- - `references/mcp-tools-reference.md` — `summer_generate_image` schema.
202
+ - `../../../references/mcp-tools-reference.md` — `summer_generate_image` schema.
@@ -5,7 +5,7 @@ license: MIT
5
5
  compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
6
  category: 2d-assets
7
7
  user-invocable: true
8
- allowed-tools: Read Grep Glob Write Edit summer_generate_image summer_search_assets summer_import_from_url summer_set_resource_property summer_add_node summer_set_prop
8
+ allowed-tools: Read Grep Glob Write Edit summer_generate_image summer_slice_asset_sheet summer_get_studio_workflow summer_search_assets summer_import_from_url summer_import_asset_by_id summer_set_resource_property summer_add_node summer_set_prop
9
9
  paths: ["assets/**", "sprites/**", "art/sprites/**"]
10
10
  ---
11
11
 
@@ -18,10 +18,12 @@ This skill produces a grid of animation frames for a 2D character — walk cycle
18
18
  This skill therefore offers **three paths**, ranked by reliability:
19
19
 
20
20
  1. **Per-frame img2img** (most reliable) — generate the base pose, then generate each subsequent frame via `referenceImageUrl` with a small pose delta. Composite the frames into a sheet externally or wire each as a separate `SpriteFrames` entry.
21
- 2. **Single-call sheet generation** (fast, unreliable) — one prompt asks for the grid. Works ~30% of the time. Worth trying once for short cycles (4 frames or fewer) before falling back to (1).
21
+ 2. **Single-call sheet + auto-slice** (fast; sheet coherence is the gamble, not the cutting) — one prompt asks for the grid, then `summer_slice_asset_sheet` cuts it into individual frame assets server-side. Worth trying once for short cycles (4 frames or fewer) before falling back to (1).
22
22
  3. **Manual authoring** (most reliable, slowest) — hand-author in **Aseprite** or **Piskel**. For pixel art at 32×32, this is often faster than fixing AI generations.
23
23
 
24
- There is no dedicated sprite-sheet generation tool. Recommended path: per-frame `summer_generate_image` with `referenceImageUrl` (img2img) at consistent angle/lighting, OR external tools (Aseprite/Piskel).
24
+ There is no single "generate a sprite sheet" tool, but there **is** a shared two-tool sheet pipeline, and it is the same one Studio's Guided "sprite-sheet" workflow runs: `summer_generate_image` produces one sheet, then `summer_slice_asset_sheet({ assetId })` runs the server-side vision slicer that removes the background, detects each frame's bounding box, crops, and uploads every frame as its own asset. Call `summer_get_studio_workflow({ workflowId: "sprite-sheet" })` for the current ordered recipe and its stated limitations. Only Studio's frame-preview and visual timing-review UI is unreachable from MCP — the generation and the slicing both are reachable.
25
+
26
+ So do not tell the user to cut a generated sheet by hand or in ImageMagick. The cutting is automated; what is unreliable is inter-frame *consistency* inside the generated sheet.
25
27
 
26
28
  ## When to use
27
29
 
@@ -68,33 +70,44 @@ Generate frame 1 (or use existing base). For each subsequent frame, prompt the p
68
70
 
69
71
  ```
70
72
  summer_generate_image(
71
- prompt="goblin warrior, walk cycle frame 2 of 6, right leg forward, slight bob upward, identical character, same costume, same palette, transparent background",
73
+ prompt="goblin warrior, walk cycle frame 2 of 6, right leg forward, slight bob upward, identical character, same costume, same palette. Not a different character, not a different costume, no scene background.",
72
74
  referenceImageUrl="<frame 1 fileUrl>",
73
75
  model="nano-banana-2",
74
76
  style="<same as base>",
75
- options={ image_size: "square_hd", negative_prompt: "different character, different costume, scene background" }
77
+ options={ removeBackground: true }
76
78
  )
77
79
  ```
78
80
 
79
- Repeat for each frame. Save each as `goblin_walk_01.png`, `goblin_walk_02.png`, etc.
81
+ `summer_generate_image` has no `image_size` and no `negative_prompt` — put negations in the prompt text; there is no size argument at all. `options.removeBackground: true` is real and gives you true alpha instead of a prompted "transparent background" the model may paint as a literal checkerboard. `referenceImageUrl` only works on edit-capable models (`nano-banana-2`, `seedream-5-pro`, `nano-banana-lite`, `gpt-image-2`, `gemini-flash`, `flux-2`); `grok-imagine` has no edit endpoint and returns `edit_not_supported`.
80
82
 
81
- After all frames return, either:
83
+ Repeat for each frame. Save each as `goblin_walk_01.png`, `goblin_walk_02.png`, etc.
82
84
 
83
- - Wire each as a separate frame in a `SpriteFrames` resource (Godot will treat them as a sequence — no need to composite into a single sheet image).
84
- - Composite into a single sheet image via Aseprite (`File → Import Sprite Sheet`) or ImageMagick (`montage frame_*.png -tile 6x1 -geometry +0+0 sheet.png`).
85
+ After all frames return, wire each as a separate frame in a `SpriteFrames`
86
+ resource. Summer Engine treats them as a sequence; there is no need to
87
+ composite them into one sheet image.
85
88
 
86
- ### 3b. Path 2 — Single-call sheet (try once)
89
+ ### 3b. Path 2 — Single-call sheet, then auto-slice
87
90
 
88
91
  ```
89
92
  summer_generate_image(
90
- prompt="goblin warrior walk cycle, sprite sheet, 6 frames in a horizontal row, identical character across frames, side view, transparent background, frames clearly separated, consistent lighting, consistent palette",
93
+ prompt="goblin warrior walk cycle, sprite sheet, 6 frames in a horizontal row, identical character across frames, side view, frames clearly separated with empty space between them, consistent lighting, consistent palette. No scene background, no varying lighting, not a different character per frame.",
91
94
  model="nano-banana-2",
92
- style="pixel",
93
- options={ image_size: "landscape_16_9", negative_prompt: "different character per frame, scene background, varying lighting" }
95
+ style="none",
96
+ options={ removeBackground: true }
94
97
  )
95
98
  ```
96
99
 
97
- Inspect the result. If frames are coherent and the count matches, proceed. If anatomy morphs or count is wrong, fall back to Path 1 or Path 3.
100
+ There is no `"pixel"` style preset (`style` is `realistic | cartoon | anime | none`; anything else is coerced to `none`), no `image_size`, and no `negative_prompt` — the layout and the negations have to be in the prompt.
101
+
102
+ Then cut it with the same server-side slicer Studio uses, passing the asset id the generation returned:
103
+
104
+ ```
105
+ summer_slice_asset_sheet(assetId="<generated sheet assetId>")
106
+ ```
107
+
108
+ It returns the source dimensions plus per-slice URLs, names, categories, and bounding boxes. Import the frames you want by id with `summer_import_asset_by_id`.
109
+
110
+ Inspect the result. If the frames are coherent and the count matches, proceed. If anatomy morphs across the row, or the slicer returns one giant box (items touching / no gaps), fall back to Path 1 or Path 3 — re-prompting with more separation between frames is the first thing to try.
98
111
 
99
112
  ### 3c. Path 3 — Aseprite manual fallback
100
113
 
@@ -104,7 +117,7 @@ Tell the user:
104
117
 
105
118
  If yes, generate the static base via `summer:2d-assets/pixel-art` and stop here. The user takes it to Aseprite.
106
119
 
107
- ### 4. Import frames into Godot
120
+ ### 4. Import frames into Summer Engine
108
121
 
109
122
  For per-frame import (Path 1):
110
123
 
@@ -125,30 +138,21 @@ Set `Filter: Nearest` on import for pixel art, `Linear` for high-res.
125
138
  ### 5. Wire as AnimatedSprite2D
126
139
 
127
140
  ```
128
- summer_add_node(parentPath="/root/Game/Goblin", type="AnimatedSprite2D", name="Sprite")
141
+ summer_add_node(scenePath="res://main.tscn", parent="./Goblin", type="AnimatedSprite2D", name="Sprite")
129
142
  ```
130
143
 
131
- Create a `SpriteFrames` resource and add an animation named `walk`. For per-frame textures:
144
+ Every scene-mutating tool takes an explicit `scenePath`, and node paths are relative to that scene's root (`./`), not absolute `/root/...` runtime paths.
145
+
146
+ Building the `SpriteFrames` itself is **not** an MCP job. `summer_set_resource_property` takes five flat arguments (`scenePath`, `nodePath`, `resourceProperty`, `subProperty`, `value`) and its `value` is restricted to a single string, number, or boolean — it cannot take a frame array, and there is no `"a:b/c"` colon-path form for reaching nested sub-resources. Author the `SpriteFrames` as a `.tres` with `summer_write_file` and then point the node at it:
132
147
 
133
148
  ```
134
- summer_set_resource_property(
135
- nodePath="/root/Game/Goblin/Sprite",
136
- resourceProperty="sprite_frames:animations/walk/frames",
137
- value=["res://sprites/goblin/walk_01.png", "res://sprites/goblin/walk_02.png", ...]
138
- )
139
- summer_set_resource_property(
140
- nodePath="/root/Game/Goblin/Sprite",
141
- resourceProperty="sprite_frames:animations/walk/speed",
142
- value=8.0
143
- )
144
- summer_set_resource_property(
145
- nodePath="/root/Game/Goblin/Sprite",
146
- resourceProperty="sprite_frames:animations/walk/loop",
147
- value=true
148
- )
149
+ summer_write_file(path="res://sprites/goblin/goblin_frames.tres", content="<SpriteFrames .tres with the walk animation, its frames, speed and loop>", create_only=true)
150
+ summer_set_prop(scenePath="res://main.tscn", path="./Goblin/Sprite", key="sprite_frames", value="res://sprites/goblin/goblin_frames.tres")
151
+ summer_set_prop(scenePath="res://main.tscn", path="./Goblin/Sprite", key="animation", value="walk")
152
+ summer_save_scene(scenePath="res://main.tscn")
149
153
  ```
150
154
 
151
- For sheet-based (Path 2): use `AtlasTexture` with one region per frame, then add each AtlasTexture as a frame.
155
+ For sheet-based (Path 2): the slicer already returns individual frame images, so import those and list them as frames. If you would rather keep one packed sheet, declare `AtlasTexture` sub-resources with one region per frame inside the same `.tres`.
152
156
 
153
157
  ### 6. Trigger from code
154
158
 
@@ -198,6 +202,7 @@ func _physics_process(delta):
198
202
  - **Wiring an inconsistent sheet anyway** because you don't want to regenerate. Ship the inconsistency and the player notices the morphing limbs immediately. Cut the frame count or hand-author instead.
199
203
  - **Sprite-sheeting things that don't need to be sprite-sheeted.** UI animation, simple bobs, fades — use `AnimationPlayer` to tween a static texture instead. Sprite sheets are for character animation specifically.
200
204
  - **Pretending Aseprite is a failure.** Hand-authoring 4 pixel-art frames takes 10 minutes and looks better than 8 AI generations. Don't oversell AI here.
205
+ - **Sending the user to ImageMagick or Aseprite to *cut* a generated sheet.** `summer_slice_asset_sheet` does that server-side. Hand off the creative work, not the mechanical work.
201
206
 
202
207
  ## Edge cases
203
208
 
@@ -212,7 +217,7 @@ func _physics_process(delta):
212
217
  Print the per-frame call sequence:
213
218
 
214
219
  ```
215
- Frame 1: summer_generate_image(prompt="<base>", model="nano-banana-2", style="pixel", ...)
220
+ Frame 1: summer_generate_image(prompt="<base>", model="nano-banana-2", style="none", ...)
216
221
  Frame 2: summer_generate_image(prompt="<base + delta>", referenceImageUrl="<frame 1>", ...)
217
222
  Frame 3: summer_generate_image(prompt="<base + delta>", referenceImageUrl="<frame 2>", ...)
218
223
  ...
@@ -236,4 +241,4 @@ After the animation is wired:
236
241
  - `summer:2d-assets/character-portrait` — base portrait for higher-res characters.
237
242
  - `summer:animation/generate-motion` — 3D-skeletal counterpart.
238
243
  - `summer:audio/sound-effect` — frame-synced SFX.
239
- - `references/mcp-tools-reference.md` — `summer_generate_image` schema.
244
+ - `../../../references/mcp-tools-reference.md` — `summer_generate_image` schema.
@@ -35,7 +35,7 @@ The hard part is "seamless." Most diffusion models violate edge continuity by de
35
35
  ### 1. Search for an existing texture
36
36
 
37
37
  ```
38
- summer_search_assets(query="<material> tileable", filter={ kind: "image" })
38
+ summer_search_assets(query="<material> tileable", assetType="2d_image", source="all")
39
39
  ```
40
40
 
41
41
  Texture libraries (AmbientCG, Polyhaven) often have free PBR sets that beat AI generation for realism. If the user wants photorealistic tiling, pause and suggest those.
@@ -60,17 +60,16 @@ The load-bearing phrases are:
60
60
 
61
61
  ```
62
62
  summer_generate_image(
63
- prompt="weathered red brick wall, seamless tileable texture, top-down view, uniform lighting, no perspective, no shadows, no specific objects, square format, photographic detail",
63
+ prompt="weathered red brick wall, seamless tileable texture, top-down view, uniform lighting, no perspective, no shadows, no specific objects, square format, photographic detail. No vanishing point, no directional shadow, no vignette, no single standout feature, no scene context, no sky, no sun.",
64
64
  model="nano-banana-2",
65
- style="realistic",
66
- options={
67
- image_size: "square_hd",
68
- negative_prompt: "perspective, vanishing point, directional shadow, vignette, single feature, scene context, sky, sun"
69
- }
65
+ style="realistic"
70
66
  )
71
67
  ```
72
68
 
73
- `style: "realistic"` is the right default for textures (most are aiming for photographic surface). Switch to `"none"` for stylized/painterly.
69
+ Two things about the arguments:
70
+
71
+ - **There is no `image_size` and no `negative_prompt`.** `summer_generate_image` takes only `prompt`, `model`, `style`, `referenceImageUrl`, and `options`, and `options` only recognizes Nano Banana provider keys (`seed`, `outputFormat`, `safetyTolerance`, `syncMode`, `systemPrompt`, `limitGenerations`, `thinkingLevel`) plus `removeBackground`. Anything else is dropped without an error, so the call looks like it worked. Put the negations in the prompt text. Square is what you get regardless — MCP images come back at the server's 1:1 default, which is exactly what a tileable texture wants.
72
+ - **`style: "realistic"` is a no-op.** Only `cartoon` and `anime` append anything to the prompt; `realistic` and `none` append nothing, and any other value is coerced to `none`. The photographic look has to come from the prompt (`photographic detail`). Switching to `"none"` for stylized work likewise changes nothing on its own — change the prompt.
74
73
 
75
74
  ### 4. Import to project
76
75
 
@@ -97,27 +96,35 @@ If you see hard horizontal/vertical seams, the edges don't match — regenerate
97
96
 
98
97
  **On a PlaneMesh (floor/ceiling):**
99
98
 
99
+ Every scene-mutating tool takes an explicit `scenePath`; node paths are relative to that scene's root (`./`); `summer_set_prop`'s property argument is named `key`; and `summer_set_resource_property` needs all five of `scenePath`, `nodePath`, `resourceProperty`, `subProperty`, `value` (there is no two-argument form and no `"mesh:size"` colon-path form).
100
+
101
+ Assigning a bare class name to a resource property auto-instantiates it, so the mesh comes first:
102
+
100
103
  ```
101
- summer_add_node(parentPath="/root/Level", type="MeshInstance3D", name="Floor")
102
- summer_set_resource_property(nodePath="/root/Level/Floor", resourceProperty="mesh", value="<new PlaneMesh resource>")
103
- summer_set_prop(path="/root/Level/Floor", property="mesh:size", value="Vector2(20, 20)")
104
+ summer_add_node(scenePath="res://levels/level_01.tscn", parent="./Level", type="MeshInstance3D", name="Floor")
105
+ summer_set_prop(scenePath="res://levels/level_01.tscn", path="./Level/Floor", key="mesh", value="PlaneMesh")
106
+ summer_set_resource_property(scenePath="res://levels/level_01.tscn", nodePath="./Level/Floor", resourceProperty="mesh", subProperty="size", value="Vector2(20, 20)")
104
107
  ```
105
108
 
106
- Then create a `StandardMaterial3D`, set `albedo_texture` to the imported texture, and crank `uv1_scale` so each tile covers ~1m of world space:
109
+ Then the material. `material_override` is a `Material`, and `StandardMaterial3D` is the class name that auto-instantiates:
107
110
 
108
111
  ```
112
+ summer_set_prop(scenePath="res://levels/level_01.tscn", path="./Level/Floor", key="material_override", value="StandardMaterial3D")
109
113
  summer_set_resource_property(
110
- nodePath="/root/Level/Floor",
114
+ scenePath="res://levels/level_01.tscn",
115
+ nodePath="./Level/Floor",
111
116
  resourceProperty="material_override",
112
117
  subProperty="albedo_texture",
113
118
  value="res://art/textures/brick_red.png"
114
119
  )
115
120
  summer_set_resource_property(
116
- nodePath="/root/Level/Floor",
121
+ scenePath="res://levels/level_01.tscn",
122
+ nodePath="./Level/Floor",
117
123
  resourceProperty="material_override",
118
124
  subProperty="uv1_scale",
119
125
  value="Vector3(20, 20, 1)"
120
126
  )
127
+ summer_save_scene(scenePath="res://levels/level_01.tscn")
121
128
  ```
122
129
 
123
130
  `uv1_scale = (20, 20, 1)` on a 20m plane means the texture tiles 20× across — each tile covers 1m².
@@ -125,8 +132,8 @@ summer_set_resource_property(
125
132
  **On a CSGBox3D (walls):**
126
133
 
127
134
  ```
128
- summer_add_node(parentPath="/root/Level", type="CSGBox3D", name="WallNorth")
129
- summer_set_prop(path="/root/Level/WallNorth", property="size", value="Vector3(10, 3, 0.3)")
135
+ summer_add_node(scenePath="res://levels/level_01.tscn", parent="./Level", type="CSGBox3D", name="WallNorth")
136
+ summer_set_prop(scenePath="res://levels/level_01.tscn", path="./Level/WallNorth", key="size", value="Vector3(10, 3, 0.3)")
130
137
  ```
131
138
 
132
139
  Then attach the same material with `uv1_scale` tuned to wall dimensions.
@@ -141,7 +148,7 @@ Then attach the same material with `uv1_scale` tuned to wall dimensions.
141
148
  | Stone tiles | `cobblestone path, seamless tileable, top-down, uniform lighting, no shadows, no moss patches, square, photographic` | "No moss patches" kills hotspot |
142
149
  | Metal panel | `industrial metal floor panel, seamless tileable, top-down, uniform lighting, no rust hotspots, no scratches concentrated, square` | Diffuse rust spreads across the tile instead of clumping |
143
150
  | Sand / dirt | `dry desert sand, seamless tileable, top-down view, uniform soft lighting, no footprints, no rocks, no shadows, square` | Negative space is ideal for tiling |
144
- | Stylized painterly grass | `stylized painterly grass, Studio Ghibli, seamless tileable, top-down, uniform lighting, no specific blades emphasized, square` (style: "none") | Style preset would fight the painterly direction |
151
+ | Stylized painterly grass | `stylized painterly grass, Studio Ghibli, seamless tileable, top-down, uniform lighting, no specific blades emphasized, square` | The painterly direction has to be in the prompt; no `style` value produces it |
145
152
  | Sci-fi panel | `sci-fi metal floor panel with subtle glowing seams, seamless tileable, top-down, uniform lighting, square, the glowing seams form a regular grid that aligns with tile edges` | Make the seams part of the design |
146
153
 
147
154
  ### Bad prompts (and why)
@@ -167,7 +174,7 @@ Then attach the same material with `uv1_scale` tuned to wall dimensions.
167
174
 
168
175
  - **User wants normal map / roughness / AO too.** Generation today produces albedo only. Use `Materialize` (free) or `MaterialMaker` (open source) to derive a normal from the albedo. Hand-paint roughness if the surface is heterogeneous (wood = low roughness on knots, high on grain). Set the user's expectation: AI gives albedo; PBR is a follow-up step.
169
176
  - **Texture must tile in only one direction (e.g., a brick wall that runs horizontally but not vertically).** Generate 1024×1024 seamless, then crop to your actual aspect; the horizontal tile remains seamless. Or: prompt `tileable horizontally only, distinct top and bottom edges` for ceiling-to-floor walls.
170
- - **Texture must read at very low resolution (mobile, distant LOD).** Generate at `square_hd`, downscale on import via `Compress: VRAM Compressed`. Avoid generating at low resolution — model quality drops.
177
+ - **Texture must read at very low resolution (mobile, distant LOD).** You cannot request a generation size over MCP anyway — take the default and downscale on import (`Compress: VRAM Compressed`, or set a smaller size in the import dock).
171
178
  - **User wants animated water / lava texture.** Generate a still tileable texture and use a `ShaderMaterial` with UV scrolling to animate. Don't try to generate frames.
172
179
  - **Visible seam after generation.** Run through GIMP `Filters → Map → Make Seamless` or open in Aseprite, set Tiled mode, paint over the seam manually. AI-generated tileables often need a 5-minute touch-up.
173
180
 
@@ -177,10 +184,9 @@ Print the call:
177
184
 
178
185
  ```
179
186
  summer_generate_image(
180
- prompt="<material> seamless tileable texture, top-down view, uniform lighting, no perspective, no shadows, no specific objects, square",
187
+ prompt="<material> seamless tileable texture, top-down view, uniform lighting, no perspective, no shadows, no specific objects, square. No directional shadow, no single standout feature, no scene context.",
181
188
  model="nano-banana-2",
182
- style="realistic",
183
- options={ image_size: "square_hd", negative_prompt: "perspective, directional shadow, single feature, scene context" }
189
+ style="realistic"
184
190
  )
185
191
  ```
186
192
 
@@ -202,4 +208,4 @@ After the texture is wired:
202
208
  - `summer:asset-pipeline/asset-strategy` — meta-router and 3D pipeline.
203
209
  - `summer:2d-assets/skybox-panorama` — sky/environment counterpart.
204
210
  - `summer:scene-composition` — applying textures to CSG and MeshInstance3D.
205
- - `references/mcp-tools-reference.md` — `summer_generate_image` schema.
211
+ - `../../../references/mcp-tools-reference.md` — `summer_generate_image` schema.