summer-engine 4.3.0 → 4.6.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 (231) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +3 -1
  3. package/.codex-plugin/plugin.json +5 -3
  4. package/.cursor-plugin/plugin.json +4 -2
  5. package/.factory-plugin/plugin.json +4 -2
  6. package/AGENTS.md +2 -2
  7. package/CHANGELOG.md +100 -0
  8. package/README.md +67 -27
  9. package/commands/start.md +19 -15
  10. package/commands/summer.md +1 -0
  11. package/dist/cli/command-usage.d.ts +3 -1
  12. package/dist/cli/command-usage.js +10 -4
  13. package/dist/cli/commands/create.d.ts +1 -25
  14. package/dist/cli/commands/create.js +10 -138
  15. package/dist/cli/commands/dev.d.ts +66 -0
  16. package/dist/cli/commands/dev.js +234 -0
  17. package/dist/cli/commands/install.d.ts +15 -58
  18. package/dist/cli/commands/install.js +31 -481
  19. package/dist/cli/commands/login.js +1 -1
  20. package/dist/cli/commands/ops.d.ts +17 -1
  21. package/dist/cli/commands/ops.js +97 -9
  22. package/dist/cli/commands/preview.d.ts +58 -0
  23. package/dist/cli/commands/preview.js +181 -0
  24. package/dist/cli/commands/run.d.ts +1 -17
  25. package/dist/cli/commands/run.js +17 -206
  26. package/dist/cli/commands/setup.js +175 -32
  27. package/dist/cli/index.js +5 -0
  28. package/dist/core/agent-host.d.ts +3 -0
  29. package/dist/core/agent-host.js +1 -1
  30. package/dist/core/api-client.d.ts +10 -2
  31. package/dist/core/api-client.js +13 -8
  32. package/dist/core/capabilities/agent-playbook.js +1 -0
  33. package/dist/core/capabilities/apps.d.ts +9 -9
  34. package/dist/core/capabilities/asset-import.d.ts +4 -1
  35. package/dist/core/capabilities/asset-import.js +15 -6
  36. package/dist/core/capabilities/capture-gameplay.js +1 -1
  37. package/dist/core/capabilities/connect-signal.d.ts +2 -2
  38. package/dist/core/capabilities/content-make/index.d.ts +81 -0
  39. package/dist/core/capabilities/content-make/index.js +706 -0
  40. package/dist/core/capabilities/content-make/media.d.ts +57 -0
  41. package/dist/core/capabilities/content-make/media.js +172 -0
  42. package/dist/core/capabilities/content-make/plan.d.ts +130 -0
  43. package/dist/core/capabilities/content-make/plan.js +433 -0
  44. package/dist/core/capabilities/content-make/render.d.ts +64 -0
  45. package/dist/core/capabilities/content-make/render.js +370 -0
  46. package/dist/core/capabilities/content-make/study.d.ts +13 -0
  47. package/dist/core/capabilities/content-make/study.js +165 -0
  48. package/dist/core/capabilities/content-make/types.d.ts +173 -0
  49. package/dist/core/capabilities/content-make/types.js +6 -0
  50. package/dist/core/capabilities/content-make/voice.d.ts +7 -0
  51. package/dist/core/capabilities/content-make/voice.js +27 -0
  52. package/dist/core/capabilities/events.d.ts +2 -2
  53. package/dist/core/capabilities/export-game.d.ts +4 -1
  54. package/dist/core/capabilities/export-game.js +4 -3
  55. package/dist/core/capabilities/export-presets.d.ts +2 -1
  56. package/dist/core/capabilities/export-presets.js +2 -1
  57. package/dist/core/capabilities/go-live.d.ts +14 -0
  58. package/dist/core/capabilities/go-live.js +408 -0
  59. package/dist/core/capabilities/image-generation.d.ts +6 -6
  60. package/dist/core/capabilities/item-manifest.d.ts +92 -0
  61. package/dist/core/capabilities/item-manifest.js +247 -0
  62. package/dist/core/capabilities/placement.d.ts +7 -7
  63. package/dist/core/capabilities/projects-local.d.ts +68 -0
  64. package/dist/core/capabilities/projects-local.js +172 -0
  65. package/dist/core/capabilities/publish-build.d.ts +13 -2
  66. package/dist/core/capabilities/publish-build.js +87 -21
  67. package/dist/core/capabilities/publish-download.js +1 -1
  68. package/dist/core/capabilities/runtime-control.d.ts +7 -2
  69. package/dist/core/capabilities/runtime-control.js +27 -1
  70. package/dist/core/capabilities/seeing/args.d.ts +2 -2
  71. package/dist/core/capabilities/store-checks.d.ts +45 -0
  72. package/dist/core/capabilities/store-checks.js +85 -0
  73. package/dist/core/capabilities/store-details.d.ts +37 -0
  74. package/dist/core/capabilities/store-details.js +94 -0
  75. package/dist/core/capabilities/summer-bundle.d.ts +21 -2
  76. package/dist/core/capabilities/summer-bundle.js +54 -7
  77. package/dist/core/capabilities/sync-items.d.ts +89 -0
  78. package/dist/core/capabilities/sync-items.js +352 -0
  79. package/dist/core/capabilities/tool-dispatch.js +66 -6
  80. package/dist/core/capabilities/video-ogv.d.ts +49 -0
  81. package/dist/core/capabilities/video-ogv.js +260 -0
  82. package/dist/core/capability-skew.js +2 -2
  83. package/dist/core/cli-usage-beacon.js +26 -2
  84. package/dist/core/cli-usage.d.ts +5 -2
  85. package/dist/core/cli-usage.js +8 -2
  86. package/dist/core/engine-install.d.ts +53 -0
  87. package/dist/core/engine-install.js +93 -0
  88. package/dist/core/engine-installer.d.ts +134 -0
  89. package/dist/core/engine-installer.js +760 -0
  90. package/dist/core/engine-launch.d.ts +126 -0
  91. package/dist/core/engine-launch.js +398 -0
  92. package/dist/core/engine-self-start.d.ts +63 -0
  93. package/dist/core/engine-self-start.js +282 -0
  94. package/dist/core/engine.d.ts +7 -1
  95. package/dist/core/engine.js +9 -2
  96. package/dist/core/error-codes.d.ts +4 -1
  97. package/dist/core/error-codes.js +7 -3
  98. package/dist/core/library-read.d.ts +2 -2
  99. package/dist/core/library-search.d.ts +2 -2
  100. package/dist/core/local-project.d.ts +50 -0
  101. package/dist/core/local-project.js +234 -0
  102. package/dist/core/ops/areas.js +9 -3
  103. package/dist/core/ops/catalog.d.ts +9 -0
  104. package/dist/core/ops/catalog.js +56 -4
  105. package/dist/core/ops/engine-answer.d.ts +4 -1
  106. package/dist/core/ops/engine-answer.js +16 -3
  107. package/dist/core/ops/engine.js +4 -4
  108. package/dist/core/ops/save-files.d.ts +6 -1
  109. package/dist/core/ops/save-files.js +67 -50
  110. package/dist/core/ops/search.js +9 -2
  111. package/dist/core/preview/input.d.ts +35 -0
  112. package/dist/core/preview/input.js +105 -0
  113. package/dist/core/preview/launch-config.d.ts +52 -0
  114. package/dist/core/preview/launch-config.js +137 -0
  115. package/dist/core/preview/page.d.ts +22 -0
  116. package/dist/core/preview/page.js +232 -0
  117. package/dist/core/preview/preview-source.d.ts +179 -0
  118. package/dist/core/preview/preview-source.js +350 -0
  119. package/dist/core/preview/server.d.ts +26 -0
  120. package/dist/core/preview/server.js +218 -0
  121. package/dist/core/telemetry.d.ts +20 -16
  122. package/dist/core/telemetry.js +92 -16
  123. package/dist/core/templates.d.ts +20 -0
  124. package/dist/core/templates.js +300 -3
  125. package/dist/core/tool-profiles.d.ts +2 -2
  126. package/dist/core/tool-profiles.js +1 -0
  127. package/dist/core/usage-fields.d.ts +41 -0
  128. package/dist/core/usage-fields.js +150 -0
  129. package/dist/core/util/sleep.d.ts +3 -0
  130. package/dist/core/util/sleep.js +12 -0
  131. package/dist/installer/agent-config.d.ts +29 -0
  132. package/dist/installer/agent-config.js +75 -11
  133. package/dist/installer/agent-detect.d.ts +44 -0
  134. package/dist/installer/agent-detect.js +166 -0
  135. package/dist/installer/agent-table.d.ts +19 -0
  136. package/dist/installer/agent-table.js +130 -0
  137. package/dist/installer/setup-error.d.ts +19 -0
  138. package/dist/installer/setup-error.js +34 -0
  139. package/dist/installer/version-check.d.ts +5 -0
  140. package/dist/installer/version-check.js +21 -0
  141. package/dist/mcp/ops-surface.d.ts +7 -0
  142. package/dist/mcp/ops-surface.js +40 -3
  143. package/dist/mcp/server.d.ts +14 -4
  144. package/dist/mcp/server.js +42 -8
  145. package/dist/mcp/tool-surface.d.ts +8 -0
  146. package/dist/mcp/tool-surface.js +19 -2
  147. package/dist/mcp/tools/creator-tools.js +92 -14
  148. package/dist/mcp/tools/debug-tools.js +2 -0
  149. package/dist/mcp/tools/local-project-tools.d.ts +6 -0
  150. package/dist/mcp/tools/local-project-tools.js +33 -0
  151. package/dist/mcp/tools/navigation-tools.js +2 -1
  152. package/dist/mcp/tools/project-tools.js +5 -8
  153. package/dist/mcp/tools/seeing-tools.js +1 -1
  154. package/dist/mcp/tools/visual-tools.js +1 -1
  155. package/dist/mcp/tools/with-engine.js +1 -1
  156. package/dist/project-memory/agent-instructions.js +11 -3
  157. package/gemini-extension.json +3 -1
  158. package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -5
  159. package/library/skills/README.md +12 -8
  160. package/library/skills/animated-loop/SKILL.md +10 -16
  161. package/library/skills/cinematic-cutscene/SKILL.md +7 -18
  162. package/library/skills/headless-scripting/SKILL.md +7 -4
  163. package/library/skills/in-game-purchases/SKILL.md +25 -8
  164. package/library/skills/in-game-purchases/resource.yaml +2 -1
  165. package/library/skills/launch-ready/SKILL.md +351 -0
  166. package/library/skills/launch-ready/resource.yaml +45 -0
  167. package/library/skills/make-content/SKILL.md +202 -0
  168. package/library/skills/make-content/resource.yaml +32 -0
  169. package/library/skills/make-game/SKILL.md +6 -4
  170. package/library/skills/make-game/resource.yaml +2 -1
  171. package/library/skills/navigate-summer/SKILL.md +4 -2
  172. package/library/skills/new-project/SKILL.md +15 -22
  173. package/library/skills/new-project/resource.yaml +2 -1
  174. package/library/skills/painted-25d-world/SKILL.md +366 -0
  175. package/library/skills/painted-25d-world/_building-blocks/blender-route.md +33 -0
  176. package/library/skills/painted-25d-world/_building-blocks/blockout_builder.gd +149 -0
  177. package/library/skills/painted-25d-world/_building-blocks/capture_paint_view.gd +32 -0
  178. package/library/skills/painted-25d-world/_building-blocks/paint_projection.gdshader +23 -0
  179. package/library/skills/painted-25d-world/_building-blocks/paintcam_check.gd +25 -0
  180. package/library/skills/painted-25d-world/_building-blocks/painted_door.gd +17 -0
  181. package/library/skills/painted-25d-world/_building-blocks/painted_location.gd +56 -0
  182. package/library/skills/painted-25d-world/_building-blocks/painted_player.gd +125 -0
  183. package/library/skills/painted-25d-world/_building-blocks/painted_world.gd +111 -0
  184. package/library/skills/painted-25d-world/_building-blocks/tools/cam.py +57 -0
  185. package/library/skills/painted-25d-world/_building-blocks/tools/detail4k.py +81 -0
  186. package/library/skills/painted-25d-world/_building-blocks/tools/overlay.py +17 -0
  187. package/library/skills/painted-25d-world/_building-blocks/tools/preview.py +60 -0
  188. package/library/skills/painted-25d-world/resource.yaml +39 -0
  189. package/library/skills/publish-your-game/SKILL.md +13 -14
  190. package/library/skills/publish-your-game/resource.yaml +4 -3
  191. package/library/skills/release-checklist/SKILL.md +188 -0
  192. package/library/skills/release-checklist/resource.yaml +40 -0
  193. package/library/skills/release-readiness/SKILL.md +1 -1
  194. package/library/skills/release-readiness/resource.yaml +1 -1
  195. package/library/skills/store-art/SKILL.md +1 -1
  196. package/library/skills/store-art/resource.yaml +1 -1
  197. package/library/skills/store-listing/SKILL.md +1 -1
  198. package/library/skills/store-listing/resource.yaml +1 -1
  199. package/library/skills/summer-cli/SKILL.md +2 -0
  200. package/library/skills/summer-store/SKILL.md +295 -39
  201. package/library/skills/summer-store/resource.yaml +9 -3
  202. package/library/skills/trailer-shot/SKILL.md +3 -3
  203. package/library/templates/README.md +5 -0
  204. package/library/tools/content-make/resource.yaml +132 -0
  205. package/library/tools/frame-shot/GUIDE.md +1 -1
  206. package/library/tools/go-live/resource.yaml +67 -0
  207. package/library/tools/import-from-url/GUIDE.md +1 -0
  208. package/library/tools/import-from-url-batch/GUIDE.md +1 -1
  209. package/library/tools/play/GUIDE.md +2 -0
  210. package/library/tools/projects-create-local/resource.yaml +55 -0
  211. package/library/tools/projects-open-local/resource.yaml +51 -0
  212. package/library/tools/publish-build/resource.yaml +3 -3
  213. package/library/tools/screenshot/GUIDE.md +1 -1
  214. package/library/tools/store-set-details/resource.yaml +114 -0
  215. package/library/tools/sync-items/resource.yaml +72 -0
  216. package/package.json +1 -1
  217. package/registry/generated/aliases.json +6 -0
  218. package/registry/generated/counts.json +3 -3
  219. package/registry/generated/gemini-extension.json +3 -1
  220. package/registry/generated/index.json +463 -37
  221. package/registry/generated/marketplace.claude.json +1 -1
  222. package/registry/generated/plugin.claude-directory.json +4 -2
  223. package/registry/generated/plugin.claude.json +3 -1
  224. package/registry/generated/plugin.codex.json +5 -3
  225. package/registry/generated/plugin.cursor.json +4 -2
  226. package/registry/generated/plugin.factory.json +4 -2
  227. package/registry/generated/server.json +2 -2
  228. package/registry/generated/skills-index.md +12 -8
  229. package/registry/generated/skills-registry.json +62 -5
  230. package/registry/operations/legacy-names.json +40 -0
  231. package/registry/operations/public-catalog.json +10144 -387
