summer-engine 4.3.0 → 4.5.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 (218) 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 +87 -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/index.js +5 -0
  27. package/dist/core/agent-host.d.ts +3 -0
  28. package/dist/core/agent-host.js +1 -1
  29. package/dist/core/api-client.d.ts +10 -2
  30. package/dist/core/api-client.js +13 -8
  31. package/dist/core/capabilities/agent-playbook.js +1 -0
  32. package/dist/core/capabilities/apps.d.ts +9 -9
  33. package/dist/core/capabilities/asset-import.d.ts +4 -1
  34. package/dist/core/capabilities/asset-import.js +15 -6
  35. package/dist/core/capabilities/capture-gameplay.js +1 -1
  36. package/dist/core/capabilities/connect-signal.d.ts +2 -2
  37. package/dist/core/capabilities/content-make/index.d.ts +81 -0
  38. package/dist/core/capabilities/content-make/index.js +706 -0
  39. package/dist/core/capabilities/content-make/media.d.ts +57 -0
  40. package/dist/core/capabilities/content-make/media.js +172 -0
  41. package/dist/core/capabilities/content-make/plan.d.ts +130 -0
  42. package/dist/core/capabilities/content-make/plan.js +433 -0
  43. package/dist/core/capabilities/content-make/render.d.ts +64 -0
  44. package/dist/core/capabilities/content-make/render.js +370 -0
  45. package/dist/core/capabilities/content-make/study.d.ts +13 -0
  46. package/dist/core/capabilities/content-make/study.js +165 -0
  47. package/dist/core/capabilities/content-make/types.d.ts +173 -0
  48. package/dist/core/capabilities/content-make/types.js +6 -0
  49. package/dist/core/capabilities/content-make/voice.d.ts +7 -0
  50. package/dist/core/capabilities/content-make/voice.js +27 -0
  51. package/dist/core/capabilities/events.d.ts +2 -2
  52. package/dist/core/capabilities/export-game.d.ts +4 -1
  53. package/dist/core/capabilities/export-game.js +4 -3
  54. package/dist/core/capabilities/export-presets.d.ts +2 -1
  55. package/dist/core/capabilities/export-presets.js +2 -1
  56. package/dist/core/capabilities/go-live.d.ts +14 -0
  57. package/dist/core/capabilities/go-live.js +408 -0
  58. package/dist/core/capabilities/image-generation.d.ts +6 -6
  59. package/dist/core/capabilities/item-manifest.d.ts +92 -0
  60. package/dist/core/capabilities/item-manifest.js +247 -0
  61. package/dist/core/capabilities/placement.d.ts +7 -7
  62. package/dist/core/capabilities/projects-local.d.ts +68 -0
  63. package/dist/core/capabilities/projects-local.js +172 -0
  64. package/dist/core/capabilities/publish-build.d.ts +13 -2
  65. package/dist/core/capabilities/publish-build.js +87 -21
  66. package/dist/core/capabilities/publish-download.js +1 -1
  67. package/dist/core/capabilities/runtime-control.d.ts +7 -2
  68. package/dist/core/capabilities/runtime-control.js +27 -1
  69. package/dist/core/capabilities/seeing/args.d.ts +2 -2
  70. package/dist/core/capabilities/store-checks.d.ts +45 -0
  71. package/dist/core/capabilities/store-checks.js +85 -0
  72. package/dist/core/capabilities/store-details.d.ts +37 -0
  73. package/dist/core/capabilities/store-details.js +94 -0
  74. package/dist/core/capabilities/summer-bundle.d.ts +21 -2
  75. package/dist/core/capabilities/summer-bundle.js +54 -7
  76. package/dist/core/capabilities/sync-items.d.ts +89 -0
  77. package/dist/core/capabilities/sync-items.js +352 -0
  78. package/dist/core/capabilities/tool-dispatch.js +66 -6
  79. package/dist/core/capabilities/video-ogv.d.ts +49 -0
  80. package/dist/core/capabilities/video-ogv.js +260 -0
  81. package/dist/core/capability-skew.js +2 -2
  82. package/dist/core/cli-usage-beacon.js +26 -2
  83. package/dist/core/cli-usage.d.ts +5 -2
  84. package/dist/core/cli-usage.js +8 -2
  85. package/dist/core/engine-install.d.ts +53 -0
  86. package/dist/core/engine-install.js +93 -0
  87. package/dist/core/engine-installer.d.ts +134 -0
  88. package/dist/core/engine-installer.js +760 -0
  89. package/dist/core/engine-launch.d.ts +126 -0
  90. package/dist/core/engine-launch.js +398 -0
  91. package/dist/core/engine-self-start.d.ts +63 -0
  92. package/dist/core/engine-self-start.js +282 -0
  93. package/dist/core/engine.d.ts +7 -1
  94. package/dist/core/engine.js +9 -2
  95. package/dist/core/error-codes.d.ts +4 -1
  96. package/dist/core/error-codes.js +7 -3
  97. package/dist/core/library-read.d.ts +2 -2
  98. package/dist/core/library-search.d.ts +2 -2
  99. package/dist/core/local-project.d.ts +50 -0
  100. package/dist/core/local-project.js +234 -0
  101. package/dist/core/ops/areas.js +9 -3
  102. package/dist/core/ops/catalog.d.ts +9 -0
  103. package/dist/core/ops/catalog.js +56 -4
  104. package/dist/core/ops/engine-answer.d.ts +4 -1
  105. package/dist/core/ops/engine-answer.js +16 -3
  106. package/dist/core/ops/engine.js +4 -4
  107. package/dist/core/ops/save-files.d.ts +6 -1
  108. package/dist/core/ops/save-files.js +67 -50
  109. package/dist/core/ops/search.js +9 -2
  110. package/dist/core/preview/input.d.ts +35 -0
  111. package/dist/core/preview/input.js +105 -0
  112. package/dist/core/preview/launch-config.d.ts +52 -0
  113. package/dist/core/preview/launch-config.js +137 -0
  114. package/dist/core/preview/page.d.ts +22 -0
  115. package/dist/core/preview/page.js +232 -0
  116. package/dist/core/preview/preview-source.d.ts +179 -0
  117. package/dist/core/preview/preview-source.js +350 -0
  118. package/dist/core/preview/server.d.ts +26 -0
  119. package/dist/core/preview/server.js +218 -0
  120. package/dist/core/telemetry.d.ts +20 -16
  121. package/dist/core/telemetry.js +92 -16
  122. package/dist/core/templates.d.ts +20 -0
  123. package/dist/core/templates.js +300 -3
  124. package/dist/core/tool-profiles.d.ts +2 -2
  125. package/dist/core/tool-profiles.js +1 -0
  126. package/dist/core/usage-fields.d.ts +41 -0
  127. package/dist/core/usage-fields.js +150 -0
  128. package/dist/core/util/sleep.d.ts +3 -0
  129. package/dist/core/util/sleep.js +12 -0
  130. package/dist/mcp/ops-surface.js +28 -2
  131. package/dist/mcp/server.d.ts +14 -4
  132. package/dist/mcp/server.js +42 -8
  133. package/dist/mcp/tool-surface.d.ts +8 -0
  134. package/dist/mcp/tool-surface.js +19 -2
  135. package/dist/mcp/tools/creator-tools.js +92 -14
  136. package/dist/mcp/tools/debug-tools.js +2 -0
  137. package/dist/mcp/tools/local-project-tools.d.ts +6 -0
  138. package/dist/mcp/tools/local-project-tools.js +33 -0
  139. package/dist/mcp/tools/navigation-tools.js +2 -1
  140. package/dist/mcp/tools/project-tools.js +5 -8
  141. package/dist/mcp/tools/seeing-tools.js +1 -1
  142. package/dist/mcp/tools/visual-tools.js +1 -1
  143. package/dist/mcp/tools/with-engine.js +1 -1
  144. package/gemini-extension.json +3 -1
  145. package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -5
  146. package/library/skills/README.md +12 -8
  147. package/library/skills/animated-loop/SKILL.md +10 -16
  148. package/library/skills/cinematic-cutscene/SKILL.md +7 -18
  149. package/library/skills/headless-scripting/SKILL.md +7 -4
  150. package/library/skills/in-game-purchases/SKILL.md +25 -8
  151. package/library/skills/in-game-purchases/resource.yaml +2 -1
  152. package/library/skills/launch-ready/SKILL.md +351 -0
  153. package/library/skills/launch-ready/resource.yaml +45 -0
  154. package/library/skills/make-content/SKILL.md +202 -0
  155. package/library/skills/make-content/resource.yaml +32 -0
  156. package/library/skills/make-game/SKILL.md +2 -0
  157. package/library/skills/make-game/resource.yaml +2 -1
  158. package/library/skills/navigate-summer/SKILL.md +4 -2
  159. package/library/skills/new-project/SKILL.md +15 -22
  160. package/library/skills/new-project/resource.yaml +2 -1
  161. package/library/skills/painted-25d-world/SKILL.md +366 -0
  162. package/library/skills/painted-25d-world/_building-blocks/blender-route.md +33 -0
  163. package/library/skills/painted-25d-world/_building-blocks/blockout_builder.gd +149 -0
  164. package/library/skills/painted-25d-world/_building-blocks/capture_paint_view.gd +32 -0
  165. package/library/skills/painted-25d-world/_building-blocks/paint_projection.gdshader +23 -0
  166. package/library/skills/painted-25d-world/_building-blocks/paintcam_check.gd +25 -0
  167. package/library/skills/painted-25d-world/_building-blocks/painted_door.gd +17 -0
  168. package/library/skills/painted-25d-world/_building-blocks/painted_location.gd +56 -0
  169. package/library/skills/painted-25d-world/_building-blocks/painted_player.gd +125 -0
  170. package/library/skills/painted-25d-world/_building-blocks/painted_world.gd +111 -0
  171. package/library/skills/painted-25d-world/_building-blocks/tools/cam.py +57 -0
  172. package/library/skills/painted-25d-world/_building-blocks/tools/detail4k.py +81 -0
  173. package/library/skills/painted-25d-world/_building-blocks/tools/overlay.py +17 -0
  174. package/library/skills/painted-25d-world/_building-blocks/tools/preview.py +60 -0
  175. package/library/skills/painted-25d-world/resource.yaml +39 -0
  176. package/library/skills/publish-your-game/SKILL.md +13 -14
  177. package/library/skills/publish-your-game/resource.yaml +4 -3
  178. package/library/skills/release-checklist/SKILL.md +188 -0
  179. package/library/skills/release-checklist/resource.yaml +40 -0
  180. package/library/skills/release-readiness/SKILL.md +1 -1
  181. package/library/skills/release-readiness/resource.yaml +1 -1
  182. package/library/skills/store-art/SKILL.md +1 -1
  183. package/library/skills/store-art/resource.yaml +1 -1
  184. package/library/skills/store-listing/SKILL.md +1 -1
  185. package/library/skills/store-listing/resource.yaml +1 -1
  186. package/library/skills/summer-cli/SKILL.md +2 -0
  187. package/library/skills/summer-store/SKILL.md +295 -39
  188. package/library/skills/summer-store/resource.yaml +9 -3
  189. package/library/skills/trailer-shot/SKILL.md +3 -3
  190. package/library/templates/README.md +5 -0
  191. package/library/tools/content-make/resource.yaml +132 -0
  192. package/library/tools/frame-shot/GUIDE.md +1 -1
  193. package/library/tools/go-live/resource.yaml +67 -0
  194. package/library/tools/import-from-url/GUIDE.md +1 -0
  195. package/library/tools/import-from-url-batch/GUIDE.md +1 -1
  196. package/library/tools/play/GUIDE.md +2 -0
  197. package/library/tools/projects-create-local/resource.yaml +55 -0
  198. package/library/tools/projects-open-local/resource.yaml +51 -0
  199. package/library/tools/publish-build/resource.yaml +3 -3
  200. package/library/tools/screenshot/GUIDE.md +1 -1
  201. package/library/tools/store-set-details/resource.yaml +114 -0
  202. package/library/tools/sync-items/resource.yaml +72 -0
  203. package/package.json +1 -1
  204. package/registry/generated/aliases.json +6 -0
  205. package/registry/generated/counts.json +3 -3
  206. package/registry/generated/gemini-extension.json +3 -1
  207. package/registry/generated/index.json +463 -37
  208. package/registry/generated/marketplace.claude.json +1 -1
  209. package/registry/generated/plugin.claude-directory.json +4 -2
  210. package/registry/generated/plugin.claude.json +3 -1
  211. package/registry/generated/plugin.codex.json +5 -3
  212. package/registry/generated/plugin.cursor.json +4 -2
  213. package/registry/generated/plugin.factory.json +4 -2
  214. package/registry/generated/server.json +2 -2
  215. package/registry/generated/skills-index.md +12 -8
  216. package/registry/generated/skills-registry.json +62 -5
  217. package/registry/operations/legacy-names.json +40 -0
  218. package/registry/operations/public-catalog.json +10144 -387
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { createLocalProject, LocalProjectError, localProjectFailure, openLocalProject, } from "../../core/capabilities/projects-local.js";
3
+ import { EngineNotRunningError } from "../../core/error-codes.js";
4
+ import { bindMcpProject, currentMcpEngineSelection, logEngineSelfStart } from "../server.js";
5
+ import { textJson } from "./text-json.js";
6
+ import { engineNotRunningResult } from "./with-engine.js";
7
+ async function localProjectResult(operation) {
8
+ try {
9
+ return textJson(await operation());
10
+ }
11
+ catch (error) {
12
+ if (error instanceof LocalProjectError)
13
+ return textJson(localProjectFailure(error), true);
14
+ if (error instanceof EngineNotRunningError)
15
+ return engineNotRunningResult(error);
16
+ throw error;
17
+ }
18
+ }
19
+ /**
20
+ * projects.create_local and projects.open_local: what `summer dev` does, for
21
+ * agents with no shell (core/capabilities/projects-local.ts).
22
+ */
23
+ export function registerLocalProjectTools(server) {
24
+ server.tool("summer_projects_create_local", "Create a Summer project on this computer from a template, with no shell: the built-in 3d-basic (sky, sun, ground and a hero; no download) unless template names another. Writes it into dir, or into <name> next to the session's project, in the session's folder, or in ~/Documents/Summer; never inside another project. A folder that already holds project.godot is left as it is. Returns projectPath. Next: summer_projects_open_local with that path.", {
25
+ template: z.string().max(80).optional().describe("Template slug (docs.search finds them): 3d-basic (default), empty, 3d-third-person-controller, 2d-platformer, ..."),
26
+ name: z.string().max(80).optional().describe("The project's name and folder name. Default my-game (or the template's name)."),
27
+ dir: z.string().max(1000).optional().describe("The project folder: a new or empty folder, not inside another project; ~ is home. Default <name> next to the session's project, in the session's folder, or in ~/Documents/Summer."),
28
+ }, async (args) => localProjectResult(() => createLocalProject(args, currentMcpEngineSelection()?.cwd)));
29
+ server.tool("summer_projects_open_local", "Open a project on this computer in Summer Engine, in the background, and wait until it connects (an editor that has it open is used as it is); this session's engine tools then work on it. When Summer Engine is not installed it answers engine_not_running: ask the person, and only with their yes call again with install: true (about 660 MB, free). A first open can take a few minutes: the answer says to call again. It adds summer-preview to the session folder's .claude/launch.json (Claude Code Desktop's Browser pane), and preview.url is where the game shows. Next: summer_get_project_context.", {
30
+ path: z.string().max(1000).optional().describe("The project folder (holds project.godot), e.g. projectPath from summer_projects_create_local. Default this session's project."),
31
+ install: z.boolean().default(false).describe("Install Summer Engine first when it is missing. Set true only after the person said yes."),
32
+ }, async (args) => localProjectResult(() => openLocalProject(args, currentMcpEngineSelection(), { log: logEngineSelfStart }, (root, client) => bindMcpProject(root, client))));
33
+ }
@@ -24,7 +24,8 @@ Result: { ok, action: opened | printed | listed | ambiguous | unsupported | engi
24
24
  - ambiguous: several destinations match; call again with one of matches[].id.
25
25
  Only summerengine.com (and subdomains) are ever opened — a gateway configured elsewhere is refused (blocked_origin); res:// paths with .. or other escapes are refused; a machine with no browser gets open_failed with the url to hand over.`, openArgsShape, async (args) => {
26
26
  const result = await runOpen(args, {
27
- engine: () => getClient(),
27
+ // Lists and prints must not open the editor (no side effects).
28
+ engine: () => getClient({ launch: false }),
28
29
  openUrl: (url) => open(url),
29
30
  isLoggedIn: async () => (await getAuthToken()) !== null,
30
31
  gatewayUrl: resolveGatewayUrl,
@@ -5,6 +5,7 @@ import { buildProjectContext, projectContextInputShape, resolveMainScene, } from
5
5
  import { getCachedBootDriftNotice } from "../boot-notice.js";
6
6
  import { appendMcpLogEvent } from "../../core/mcp-log.js";
7
7
  import { withEngine } from "./with-engine.js";
8
+ import { importUrls } from "../../core/capabilities/video-ogv.js";
8
9
  import { asRecord, stringFrom } from "../../core/util/json.js";
9
10
  // One skew log line per MCP process — the warning itself stays in every
10
11
  // summer_get_project_context payload.
@@ -245,20 +246,16 @@ Use this for:
245
246
  - 3D models (.glb, .gltf, .obj)
246
247
  - Textures (.png, .jpg, .webp)
247
248
  - Audio (.ogg, .wav, .mp3)
249
+ - Video (.mp4, .mov, .webm, .ogv): Summer Engine plays only Ogg Theora, so any other video is converted to .ogv first and lands at the path with .ogv; the answer names it.
248
250
 
249
251
  The path is auto-inferred from the URL filename if not specified. After import, the asset is immediately usable in scenes.`, {
250
252
  url: z.string().describe("HTTP(S) URL to download from"),
251
253
  path: z.string().optional().describe("Target path in project, e.g. 'res://assets/player.glb'. Auto-inferred from URL if omitted."),
252
- }, async ({ url, path }) => withEngine(async (client) => {
253
- const op = { op: "ImportFromUrl", url };
254
- if (path)
255
- op.path = path;
256
- return client.executeOps([op]);
257
- }));
258
- server.tool("summer_import_from_url_batch", "Download multiple files from URLs in one operation. Performs a single filesystem scan after all downloads, which is faster than importing one at a time.", {
254
+ }, async ({ url, path }) => withEngine(async (client) => importUrls(client, [{ url, ...(path ? { path } : {}) }], { batch: false })));
255
+ server.tool("summer_import_from_url_batch", "Download multiple files from URLs in one operation. Performs a single filesystem scan after all downloads, which is faster than importing one at a time. A video (.mp4, .mov, .webm) is converted to Ogg Theora first and lands at its path with .ogv.", {
259
256
  imports: z.array(z.object({
260
257
  url: z.string().describe("URL to download"),
261
258
  path: z.string().describe("Target path in project"),
262
259
  })).describe("Array of {url, path} objects"),
263
- }, async ({ imports }) => withEngine(async (client) => client.executeOps([{ op: "ImportFromUrlBatch", imports }])));
260
+ }, async ({ imports }) => withEngine(async (client) => importUrls(client, imports, { batch: true })));
264
261
  }
@@ -54,7 +54,7 @@ Returns the grid + caption. ${COMMON}`, debugViewsShape, run(debugViews));
54
54
  server.tool("summer_zoom", `High-resolution close look at part of a frame: region [x, y, w, h] (fractions of the frame) or mark N from a marks render of the same pose. The camera renders the EXACT sub-frustum of that region at full output resolution, so you see real texture detail, seams, gaps and floating pieces, not upscaled pixels. A region is honoured exactly (no pad by default, never widened to an aspect ratio: the image takes the region's own aspect, with dark bars only for extreme shapes); a mark gets pad 0.15.
55
55
 
56
56
  Use after a sheet or debug view shows something suspicious. view picks beauty or a debug view. Returns the zoomed image + caption (the real zoom factor, the rendered region, widened_because when it is larger than asked, mark -> node path and a warning when that node is hidden). ${COMMON}`, zoomShape, run(zoom));
57
- server.tool("summer_frame_shot", `Smart framing: find good camera poses for a shot type automatically, measured in-engine against the real geometry.
57
+ server.tool("summer_frame_shot", `Smart framing: find good camera poses for a shot type automatically, measured in-engine against the real geometry. It runs in the open editor; use it to look at the scene as a player would.
58
58
 
59
59
  shot: establishing (wide), eye_level (from a spawn node at player eye height), low_angle (hero, near the ground looking up: the camera moves closer and widens its FOV instead of sinking into the ground), detail (close-up), corridor (down a lane or corridor found inside the subject by a free-space scan, preferring the view in from its open end, walls on both sides).
60
60
 
@@ -103,7 +103,7 @@ function teachPreviewFailure(snap) {
103
103
  export function registerVisualTools(server) {
104
104
  server.tool("summer_screenshot", `Capture a frame from Summer Engine and return it as an image you can look at directly.
105
105
 
106
- Use this to visually verify your work: scene layout, asset placement, scale, framing, missing/untextured assets, or runtime gameplay state. You see the actual pixels — no description layer in between. Lighting and materials are only truthfully shown by the "viewport" and "game" targets — see the note on "scene" below.
106
+ Use this to visually verify your work (it reads the real open editor or game window; that is allowed and expected): scene layout, asset placement, scale, framing, missing/untextured assets, or runtime gameplay state. You see the actual pixels — no description layer in between. Lighting and materials are only truthfully shown by the "viewport" and "game" targets — see the note on "scene" below.
107
107
 
108
108
  target:
109
109
  "viewport" (default) — the editor's CURRENT view (whatever scene/tab is open). No game boot. Use for edit-time checks of how the scene looks right now.
@@ -162,7 +162,7 @@ export async function withEngine(fn, opts) {
162
162
  export function engineNotRunningResult(error) {
163
163
  return {
164
164
  isError: true,
165
- content: [{ type: "text", text: JSON.stringify(codedFailure(error.code, error.message, { hint: ENGINE_FREE_NOTE }), null, 2) }],
165
+ content: [{ type: "text", text: JSON.stringify(codedFailure(error.code, error.message, { hint: ENGINE_FREE_NOTE }, error.recovery), null, 2) }],
166
166
  };
167
167
  }
168
168
  const PRE_APPLY_FAILURE_REASON = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_generated": "GENERATED from integrations/gemini — do not edit; npm run generate:registry",
3
3
  "name": "summer",
4
- "version": "4.3.0",
4
+ "version": "4.5.0",
5
5
  "description": "The game engine built for AI. Any agent makes a multiplayer game and publishes it. The Summer Engine MCP server, context primer and game-dev skills.",
6
6
  "contextFileName": "GEMINI.md",
7
7
  "mcpServers": {
@@ -72,6 +72,7 @@
72
72
  "./library/skills/in-game-purchases/",
73
73
  "./library/skills/instantiate-asset-pack/",
74
74
  "./library/skills/investigating-bugs/",
75
+ "./library/skills/make-content/",
75
76
  "./library/skills/make-game/",
76
77
  "./library/skills/multiplayer/",
77
78
  "./library/skills/multiplayer-movement/",
@@ -89,6 +90,7 @@
89
90
  "./library/skills/procedural-animation/",
90
91
  "./library/skills/prop-model/",
91
92
  "./library/skills/publish-your-game/",
93
+ "./library/skills/release-checklist/",
92
94
  "./library/skills/release-readiness/",
93
95
  "./library/skills/remote-deploy/",
94
96
  "./library/skills/retarget/",
@@ -19,7 +19,16 @@
19
19
 
20
20
  **Rule of thumb:** project reads/writes go through Summer; live hierarchy/inspector changes use scene tools; process-level work remains with the host.
21
21
 
22
- ## Tool surface (119 tools)
22
+ ## Tool surface (125 tools)
23
+
24
+ ### Local projects (2)
25
+
26
+ No shell needed (Claude Desktop, chat apps); the `summer dev` command does both in one step from a shell.
27
+
28
+ | Tool | Use |
29
+ |---|---|
30
+ | `summer_projects_create_local` | Write a new project from a template to this computer (`3d-basic` by default: sky, sun, ground and a hero). `dir`, or `name` next to the session's project, in the session's folder, or in `~/Documents/Summer`; never inside another project. A folder that already holds `project.godot` is left as it is. Returns `projectPath`. |
31
+ | `summer_projects_open_local` | Open a project in Summer Engine in the background and wait until it connects; the session's engine tools then work on it. Engine missing: answers `engine_not_running`; ask the person, and only with their yes call again with `install: true` (about 660 MB, free). A slow first open answers "call again in 30 seconds". It registers `summer preview` in the session folder's `.claude/launch.json`; `preview.url` is where the game shows. |
23
32
 
24
33
  ### Project files (4)
25
34
 
@@ -253,13 +262,17 @@ Each spends the person's credits. `dryRun: true` returns `preview.estimate` (`cr
253
262
  | `summer_call` `{"op":"summer_get_agent_playbook"}` | Daily operating contract (observe-first loop, content routing, invariants, verification ritual) — read at start of session. Also served natively as the `summer_agent_playbook` MCP prompt. |
254
263
  | `plans.get` (3.x `summer_get_board`) | Read the person's game plan (look, characters, place, storyboard, picks): every item with its id, picture URL and revision, to compare screenshots against. `projects.get({ projectId })` gives the project's `planId` from the project id in the build brief; works without the engine. |
255
264
 
256
- ### Creator platform (4)
265
+ ### Creator platform (8)
257
266
 
258
267
  | Tool | Use |
259
268
  |---|---|
260
269
  | `summer_export_game` | Export the game in the file the Summer Games store takes, headless (no window), no running editor needed. `format:"bundle"` (default): the `summer.games` `.zip` the Summer apps run; `targets` picks `ios`, `android`, `macos`, `windows` (a game without a server: phones only) through a named `summer.games <targets>` preset in `export_presets.cfg`. `format:"download"` with one target: `web` (HTML5 `.zip` on Summer's WebGPU Forward+ template; refuses Compatibility projects), `macos` (ad hoc signed `.app` zip, `macos-universal`) or `windows` (`.exe` with embedded pack, zipped, `windows-x64`). Returns path, sha256, size, bundle manifest or store platform, warnings. |
261
270
  | `summer_export_templates` | `list` or `install` export templates from Summer's CDN (`downloads.summer.games/engine-templates/<summerVersion>/manifest.json`) into the engine's user template folder (`<data>/Godot/export_templates/<FULL_CONFIG>/`), sha256-checked. Only download exports need them; store bundles need none. `summerVersion` is read on macOS, passed elsewhere. |
262
- | `store.upload_file` (3.x `summer_publish_build`; through `summer_call`) | Upload that `.zip` to the creator's game through Studio's store upload: confirm-gated preview first, then declare, part upload from disk, seal, wait for the Build; `publish:true` also approves it. Needs `summer login --store`; a retry with the same file and version continues the same upload. Without a shell, `store.upload_begin`, `store.upload_sign_parts` and `store.upload_complete` take the bytes in parts. |
271
+ | `store.upload_file` (3.x `summer_publish_build`; through `summer_call`) | Upload that `.zip` to the creator's game through Studio's store upload: confirm-gated preview first, then declare, part upload from disk, seal, wait for the Build and for Summer's automated checks on each platform (`checks`: passed, or failed with `code`, `owner` and `fix`); `publish:true` also makes the Build available to players. Needs `summer login --store`; a retry with the same file and version continues the same upload. Without a shell, `store.upload_begin`, `store.upload_sign_parts` and `store.upload_complete` take the bytes in parts. |
272
+ | `store.go_live` (`summer_go_live`; through `summer_call`) | Take the store game live: release the uploaded bundle Build to the platforms that passed their checks and publish the store page, through the same store routes Studio uses, then watch until players get it. Confirm-gated: the plan first (or `live`, `blocked` with each failure's fix, `needs_changes` with Summer's feedback). It needs no owner approval link while the person's Agent permissions allow Publish (the default; otherwise `needs_permission`). `waiting` names what it waits on (`automated_checks`, `activation`, or `summer`: a hold on Summer's side that needs nothing from the creator). Call again to keep watching; nothing is asked twice. Run the `release-checklist` skill first. |
273
+ | `store.set_details` (`summer_store_set_details`; through `summer_call`) | The store page sections `store.update_listing` does not edit, on the draft: `genres`, `features`, `credits`, `languageSupport`, `systemRequirements`, `contentSurvey` (the age questionnaire) and `aiDisclosure`. A section given replaces it, `null` clears it. Never publishes. |
274
+ | `economy.sync_items` (`summer_sync_items`; through `summer_call`) | Bring the store game's items in line with `summer.items.json` in the project root, matched by slug, so staging and production carry the same items. Confirm-gated: the plan first (create, update with the changed fields, unchanged, blocked), then the changed images are uploaded and the plan goes to the owner, who approves it in Studio; the items are then created or revised, priced in Sparks and submitted for review. One approval takes at most 50 changed items (a larger plan lists `batches`; confirm each with `slugs`); a new item needs at least one image. Never activates or releases an item. Needs `summer login --store`. Staging or production is the gateway setting: switching takes `SUMMER_GATEWAY_URL` and `SUMMER_MCP_RESOURCE_URL`, then `summer login --store --force` (one store sign-in per machine). |
275
+ | `content.make` (`summer_content_make`; through `summer_call`) | Make one finished piece of content for a game on this computer and put it in the team's Review: picks the reference that fits today (a format the game has not posted, what changed in the repo), studies its cuts and caption look, maps each reference shot to a footage window with motion, cuts to its timings, draws its captions, puts a song on the beat, mixes at -14 LUFS, checks hook, motion per shot, safe zones, length and loudness, renders the reference side by side and saves the piece (failed checks: a draft). It never writes words: `needs_words` lists the beats, call again with `workDir` and `lines`; a reference that speaks also needs `voiceFile` in the team's voice (`needs_voice`). Same `workDir` continues where it stopped. Needs ffmpeg and ImageMagick (Whisper for a voice-over). |
263
276
  | `summer_capture_gameplay` | Real gameplay frames without a running editor: starts the game (main scene or `scene`) in the engine's offscreen verify instance (`--summer-verify`, real renderer, window parked offscreen, no focus) (`--summer-offscreen`) at `resolution` (default `1920x1080`), waits `waitSeconds`, runs `steps` (`press` a button by text, `key`, `action`, `click`, `drag`, `wait`, `shot`), saves `frames` PNGs (HUD included; with a `shot` step, one per shot) to `<project>/.summer/captures/<time>/`. `args` are the game's own flags, passed after `--` (e.g. `["--autostart"]` to skip the title screen). Imports the project first when `.godot/` is missing. Returns each path with its real width and height; warns when the stretch settings render another size. For store screenshots. |
264
277
 
265
278
  ### Hosted store, publishing and Grow tools
@@ -267,9 +280,9 @@ Each spends the person's credits. `dryRun: true` returns `preview.estimate` (`cr
267
280
  These come from the hosted Summer server (the one ChatGPT and Claude connect to) and are mounted into the local MCP after `summer login`; `summer tool <name>` reaches them too.
268
281
 
269
282
  - **Store page:** `summer_store_list_games`, `summer_store_create_game`, `summer_store_get_listing` (the page, the checklist and `availableTags`), `summer_store_update_listing` (text, tags, long description, support contact, release date, content rating), `summer_store_set_art`, `summer_store_set_trailer`, `summer_store_set_sound`, `summer_store_preview_link`, `summer_store_jams` and `summer_store_enter_jam`.
270
- - **Builds and release:** `summer_build_begin_upload` / `_sign_parts` / `_complete_upload` / `_status` (the local `summer_publish_build` does these from disk), `summer_store_version_*` for web and native downloads, `summer_store_submit` (one approval link for the owner), `summer_store_cancel_submission`, `summer_store_review`, `summer_store_releases`, `summer_build_release`.
283
+ - **Builds and release:** `summer_build_begin_upload` / `_sign_parts` / `_complete_upload` / `_status` (the local `summer_publish_build` does these from disk), `summer_store_version_*` for web and native downloads, `summer_store_submit` (one approval link for the owner, for a person whose Agent permissions have Publish off; otherwise the local `summer_go_live` takes the game live), `summer_store_cancel_submission`, `summer_store_review`, `summer_store_releases`, `summer_build_release`. The engine profile leaves out `summer_store_releases` and `summer_store_version_status`: `summer_go_live` reports what players get and each download's state.
271
284
  - **Grow:** `summer_grow_overview` and `summer_grow_analytics` (store page views, launches, play sessions, play time, custom events), `summer_grow_event_catalog`, `summer_grow_event_trend`, `summer_grow_event_funnel`, `summer_grow_members`, `summer_grow_ab_tests`, `summer_grow_prices`, `summer_grow_event_limit`, `summer_grow_apply` and `summer_grow_applications`.
272
- - **Guides:** the `publish-your-game`, `store-listing`, `store-art` and `grow-analytics` skills (`summer_docs_read`).
285
+ - **Guides:** the `publish-your-game`, `release-checklist`, `store-listing`, `store-art` and `grow-analytics` skills (`summer_docs_read`).
273
286
 
274
287
  ### Library search (2)
275
288
 
@@ -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