@@ -1,6 +1,6 @@
1
1
  # Summer skills
2
2
 
3
- > 128 skills, grouped by their primary domain. **Generated** by `npm run generate:registry` from each skill's `resource.yaml`; `--check` fails when this file and the library disagree. Do not edit by hand.
3
+ > 132 skills, grouped by their primary domain. **Generated** by `npm run generate:registry` from each skill's `resource.yaml`; `--check` fails when this file and the library disagree. Do not edit by hand.
4
4
 
5
5
  The folder is flat on purpose (`docs/design/DECISIONS.md`, D3): a skill usually belongs to several domains, so categories live in each skill's `facets.domains` and this index is rendered from them. The first domain listed is the primary one. `summer skills list --by-domain` prints the same grouping; `summer skills info <slug>` shows one skill.
6
6
 
@@ -8,7 +8,7 @@ Status: **stable** unless marked; *preview* = not yet exercised in-engine by the
8
8
 
9
9
  ## Domains
10
10
 
11
- - [2d](#2d) (10)
11
+ - [2d](#2d) (11)
12
12
  - [3d](#3d) (6)
13
13
  - [agent-workflow](#agent-workflow) (19)
14
14
  - [ai](#ai) (2)
@@ -16,7 +16,7 @@ Status: **stable** unless marked; *preview* = not yet exercised in-engine by the
16
16
  - [assets](#assets) (4)
17
17
  - [audio](#audio) (6)
18
18
  - [character-controller](#character-controller) (2)
19
- - [creator](#creator) (4)
19
+ - [creator](#creator) (7)
20
20
  - [debug](#debug) (1)
21
21
  - [deployment](#deployment) (3)
22
22
  - [editor](#editor) (1)
@@ -42,6 +42,7 @@ Status: **stable** unless marked; *preview* = not yet exercised in-engine by the
42
42
  | [concept-art](./concept-art/SKILL.md) ★ | Explore art direction with 3-4 rough concept variants of a character, environment or prop. | assets |
43
43
  | [create-asset-sheet](./create-asset-sheet/SKILL.md) | Generate a pack of 2D assets from one prompt (tile sheet, UI kit, character pack, biome), sliced. | assets |
44
44
  | [instantiate-asset-pack](./instantiate-asset-pack/SKILL.md) | Lay out a whole create-asset-sheet pack in the scene: composites, paint order, Sprite2D and NinePatch. | assets |
45
+ | [*painted-25d-world*](./painted-25d-world/SKILL.md) (preview) (library only) | Build a 2D or 2.5D game as a painted world: a 3D blockout under one fixed camera, an AI paint-over projected onto it, sprite characters. | level-design, rendering, assets |
45
46
  | [pixel-art](./pixel-art/SKILL.md) ★ | Generate pixel-art sprites, items, tiles and portraits at a set resolution with a limited palette. | assets |
46
47
  | [skybox-panorama](./skybox-panorama/SKILL.md) | Generate a 360-degree sky panorama and wire it as a PanoramaSkyMaterial Sky resource on WorldEnvironment. | assets |
47
48
  | [sprite-sheet](./sprite-sheet/SKILL.md) | Generate animated 2D character sprite sheets (walk, attack, idle, death) for AnimatedSprite2D. | assets |
@@ -135,9 +136,12 @@ Status: **stable** unless marked; *preview* = not yet exercised in-engine by the
135
136
  | skill | when to use | also |
136
137
  |---|---|---|
137
138
  | [grow-analytics](./grow-analytics/SKILL.md) | Read a creator's Summer Grow numbers (page views, launches, sessions, play time), compare windows. | deployment |
138
- | [publish-your-game](./publish-your-game/SKILL.md) | Publish a game on Summer Games through MCP: store page, art, build upload, submit, owner approval link. | deployment |
139
- | [store-art](./store-art/SKILL.md) | Make Summer Games store art per slot: key art, covers, icons, screenshots, trailer, size and text rules. | assets |
140
- | [store-listing](./store-listing/SKILL.md) | Write a Summer Games store page: title, tagline, descriptions, tags, per platform, and what never to write. | product-language |
139
+ | [*launch-ready*](./launch-ready/SKILL.md) (preview) (library only) | Get a game ready to launch on Summer Games and take it live: upload, real screenshots, store art and listing, gathered and filled in. | deployment, assets |
140
+ | [make-content](./make-content/SKILL.md) | Make a finished, postable video of your game, cut per platform and saved for review. | video |
141
+ | [publish-your-game](./publish-your-game/SKILL.md) | Publish a game on Summer Games over MCP: store page, art, build upload, go live. | deployment |
142
+ | [*release-checklist*](./release-checklist/SKILL.md) (preview) | Pre-launch check for Summer Games: export, upload checks, store art, listing fields. | deployment |
143
+ | [store-art](./store-art/SKILL.md) | Make Summer Games store art per slot: key art, icons, screenshots, trailer, sizes. | assets |
144
+ | [store-listing](./store-listing/SKILL.md) | Write a Summer Games store page: title, tagline, descriptions, tags, what never to write. | product-language |
141
145
 
142
146
  ## debug
143
147
 
@@ -150,7 +154,7 @@ Status: **stable** unless marked; *preview* = not yet exercised in-engine by the
150
154
  | skill | when to use | also |
151
155
  |---|---|---|
152
156
  | [export-and-ship](./export-and-ship/SKILL.md) ★ | Prepare a game export: check templates and targets, validate release assets, build after approval. | project |
153
- | [*release-readiness*](./release-readiness/SKILL.md) (preview) | Before releasing a Summer game version, prove players can play it: server, online join, progress, files. | multiplayer, playtest |
157
+ | [*release-readiness*](./release-readiness/SKILL.md) (preview) | Prove players can play a Summer release: server, online join, progress, files. | multiplayer, playtest |
154
158
  | [remote-deploy](./remote-deploy/SKILL.md) ★ | Run or test the game on a real phone, tablet or computer with Remote Deploy and on-device debugging. | project |
155
159
 
156
160
  ## editor
@@ -195,7 +199,7 @@ Status: **stable** unless marked; *preview* = not yet exercised in-engine by the
195
199
  | [*summer-matchmaking*](./summer-matchmaking/SKILL.md) (preview) | Get players into matches with Summer matchmaking: queues, teams, accept prompts, join progress and failures. | ux |
196
200
  | [*summer-parties*](./summer-parties/SKILL.md) (preview) | Let a Summer party play together: the leader presses Play, members follow into the same match. Hosted only. | ui |
197
201
  | [summer-player-data](./summer-player-data/SKILL.md) | Save a player's progress so it follows them to every match: authority load and commit, autosave, safe retries. | scripting |
198
- | [*summer-store*](./summer-store/SKILL.md) (preview) | Sell Summer items for Sparks in a multiplayer game: shop, checkout, owned items, authority entitlement checks. | gameplay |
202
+ | [*summer-store*](./summer-store/SKILL.md) (preview) | Sell Summer items for Sparks: shop, checkout, item slugs, bundles and sales, owned items, summer.items.json sync, authority checks. | gameplay |
199
203
  | [*summer-world-chat*](./summer-world-chat/SKILL.md) (preview) | Add match chat to a Summer game: one World channel shared by everyone in the match. Hosted only. | ui |
200
204
  | [*summer-world-saves*](./summer-world-saves/SKILL.md) (preview) | Keep a persistent Summer World between restarts: checkpoint saves, restore before join, the final save. | scripting |
201
205
 
@@ -107,23 +107,14 @@ If three regenerations don't seam-close, accept a small crossfade in the engine:
107
107
 
108
108
  ### 6. Import and wire as a looping VideoStreamPlayer
109
109
 
110
- **Transcode to Ogg Theora first.** The generated clip is an `.mp4`, and Summer Engine cannot load `.mp4`. `.ogv` is the only video container in the build — there is no bundled WebM or MP4 plugin, and nothing transcodes on your behalf. Measured against the shipped binary (4.6.1):
110
+ **Import the `.mp4` as it is; the import converts it.** Summer Engine plays video only as Ogg Theora (`.ogv`) — there is no MP4 or WebM loader in the build — so every Summer import tool converts a video on the way in: `summer_import_from_url`, its batch, `summer_import_asset_by_id` and `summer_import_asset`. A clip Summer generated or stores converts on Summer's media host; any other video converts with ffmpeg on this computer when it has Theora, else on summerengine.com. The `.ogv` lands at the path you asked for with the extension swapped, and the answer names it in `videoConversions` and `note`:
111
111
 
112
112
  ```
113
- $ Summer --headless --path <proj> -s res://probe.gd
114
- VideoStream exts: ["ogv", "tres", "res"]
115
- ERROR: No loader found for resource: res://clip.mp4 (expected type: unknown)
113
+ summer_import_asset_by_id(assetId="<the clip's asset id>", path="res://assets/video/loops/title_screen_bg.mp4")
114
+ → importedTo: res://assets/video/loops/title_screen_bg.ogv
116
115
  ```
117
116
 
118
- `summer_import_from_url` downloads the bytes, runs the engine's import pipeline, and *fails the import* if the file never becomes a loadable resource — so importing the `.mp4` does not quietly half-work, it is rejected and rolled back. Convert first:
119
-
120
- ```
121
- ffmpeg -i title_screen_bg.mp4 -c:v libtheora -q:v 8 -an title_screen_bg.ogv
122
- ```
123
-
124
- ```
125
- summer_import_from_url(url="<hosted .ogv url>", path="res://assets/video/loops/title_screen_bg.ogv")
126
- ```
117
+ Load the `.ogv` path from the answer, never the `.mp4`.
127
118
 
128
119
  Then wire it in one script. `scenePath` is the exact scene to change:
129
120
 
@@ -188,11 +179,12 @@ Pattern: `<subject> + <ambient loopable motion> + <constant lighting> + "looping
188
179
  - **Forgetting `loop=true` on the `VideoStreamPlayer`.** The clip will play once and freeze on the last frame.
189
180
  - **Forgetting to mute baked audio.** If audio is on, the loop point becomes audible even if it's invisible.
190
181
  - **Expecting `aspectRatio` to reframe an image-to-video call.** It is applied on the text-to-video path only. A portrait splash needs a portrait *reference image* — the argument does nothing here.
191
- - **Importing the `.mp4` as-is.** `.ogv` is the only video container the engine can load; there is no bundled WebM or MP4 plugin. An un-transcoded import fails and is rolled back.
182
+ - **Loading the `.mp4` path after an import.** The import converted the clip to `.ogv` and saved it under that name; `load()` the `.ogv` path the answer names.
183
+ - **Converting by hand.** The import tools convert; a hand-made ffmpeg command also fails on builds without libtheora (Homebrew's default ffmpeg has none).
192
184
 
193
185
  ## Edge cases
194
186
 
195
- - **Splash loop must be tiny in build size.** Loops compress aggressively because of low motion. Target ≤2MB by exporting at 720p, low bitrate, in DaVinci. Studio's import doesn't re-encode by default.
187
+ - **Splash loop must be tiny in build size.** Loops compress aggressively because of low motion. Target ≤2MB by exporting at 720p, low bitrate, in DaVinci. The import's conversion keeps quality high (Theora at quality 8, at most 1080p), so a small file starts from a 720p clip.
196
188
  - **Mobile portrait splash.** The reference image must be portrait — `aspectRatio` is ignored on the image-to-video path, and MCP image generation is square-only, so make the reference in the Summer dashboard or crop it. Anchors preset 15 still works.
197
189
  - **Loop must sync to a music beat.** The video model doesn't know your BPM. Generate at the duration matching one bar at the menu music tempo (e.g. 120 BPM × 4 beats = 2s, or 8 beats = 4s) and confirm visually.
198
190
  - **Loop is behind translucent UI.** Generate with extra contrast headroom — the model tends toward mid-grey, and translucent UI on mid-grey reads muddy. Push for `high contrast cinematic` in the prompt.
@@ -209,7 +201,7 @@ If the MCP server isn't running, route the user to the Summer dashboard:
209
201
  1. Image tab → generate the reference still (the loop's "neutral frame").
210
202
  2. Video tab → image-to-video with `ltx`, duration 5s, aspect ratio per target.
211
203
  3. Prompt with the loopable-motion vocabulary above and `"looping, seamless"`.
212
- 4. Download the result, transcode to `.ogv` if needed, place under `assets/video/loops/`.
204
+ 4. Import the clip's URL from a shell while Summer Engine runs: `summer tool import-from-url --args '{"url":"<clip url>","path":"res://assets/video/loops/<name>.ogv"}'`. It converts the clip to Ogg Theora (`.ogv`), the only video Summer Engine plays.
213
205
 
214
206
  Print the exact prompt + model + duration + aspect ratio so the user can paste it into the dashboard.
215
207
 
@@ -244,6 +236,8 @@ No Summer MCP tools in this session? Run each one as a command; when `summer --v
244
236
  | `summer_assets_search` | `summer assets search` |
245
237
  | `summer_docs_read` | `summer docs read` |
246
238
  | `summer_add_node` | `summer engine add-node` |
239
+ | `summer_import_asset` | `summer engine import-asset` |
240
+ | `summer_import_asset_by_id` | `summer engine import-asset-by-id` |
247
241
  | `summer_import_from_url` | `summer engine import-from-url` |
248
242
  | `summer_run_script` | `summer engine run-script` |
249
243
  | `summer_set_prop` | `summer engine set-prop` |
@@ -126,24 +126,11 @@ Lip-sync caveat: if the video shows the character clearly mouthing words and the
126
126
 
127
127
  ### 7. Import and wire as a VideoStreamPlayer
128
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):
129
+ **Import the `.mp4` as it is; the import converts it.** Summer Engine plays video only as Ogg Theora (`.ogv`), so every Summer import tool (`summer_import_from_url`, its batch, `summer_import_asset_by_id`, `summer_import_asset`) converts a video on the way in and saves it at the path you asked for with `.ogv`. The answer names the file in `videoConversions` and `note`:
130
130
 
131
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 the engine'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
-
145
- ```
146
- summer_import_from_url(url="<hosted .ogv url>", path="res://assets/video/cinematics/intro_shot_01.ogv")
132
+ summer_import_asset_by_id(assetId="<the shot's asset id>", path="res://assets/video/cinematics/intro_shot_01.mp4")
133
+ → importedTo: res://assets/video/cinematics/intro_shot_01.ogv
147
134
  ```
148
135
 
149
136
  Build a controller scene at `res://cinematics/Intro.tscn`: create it, then build its nodes in one script (`scenePath` names the new scene; the editor's open tab comes back afterwards):
@@ -204,7 +191,7 @@ Pattern: `<subject> + <action> + <camera move> + <lighting> + <stylistic anchor>
204
191
  - **Using `kling` for blocking iterations.** Validate framing and prompt on the cheaper `ltx` first; move to `kling` once the composition lands.
205
192
  - **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.
206
193
  - **Treating `assets.generate_video` as finished.** It answers `{ status: "running", job }` and no URL. Wait with `jobs.wait` until the job is done before there is anything to show or import.
207
- - **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.
194
+ - **Loading the `.mp4` path after an import.** The engine has no MP4 or WebM loader; the import saved the shot as `.ogv`. `load()` the `.ogv` path the answer names.
208
195
  - **Asking `ltx` or `kling` for `duration: 3` or `duration: 8`.** On those two only 5 and 10 exist; anything else renders 5.
209
196
  - **Pairing `imageUrl` with `kling-turbo` or `veo3`.** Neither has an image-to-video endpoint — that combination is a 400.
210
197
 
@@ -227,7 +214,7 @@ If the MCP server isn't running, the user can do all of this in the Summer dashb
227
214
  1. Generate a reference image in the Image tab.
228
215
  2. Open the Video tab, paste the reference URL into the image-to-video field.
229
216
  3. Set model, duration, aspect ratio, and prompt as listed above.
230
- 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.
217
+ 4. Import the shot's URL from a shell while Summer Engine runs: `summer tool import-from-url --args '{"url":"<shot url>","path":"res://assets/video/cinematics/<name>.ogv"}'`. It converts the `.mp4` to Ogg Theora (`.ogv`), the only video container Summer Engine can open.
231
218
 
232
219
  Print the exact prompt + model + duration + aspect ratio so the user can paste it into the dashboard verbatim.
233
220
 
@@ -265,6 +252,8 @@ No Summer MCP tools in this session? Run each one as a command; when `summer --v
265
252
  | `summer_docs_read` | `summer docs read` |
266
253
  | `summer_add_node` | `summer engine add-node` |
267
254
  | `summer_create_scene` | `summer engine create-scene` |
255
+ | `summer_import_asset` | `summer engine import-asset` |
256
+ | `summer_import_asset_by_id` | `summer engine import-asset-by-id` |
268
257
  | `summer_import_from_url` | `summer engine import-from-url` |
269
258
  | `summer_run_script` | `summer engine run-script` |
270
259
  | `summer_set_prop` | `summer engine set-prop` |
@@ -48,14 +48,14 @@ Exit codes lie in both directions here.
48
48
  - **`--write-movie` under `--headless` is a deterministic crash**, not a graceful failure. `MovieWriter::add_frame()` dereferences a null image from the dummy renderer on frame one. Headless has no pixels, so there is no safe form of this. Frame capture needs the windowed verify instance below.
49
49
  - **`--quit-after 1`** hits the fast-exit path and aborts during static destruction. Use `--headless --quit-after 60` if you need a bounded editor run — with `--headless`, never without.
50
50
 
51
- ### Never put a window on the user's screen
51
+ ### Never put an extra window on the user's screen from a shell
52
52
 
53
53
  <EXTREMELY-IMPORTANT>
54
- **Every engine launch you make is `--headless`.** The user did not ask you to open anything. A window that appears unasked steals focus, interrupts whatever they were doing, and is indistinguishable from a crash or a bug from their side. This is a product rule, not a convenience.
54
+ **Every engine process you start from a shell is `--headless`.** The user did not ask you to open anything. A window that appears unasked steals focus, interrupts whatever they were doing, and is indistinguishable from a crash or a bug from their side. This is a product rule, not a convenience.
55
55
 
56
56
  The one exception is the verify instance, and it is safe precisely because it is not visible: `--summer-verify` opens a real rendering window that is **hidden, `NO_FOCUS`, and positioned at `(-32000,-32000)`**. That is why it can produce real pixels without ever appearing. Never reproduce the "I need a renderer" reasoning by launching a plain windowed editor — use `--summer-verify`.
57
57
 
58
- If you genuinely believe the user needs to see the editor, ask them first.
58
+ This rule is about extra engine processes you start from a shell. Opening the Summer editor and playing the game in a window through the Summer tools is allowed and expected: `summer_play`, then `summer_screenshot` or `summer_frame_shot` to see the result. Close what you opened when you are done; one editor at a time.
59
59
  </EXTREMELY-IMPORTANT>
60
60
 
61
61
  ### Finding the binary — do not guess
@@ -401,7 +401,7 @@ Keep scripts in the project (`res://` is required for `-s`), but name them so th
401
401
  | Killing an import at 3s | Measured 0/8 assets registered. The floor is ~5s. |
402
402
  | A long-lived `--headless --editor` as a file watcher | It never rescans. Boot, act, exit. |
403
403
  | Adding `--quiet` | Swallows your own print() output. |
404
- | Launching the editor without `--headless` | Pops a window onto the user's screen unasked. |
404
+ | A shell script run without `--headless` | Pops an extra window onto the user's screen unasked. To see the game, use `summer_play` and `summer_screenshot` in the open editor. |
405
405
  | Ignoring `ResourceSaver.save()`'s return value | Non-zero is a silent failure that ships. |
406
406
  | `pack()` without setting `.owner` on every node | Two success codes, nodes missing from the file. |
407
407
  | Verifying a write by reading the object you just wrote | In-memory read-back passes whether or not it landed. |
@@ -420,8 +420,11 @@ No Summer MCP tools in this session? Run each one as a command; when `summer --v
420
420
 
421
421
  | In this skill | Command |
422
422
  |---|---|
423
+ | `summer_frame_shot` | `summer engine frame-shot` |
423
424
  | `summer_get_project_context` | `summer engine get-project-context` |
424
425
  | `summer_import_from_url` | `summer engine import-from-url` |
426
+ | `summer_play` | `summer engine play` |
425
427
  | `summer_run_script` | `summer engine run-script` |
428
+ | `summer_screenshot` | `summer engine screenshot` |
426
429
  | `summer_write_file` | `summer engine write-file` |
427
430
  <!-- /shell-commands -->
@@ -25,6 +25,11 @@ checkout fails with `insufficient_funds`, tell the player they need more
25
25
  Sparks and that they can get them in the Summer app, then let them press Buy
26
26
  again.
27
27
 
28
+ This skill covers the purchase sheet and granting an effect on a server.
29
+ For the rest of the store, use the `summer-store` skill: where items come
30
+ from and how one becomes buyable, item slugs, `summer.items.json`, bundles
31
+ and sales, owned items, and the authority's entitlement check.
32
+
28
33
  ## When to sell with Sparks
29
34
 
30
35
  - Sell anything that persists across sessions or devices (cosmetics, unlocks,
@@ -89,12 +94,20 @@ The operation returned by `request_checkout` also completes: ok on
89
94
 
90
95
  ## Minimal complete example
91
96
 
97
+ Items are named by **slug** (Studio's "Item key", e.g. `sword`), which is
98
+ the same in staging and production. Definition ids (`item_…`) differ between
99
+ them, so never hard-code one. The slug getters need a Summer version that
100
+ carries them (newer than 0.7.3); on an older one, use each environment's
101
+ definition id with `has_owned_definition()` and `get_definition_id()`. The
102
+ `summer-store` skill shows how to check.
103
+
92
104
  ```gdscript
93
105
  extends Node
94
106
  ## A one-item shop. Buys `offer_id` and unlocks from inventory.
95
107
 
96
- @export var offer_id := "offer_sword"
97
- @export var definition_id := "item_sword"
108
+ ## From the store listing: item.price.offer_id of the item whose get_slug() is item_slug.
109
+ @export var offer_id := ""
110
+ @export var item_slug := "sword"
98
111
 
99
112
  signal message(text: String)
100
113
  var _seen := {}
@@ -137,7 +150,7 @@ func _on_checkout(status: SummerCheckoutStatus) -> void:
137
150
  pass
138
151
 
139
152
  func _sync_owned() -> void:
140
- if Summer.client.items.has_owned_definition(definition_id):
153
+ if Summer.client.items.has_owned_slug(item_slug):
141
154
  message.emit("Sword unlocked.") # the only place the item is granted
142
155
  ```
143
156
 
@@ -156,7 +169,7 @@ items. The client sends the authority only an owned item ID. The authority:
156
169
 
157
170
  1. reads that player's inventory with
158
171
  `Summer.authority.items.inventory_for_session(session)` and checks the
159
- item is there, owned, and of the right definition;
172
+ item is there, owned, and the right item (its slug);
160
173
  2. checks its own record of redeemed item IDs, kept in the player's secret
161
174
  player data (`Summer.authority.player_data`), so the item grants once per
162
175
  player in every world;
@@ -165,7 +178,7 @@ items. The client sends the authority only an owned item ID. The authority:
165
178
 
166
179
  ```gdscript
167
180
  # On the dedicated authority.
168
- const EFFECT_DEFINITION := "item_grow_now"
181
+ const EFFECT_SLUG := "grow_now"
169
182
 
170
183
  func redeem(session: SummerSession, owned_item_id: String) -> void:
171
184
  var inv := Summer.authority.items.inventory_for_session(session)
@@ -176,7 +189,7 @@ func redeem(session: SummerSession, owned_item_id: String) -> void:
176
189
  for candidate in inv.items:
177
190
  if candidate.get_owned_item_id() == owned_item_id:
178
191
  item = candidate
179
- if item == null or not item.is_owned() or item.get_definition_id() != EFFECT_DEFINITION:
192
+ if item == null or not item.is_owned() or item.get_slug() != EFFECT_SLUG:
180
193
  return # not owned by this player: never grant
181
194
 
182
195
  var load_op := Summer.authority.player_data.load(session)
@@ -228,8 +241,11 @@ The game code is identical on every surface.
228
241
 
229
242
  ## Testing
230
243
 
231
- - Test against Summer staging, which runs in sandbox mode. *Why:* no real
232
- money moves and results are identical to production.
244
+ - Test against Summer staging, where Sparks come from test payments
245
+ (sandbox Sparks). *Why:* no real money moves and results are identical to
246
+ production. Use a staging account that bought Sparks in the staging Summer
247
+ app. The `summer-store` skill covers staging access and what makes an item
248
+ buyable there.
233
249
  - Walk every state: decline the sheet, let it expire, buy with too few
234
250
  Sparks, get Sparks in the Summer app, then buy the item. Kill the game while
235
251
  a checkout is pending and relaunch; the result must still arrive once.
@@ -255,6 +271,7 @@ Sparks in the Summer app.
255
271
 
256
272
  ## See also
257
273
 
274
+ - summer-store: items, slugs, bundles, owned items and the authority check
258
275
  - multiplayer-state
259
276
  - ui-basics
260
277
 
@@ -1,6 +1,6 @@
1
1
  id: skill/in-game-purchases
2
2
  kind: skill
3
- version: 1.0.0
3
+ version: 1.1.0
4
4
  summary: "Sell items for Sparks via the Summer purchase sheet: checkout, not enough Sparks, unlocks, grants."
5
5
  use_when:
6
6
  - "adding a shop, buy button or paid item to a Summer game and wiring request_checkout"
@@ -21,6 +21,7 @@ compatibility:
21
21
  engine: ">=4.6"
22
22
  related:
23
23
  skills:
24
+ - skill/summer-store
24
25
  - skill/multiplayer-state
25
26
  - skill/ui-basics
26
27
  source: official