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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +3 -1
- package/.codex-plugin/plugin.json +5 -3
- package/.cursor-plugin/plugin.json +4 -2
- package/.factory-plugin/plugin.json +4 -2
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +87 -0
- package/README.md +67 -27
- package/commands/start.md +19 -15
- package/commands/summer.md +1 -0
- package/dist/cli/command-usage.d.ts +3 -1
- package/dist/cli/command-usage.js +10 -4
- package/dist/cli/commands/create.d.ts +1 -25
- package/dist/cli/commands/create.js +10 -138
- package/dist/cli/commands/dev.d.ts +66 -0
- package/dist/cli/commands/dev.js +234 -0
- package/dist/cli/commands/install.d.ts +15 -58
- package/dist/cli/commands/install.js +31 -481
- package/dist/cli/commands/login.js +1 -1
- package/dist/cli/commands/ops.d.ts +17 -1
- package/dist/cli/commands/ops.js +97 -9
- package/dist/cli/commands/preview.d.ts +58 -0
- package/dist/cli/commands/preview.js +181 -0
- package/dist/cli/commands/run.d.ts +1 -17
- package/dist/cli/commands/run.js +17 -206
- package/dist/cli/index.js +5 -0
- package/dist/core/agent-host.d.ts +3 -0
- package/dist/core/agent-host.js +1 -1
- package/dist/core/api-client.d.ts +10 -2
- package/dist/core/api-client.js +13 -8
- package/dist/core/capabilities/agent-playbook.js +1 -0
- package/dist/core/capabilities/apps.d.ts +9 -9
- package/dist/core/capabilities/asset-import.d.ts +4 -1
- package/dist/core/capabilities/asset-import.js +15 -6
- package/dist/core/capabilities/capture-gameplay.js +1 -1
- package/dist/core/capabilities/connect-signal.d.ts +2 -2
- package/dist/core/capabilities/content-make/index.d.ts +81 -0
- package/dist/core/capabilities/content-make/index.js +706 -0
- package/dist/core/capabilities/content-make/media.d.ts +57 -0
- package/dist/core/capabilities/content-make/media.js +172 -0
- package/dist/core/capabilities/content-make/plan.d.ts +130 -0
- package/dist/core/capabilities/content-make/plan.js +433 -0
- package/dist/core/capabilities/content-make/render.d.ts +64 -0
- package/dist/core/capabilities/content-make/render.js +370 -0
- package/dist/core/capabilities/content-make/study.d.ts +13 -0
- package/dist/core/capabilities/content-make/study.js +165 -0
- package/dist/core/capabilities/content-make/types.d.ts +173 -0
- package/dist/core/capabilities/content-make/types.js +6 -0
- package/dist/core/capabilities/content-make/voice.d.ts +7 -0
- package/dist/core/capabilities/content-make/voice.js +27 -0
- package/dist/core/capabilities/events.d.ts +2 -2
- package/dist/core/capabilities/export-game.d.ts +4 -1
- package/dist/core/capabilities/export-game.js +4 -3
- package/dist/core/capabilities/export-presets.d.ts +2 -1
- package/dist/core/capabilities/export-presets.js +2 -1
- package/dist/core/capabilities/go-live.d.ts +14 -0
- package/dist/core/capabilities/go-live.js +408 -0
- package/dist/core/capabilities/image-generation.d.ts +6 -6
- package/dist/core/capabilities/item-manifest.d.ts +92 -0
- package/dist/core/capabilities/item-manifest.js +247 -0
- package/dist/core/capabilities/placement.d.ts +7 -7
- package/dist/core/capabilities/projects-local.d.ts +68 -0
- package/dist/core/capabilities/projects-local.js +172 -0
- package/dist/core/capabilities/publish-build.d.ts +13 -2
- package/dist/core/capabilities/publish-build.js +87 -21
- package/dist/core/capabilities/publish-download.js +1 -1
- package/dist/core/capabilities/runtime-control.d.ts +7 -2
- package/dist/core/capabilities/runtime-control.js +27 -1
- package/dist/core/capabilities/seeing/args.d.ts +2 -2
- package/dist/core/capabilities/store-checks.d.ts +45 -0
- package/dist/core/capabilities/store-checks.js +85 -0
- package/dist/core/capabilities/store-details.d.ts +37 -0
- package/dist/core/capabilities/store-details.js +94 -0
- package/dist/core/capabilities/summer-bundle.d.ts +21 -2
- package/dist/core/capabilities/summer-bundle.js +54 -7
- package/dist/core/capabilities/sync-items.d.ts +89 -0
- package/dist/core/capabilities/sync-items.js +352 -0
- package/dist/core/capabilities/tool-dispatch.js +66 -6
- package/dist/core/capabilities/video-ogv.d.ts +49 -0
- package/dist/core/capabilities/video-ogv.js +260 -0
- package/dist/core/capability-skew.js +2 -2
- package/dist/core/cli-usage-beacon.js +26 -2
- package/dist/core/cli-usage.d.ts +5 -2
- package/dist/core/cli-usage.js +8 -2
- package/dist/core/engine-install.d.ts +53 -0
- package/dist/core/engine-install.js +93 -0
- package/dist/core/engine-installer.d.ts +134 -0
- package/dist/core/engine-installer.js +760 -0
- package/dist/core/engine-launch.d.ts +126 -0
- package/dist/core/engine-launch.js +398 -0
- package/dist/core/engine-self-start.d.ts +63 -0
- package/dist/core/engine-self-start.js +282 -0
- package/dist/core/engine.d.ts +7 -1
- package/dist/core/engine.js +9 -2
- package/dist/core/error-codes.d.ts +4 -1
- package/dist/core/error-codes.js +7 -3
- package/dist/core/library-read.d.ts +2 -2
- package/dist/core/library-search.d.ts +2 -2
- package/dist/core/local-project.d.ts +50 -0
- package/dist/core/local-project.js +234 -0
- package/dist/core/ops/areas.js +9 -3
- package/dist/core/ops/catalog.d.ts +9 -0
- package/dist/core/ops/catalog.js +56 -4
- package/dist/core/ops/engine-answer.d.ts +4 -1
- package/dist/core/ops/engine-answer.js +16 -3
- package/dist/core/ops/engine.js +4 -4
- package/dist/core/ops/save-files.d.ts +6 -1
- package/dist/core/ops/save-files.js +67 -50
- package/dist/core/ops/search.js +9 -2
- package/dist/core/preview/input.d.ts +35 -0
- package/dist/core/preview/input.js +105 -0
- package/dist/core/preview/launch-config.d.ts +52 -0
- package/dist/core/preview/launch-config.js +137 -0
- package/dist/core/preview/page.d.ts +22 -0
- package/dist/core/preview/page.js +232 -0
- package/dist/core/preview/preview-source.d.ts +179 -0
- package/dist/core/preview/preview-source.js +350 -0
- package/dist/core/preview/server.d.ts +26 -0
- package/dist/core/preview/server.js +218 -0
- package/dist/core/telemetry.d.ts +20 -16
- package/dist/core/telemetry.js +92 -16
- package/dist/core/templates.d.ts +20 -0
- package/dist/core/templates.js +300 -3
- package/dist/core/tool-profiles.d.ts +2 -2
- package/dist/core/tool-profiles.js +1 -0
- package/dist/core/usage-fields.d.ts +41 -0
- package/dist/core/usage-fields.js +150 -0
- package/dist/core/util/sleep.d.ts +3 -0
- package/dist/core/util/sleep.js +12 -0
- package/dist/mcp/ops-surface.js +28 -2
- package/dist/mcp/server.d.ts +14 -4
- package/dist/mcp/server.js +42 -8
- package/dist/mcp/tool-surface.d.ts +8 -0
- package/dist/mcp/tool-surface.js +19 -2
- package/dist/mcp/tools/creator-tools.js +92 -14
- package/dist/mcp/tools/debug-tools.js +2 -0
- package/dist/mcp/tools/local-project-tools.d.ts +6 -0
- package/dist/mcp/tools/local-project-tools.js +33 -0
- package/dist/mcp/tools/navigation-tools.js +2 -1
- package/dist/mcp/tools/project-tools.js +5 -8
- package/dist/mcp/tools/seeing-tools.js +1 -1
- package/dist/mcp/tools/visual-tools.js +1 -1
- package/dist/mcp/tools/with-engine.js +1 -1
- package/gemini-extension.json +3 -1
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -5
- package/library/skills/README.md +12 -8
- package/library/skills/animated-loop/SKILL.md +10 -16
- package/library/skills/cinematic-cutscene/SKILL.md +7 -18
- package/library/skills/headless-scripting/SKILL.md +7 -4
- package/library/skills/in-game-purchases/SKILL.md +25 -8
- package/library/skills/in-game-purchases/resource.yaml +2 -1
- package/library/skills/launch-ready/SKILL.md +351 -0
- package/library/skills/launch-ready/resource.yaml +45 -0
- package/library/skills/make-content/SKILL.md +202 -0
- package/library/skills/make-content/resource.yaml +32 -0
- package/library/skills/make-game/SKILL.md +2 -0
- package/library/skills/make-game/resource.yaml +2 -1
- package/library/skills/navigate-summer/SKILL.md +4 -2
- package/library/skills/new-project/SKILL.md +15 -22
- package/library/skills/new-project/resource.yaml +2 -1
- package/library/skills/painted-25d-world/SKILL.md +366 -0
- package/library/skills/painted-25d-world/_building-blocks/blender-route.md +33 -0
- package/library/skills/painted-25d-world/_building-blocks/blockout_builder.gd +149 -0
- package/library/skills/painted-25d-world/_building-blocks/capture_paint_view.gd +32 -0
- package/library/skills/painted-25d-world/_building-blocks/paint_projection.gdshader +23 -0
- package/library/skills/painted-25d-world/_building-blocks/paintcam_check.gd +25 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_door.gd +17 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_location.gd +56 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_player.gd +125 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_world.gd +111 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/cam.py +57 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/detail4k.py +81 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/overlay.py +17 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/preview.py +60 -0
- package/library/skills/painted-25d-world/resource.yaml +39 -0
- package/library/skills/publish-your-game/SKILL.md +13 -14
- package/library/skills/publish-your-game/resource.yaml +4 -3
- package/library/skills/release-checklist/SKILL.md +188 -0
- package/library/skills/release-checklist/resource.yaml +40 -0
- package/library/skills/release-readiness/SKILL.md +1 -1
- package/library/skills/release-readiness/resource.yaml +1 -1
- package/library/skills/store-art/SKILL.md +1 -1
- package/library/skills/store-art/resource.yaml +1 -1
- package/library/skills/store-listing/SKILL.md +1 -1
- package/library/skills/store-listing/resource.yaml +1 -1
- package/library/skills/summer-cli/SKILL.md +2 -0
- package/library/skills/summer-store/SKILL.md +295 -39
- package/library/skills/summer-store/resource.yaml +9 -3
- package/library/skills/trailer-shot/SKILL.md +3 -3
- package/library/templates/README.md +5 -0
- package/library/tools/content-make/resource.yaml +132 -0
- package/library/tools/frame-shot/GUIDE.md +1 -1
- package/library/tools/go-live/resource.yaml +67 -0
- package/library/tools/import-from-url/GUIDE.md +1 -0
- package/library/tools/import-from-url-batch/GUIDE.md +1 -1
- package/library/tools/play/GUIDE.md +2 -0
- package/library/tools/projects-create-local/resource.yaml +55 -0
- package/library/tools/projects-open-local/resource.yaml +51 -0
- package/library/tools/publish-build/resource.yaml +3 -3
- package/library/tools/screenshot/GUIDE.md +1 -1
- package/library/tools/store-set-details/resource.yaml +114 -0
- package/library/tools/sync-items/resource.yaml +72 -0
- package/package.json +1 -1
- package/registry/generated/aliases.json +6 -0
- package/registry/generated/counts.json +3 -3
- package/registry/generated/gemini-extension.json +3 -1
- package/registry/generated/index.json +463 -37
- package/registry/generated/marketplace.claude.json +1 -1
- package/registry/generated/plugin.claude-directory.json +4 -2
- package/registry/generated/plugin.claude.json +3 -1
- package/registry/generated/plugin.codex.json +5 -3
- package/registry/generated/plugin.cursor.json +4 -2
- package/registry/generated/plugin.factory.json +4 -2
- package/registry/generated/server.json +2 -2
- package/registry/generated/skills-index.md +12 -8
- package/registry/generated/skills-registry.json +62 -5
- package/registry/operations/legacy-names.json +40 -0
- package/registry/operations/public-catalog.json +10144 -387
|
@@ -40,6 +40,8 @@ Distilled blueprints for common genres live in this skill's `references/` folder
|
|
|
40
40
|
| Third-person action / 3D platformer | `references/3d-third-person.md` | `references/3d-third-person-systems.md` | Node3D / CharacterBody3D / SpringArm3D |
|
|
41
41
|
| First-person horror | `references/3d-horror.md` | `references/3d-horror-systems.md` | Node3D / CharacterBody3D / Camera3D on Head |
|
|
42
42
|
|
|
43
|
+
**2D and 2.5D games look painted.** For any 2D or 2.5D request (top-down, RPG, cozy, side-scroller, platformer look), build the world with the `painted-25d-world` skill: a 3D blockout under one fixed orthographic camera, an AI paint-over projected onto the blocks, sprite characters (Node3D / CharacterBody3D / translate-only Camera3D). Use the 2D playbooks above for the core loop, mechanics and build order only, not for the scene tree or art. Do not start a 2D game from a 2D template unless the user asks for that template.
|
|
44
|
+
|
|
43
45
|
No playbook (racing, sandbox, sim): build fresh through the phases below. The playbooks lean on these system skills — load one when its mechanic comes up: `character-movement`, `camera-rigs`, `combat-basics`, `save-load`, `ui-basics`, `multiplayer-project`.
|
|
44
46
|
|
|
45
47
|
These rules from the playbooks apply to every genre:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: skill/make-game
|
|
2
2
|
kind: skill
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.2.0
|
|
4
4
|
summary: "Orchestrate 'make me a game': brainstorm, plan, scaffold, mechanics, art, audio, polish, verify, ship."
|
|
5
5
|
use_when:
|
|
6
6
|
- the user says 'make me a game', 'build me a game', 'I want to make a [genre] game', or 'let's build something' — running the full game-dev pipeline
|
|
@@ -33,6 +33,7 @@ related:
|
|
|
33
33
|
- skill/camera-rigs
|
|
34
34
|
- skill/combat-basics
|
|
35
35
|
- skill/save-load
|
|
36
|
+
- skill/painted-25d-world
|
|
36
37
|
source: official
|
|
37
38
|
license: MIT
|
|
38
39
|
status: stable
|
|
@@ -24,10 +24,10 @@ Rigid skill: follow the rules below exactly.
|
|
|
24
24
|
| The user wants to… | Do |
|
|
25
25
|
|---|---|
|
|
26
26
|
| **see / check / decide** — plan and billing (money), their published games and releases, usage, pricing, the MCP setup guide for their agent, docs, the scene or node you just built ("show me") | **Open the surface** with `studio.open` |
|
|
27
|
-
| **get a result** — add a node, set a property, import an asset, run the game, publish | **Act through Summer tools** (mutation tools, `summer_play`, `store.publish`); do not
|
|
27
|
+
| **get a result** — add a node, set a property, import an asset, run the game, publish | **Act through Summer tools** (mutation tools, `summer_play`, `store.publish`); do not click through the editor by hand to do what a tool does |
|
|
28
28
|
| **both** ("add a camera and show me") | act first, then open the scene / select the node so the user sees the result |
|
|
29
29
|
|
|
30
|
-
Never open a browser or switch the editor's tab as a side effect of building. Opening is a user-visible action — do it because the user asked to look, and say what will open before it opens.
|
|
30
|
+
Never open a browser or switch the editor's tab as a side effect of building. Opening a page or panel is a user-visible action — do it because the user asked to look, and say what will open before it opens. Playing the game and taking screenshots to check your own work is different: that is allowed and expected (`summer_play`, then `summer_screenshot` or `summer_frame_shot`).
|
|
31
31
|
|
|
32
32
|
## How to call it
|
|
33
33
|
|
|
@@ -70,9 +70,11 @@ No Summer MCP tools in this session? Run each one as a command; when `summer --v
|
|
|
70
70
|
| In this skill | Command |
|
|
71
71
|
|---|---|
|
|
72
72
|
| `summer_docs_read` | `summer docs read` |
|
|
73
|
+
| `summer_frame_shot` | `summer engine frame-shot` |
|
|
73
74
|
| `summer_get_project_context` | `summer engine get-project-context` |
|
|
74
75
|
| `summer_is_running` | `summer engine is-running` |
|
|
75
76
|
| `summer_play` | `summer engine play` |
|
|
77
|
+
| `summer_screenshot` | `summer engine screenshot` |
|
|
76
78
|
| `store.publish` | `summer store publish` |
|
|
77
79
|
| `studio.open`, `summer_open` | `summer studio open` |
|
|
78
80
|
<!-- /shell-commands -->
|
|
@@ -42,37 +42,29 @@ Default: `my-game`. If they say "anything is fine" or similar, use `my-game` and
|
|
|
42
42
|
Two built-in options:
|
|
43
43
|
|
|
44
44
|
- `empty` — root `Node3D` only. Pure blank canvas. Best for: experimentation, when the user knows exactly what they want to build.
|
|
45
|
-
- `3d-basic` — root `Node3D` with
|
|
45
|
+
- `3d-basic` — root `Node3D` with a procedural sky on a `WorldEnvironment`, a sun with soft shadows, a tinted ground, one hero mesh and a `Camera3D` that frames it. Best for: first-time users who want something they can press Play on.
|
|
46
46
|
|
|
47
47
|
If you're not sure which fits, ask:
|
|
48
48
|
|
|
49
49
|
> "Empty (just a root node) or 3d-basic (camera, light, and a floor — you can press play immediately)?"
|
|
50
50
|
|
|
51
|
-
If the user has clearly invoked `brainstorm-game` already and the brief calls for 3D, default to `3d-basic` and mention you did. If 2D, use `empty` (
|
|
51
|
+
If the user has clearly invoked `brainstorm-game` already and the brief calls for 3D, default to `3d-basic` and mention you did. If 2D or 2.5D, use `empty`, keep its `Node3D` root and build the world with `painted-25d-world` (a painted 3D blockout under a fixed orthographic camera with sprite characters).
|
|
52
52
|
|
|
53
|
-
### 3. Create
|
|
53
|
+
### 3. Create and open it
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
summer create empty my-game
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
or
|
|
55
|
+
One command creates the project and opens it. When Summer Engine is missing it also installs it (about 660 MB): ask the user first, and pass `--yes` only with their OK (without it nothing is installed):
|
|
60
56
|
|
|
61
57
|
```
|
|
62
|
-
summer
|
|
58
|
+
summer dev --yes 3d-basic my-game
|
|
63
59
|
```
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
or `summer dev --yes empty my-game`. It writes `project.godot` and the chosen `main.tscn` (no network call for these two), opens the editor and waits until it answers.
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
summer run my-game
|
|
71
|
-
```
|
|
63
|
+
No shell in this session (a chat app)? Call `projects.create_local` with `template` and `name`, then `projects.open_local` with its `projectPath` (and `install: true` only after the user said yes to installing the engine).
|
|
72
64
|
|
|
73
|
-
Confirm the
|
|
65
|
+
Confirm the project loaded with `summer_get_project_context`. If it fails, run `summer doctor` and surface the failure to the user.
|
|
74
66
|
|
|
75
|
-
###
|
|
67
|
+
### 4. Don't keep going automatically
|
|
76
68
|
|
|
77
69
|
After scaffolding, **stop and let the user direct.** A common mistake: fire `fps-controller` or `design-mechanic` automatically because "now we make a game." Wait. The user might want to:
|
|
78
70
|
|
|
@@ -88,16 +80,16 @@ Ask: "Project is open. What do you want to build?"
|
|
|
88
80
|
| Don't | Why |
|
|
89
81
|
|---|---|
|
|
90
82
|
| Skip the name question and use `my-game` silently | The user has opinions about the directory name. Two seconds of asking saves a `mv` later. |
|
|
91
|
-
| Use `summer create 3d-basic` for a 2D game |
|
|
83
|
+
| Use `summer create 3d-basic` for a 2D game | Its light and floor fight the painted look. Use `empty` and follow `painted-25d-world`. |
|
|
92
84
|
| Default to a community template | That's `browse-templates`. This skill is specifically for "blank canvas." |
|
|
93
85
|
| Continue into `fps-controller` automatically | Most users want to brainstorm or set art direction first. Stop and ask. |
|
|
94
86
|
| Run this when the user is in an existing project | Check `summer status` or `summer_get_project_context` first. If a project is already open, the user probably wanted to modify it, not create a new one. |
|
|
95
87
|
|
|
96
88
|
## Edge cases
|
|
97
89
|
|
|
98
|
-
- **Engine not running** → that's fine. `summer
|
|
99
|
-
- **User wants 2D
|
|
100
|
-
- **Directory exists** →
|
|
90
|
+
- **Engine not running** → that's fine. `summer dev` (or `projects.open_local`) starts it; `summer create` alone doesn't need it.
|
|
91
|
+
- **User wants 2D or 2.5D** → use `empty`, keep the `Node3D` root and follow `painted-25d-world`. Use a `Node2D` root only when the user asks for a classic 2D tile or pixel game.
|
|
92
|
+
- **Directory exists** → a folder that already holds `project.godot` is just opened; one with other files is refused. Ask for a different name; don't try to overwrite.
|
|
101
93
|
|
|
102
94
|
## Closing
|
|
103
95
|
|
|
@@ -111,5 +103,6 @@ No Summer MCP tools in this session? Run each one as a command; when `summer --v
|
|
|
111
103
|
| In this skill | Command |
|
|
112
104
|
|---|---|
|
|
113
105
|
| `summer_get_project_context` | `summer engine get-project-context` |
|
|
114
|
-
| `
|
|
106
|
+
| `projects.create_local` | `summer projects create-local` |
|
|
107
|
+
| `projects.open_local` | `summer projects open-local` |
|
|
115
108
|
<!-- /shell-commands -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: skill/new-project
|
|
2
2
|
kind: skill
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.5
|
|
4
4
|
summary: "Create a blank Summer Engine project: ask for the project name and run summer create empty."
|
|
5
5
|
use_when:
|
|
6
6
|
- the user wants a fresh blank Summer Engine project — from scratch, blank canvas
|
|
@@ -20,6 +20,7 @@ compatibility:
|
|
|
20
20
|
related:
|
|
21
21
|
skills:
|
|
22
22
|
- skill/make-game
|
|
23
|
+
- skill/painted-25d-world
|
|
23
24
|
source: official
|
|
24
25
|
license: MIT
|
|
25
26
|
status: stable
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: painted-25d-world
|
|
3
|
+
description: "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."
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: 2d
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: Read Write Edit Bash summer_write_file summer_read_file summer_create_scene summer_add_node summer_set_prop summer_run_script summer_save_scene summer_screenshot summer_play summer_stop summer_get_script_errors summer_assets_generate_image summer_get_project_context summer_jobs_wait summer_import_from_url summer_call
|
|
9
|
+
paths: ["painted/**", "**/*.gdshader", "**/*.gd", "**/*.tscn"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Painted 2.5D world
|
|
13
|
+
|
|
14
|
+
The world looks like one hand-painted illustration, but it is real 3D: the player walks behind houses, enters
|
|
15
|
+
buildings and collides with walls. The trick: build the level from cheap blocks, render the blocks from one fixed
|
|
16
|
+
camera, have an image model paint over that render, then project the painting back onto the blocks from the same
|
|
17
|
+
camera. Characters are 2D sprite sheets standing in the 3D world.
|
|
18
|
+
|
|
19
|
+
## The rule
|
|
20
|
+
|
|
21
|
+
**Whenever a user asks for a 2D or 2.5D game** (top-down, RPG, cozy village, adventure, farming, dungeon,
|
|
22
|
+
side-scroller, platformer look), build it with this skill. Do not start from a 2D template or a Node2D tile map.
|
|
23
|
+
The genre playbooks in `make-game` still decide the mechanics; this skill decides how the world is made and looks.
|
|
24
|
+
|
|
25
|
+
- Top-down / three-quarter games: camera 30 degrees down, 45 degrees around (houses show two faces). Image
|
|
26
|
+
models draw "isometric" as 2:1 dimetric, which is exactly 30 degrees down; use 30 so the blockout can match a
|
|
27
|
+
generated concept.
|
|
28
|
+
- Side-scrollers: the same technique with a camera that looks along the side axis (about 10-20 degrees down,
|
|
29
|
+
0 degrees around) and pans left and right only. Paint one frame per screen-wide chunk.
|
|
30
|
+
|
|
31
|
+
Tell the user once, before the first character generation or animation: "The world blockout is cheap. Animating
|
|
32
|
+
characters costs a couple of dollars in credits and can come out with mistakes; I will check every frame." Then
|
|
33
|
+
continue. The blockout, the camera and the projection cost nothing.
|
|
34
|
+
|
|
35
|
+
## Hard rules (a playtest found each one)
|
|
36
|
+
|
|
37
|
+
1. **Scale.** Doors 2.5 m. Hero height = door height / 1.15 (2.15 m). One-storey eaves 3.5-4 m, two-storey about
|
|
38
|
+
6 m. Check the hero against a door in the first screenshot.
|
|
39
|
+
2. **The gait follows the game type.** Cozy, exploration and RPG games walk by default (about 1.8 m/s, walk cycle)
|
|
40
|
+
and run on Shift (about 4 m/s, run cycle). Action games may run by default (about 4.2 m/s, run cycle). Never
|
|
41
|
+
play the run cycle for the default gait of a cozy game. `painted_player.gd`: `move_speed`, `sprint_speed`,
|
|
42
|
+
`run_cycle_from` (3 m/s).
|
|
43
|
+
3. **Animation speed follows ground speed.** A cycle's natural speed is the ground speed at which its feet stick
|
|
44
|
+
(stride per cycle x cycles per second, scaled to the hero height). Each sheet json carries `height_m`,
|
|
45
|
+
`stride_m` and `cycles_per_s` per kind; `speed_scale = speed / natural speed`, clamped. The feet must not
|
|
46
|
+
slide. Never one fixed fps for every speed.
|
|
47
|
+
4. **Framing.** The game camera shows about 16 m across (7-8 hero heights). Clamp it inside the painting with
|
|
48
|
+
the real viewport aspect, never an assumed 16:9. The clear colour is the painting's edge colour, per location.
|
|
49
|
+
Rooms are framed whole, like a stage.
|
|
50
|
+
5. **At least one enterable building** in every village: a cut-away interior, same view direction, its own 4K
|
|
51
|
+
paint-over, door triggers both ways, a door gap of about 1.8 m. Blockout door and step slabs are hidden in the
|
|
52
|
+
game; the painting shows them.
|
|
53
|
+
6. **Eight directions** for idle, walk and run: down, up, left, right, down_left, down_right, up_left, up_right.
|
|
54
|
+
One clip per direction and animation. Mirror only where every frame holds up (never asymmetric hair, a held
|
|
55
|
+
weapon or a walking stick). The player picks the facing by 45 degree sectors.
|
|
56
|
+
7. **Blockout proportions from the concept.** Dormers sit on the roof slope (never floating); gables and roofs
|
|
57
|
+
from measured concept pixels; doors 2.5 m; a low block for every flower bed, barrel and crate.
|
|
58
|
+
8. **No long cast shadows in the paint.** "Soft short contact shadows only, no long cast shadows on the ground":
|
|
59
|
+
baked long shadows look wrong once the hero walks through them.
|
|
60
|
+
9. **Verify in a real window.** Run the game with `-- --shots=<dir>`: `painted_world.gd` walks and runs the hero
|
|
61
|
+
through `shot_plan` (add a walk through each door) and saves a JPG per step. Look at every frame.
|
|
62
|
+
10. **Generate a walk whose stride fits the default speed.** Keep the walk cycle's playback within about 1.5x
|
|
63
|
+
(`speed / natural <= 1.5`): a short-step clip played fast looks wrong. Measure the natural walk speed; if it
|
|
64
|
+
is too low, regenerate the walk clips with the brisk long-stride prompt (step 9). The plug-in walks are natural
|
|
65
|
+
at about 1.25-1.4 m/s at 2.15 m, so 1.8 m/s plays at 1.3-1.45x. Short, 4-heads-tall characters reach about
|
|
66
|
+
half a body height per cycle at most; taller proportions (6-7 heads) give longer strides.
|
|
67
|
+
|
|
68
|
+
## Steps
|
|
69
|
+
|
|
70
|
+
### 0. The project and the engine
|
|
71
|
+
|
|
72
|
+
- No project yet: `summer create empty <name>` (or write a plain `project.godot`), open it with
|
|
73
|
+
`summer run <path>`, and check that `summer_get_project_context` answers for that project.
|
|
74
|
+
- `engine_not_running` while an editor is open: the editor was started with another HOME, or the MCP is bound to
|
|
75
|
+
a different editor. Start this project's editor with `summer run <path>`, or drive it from a shell with the CLI
|
|
76
|
+
and `SUMMER_ENGINE_PROJECT=<path>` set.
|
|
77
|
+
- Image generation through Summer: always pass an `idempotencyKey` and `numImages: 1`. A call that answers
|
|
78
|
+
`outcome_unknown` (a timeout) may still run and charge: retry with the **same** key, never a new one.
|
|
79
|
+
|
|
80
|
+
### 1. Concept (one image)
|
|
81
|
+
|
|
82
|
+
`summer_assets_generate_image` with `model: "seedream-5-pro"`, `width` 2048, `height` 1152 (the largest 16:9
|
|
83
|
+
image Summer's models return; the others stop near 1024x576):
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Hand-painted illustration of <place>, rich detail, warm painterly light, seen from a high three-quarter
|
|
87
|
+
top-down camera (looking down about 30 degrees, orthographic, no perspective distortion), like a tilted
|
|
88
|
+
isometric game map. In the scene: <every object with its rough position: "three cottages around a dirt
|
|
89
|
+
plaza, a well with a small roof in the centre, a striped market stall top left, fences, round trees">.
|
|
90
|
+
Clean readable shapes, soft brush texture, no characters, no text, no UI, no border.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Pick the image the user likes. It is the art direction and the layout.
|
|
94
|
+
|
|
95
|
+
### 2. Blockout (cheap: you write it)
|
|
96
|
+
|
|
97
|
+
Write one GDScript or scene that rebuilds the concept **one to one** from the fixed camera: the same building
|
|
98
|
+
positions and footprints, roof shapes (gable, hip, dormers on the slope, thatch overhang), chimneys, the well, the
|
|
99
|
+
stall, fences, paths, trees and bushes where the concept has them. Use `MeshInstance3D` with `BoxMesh`,
|
|
100
|
+
`PrismMesh`, `CylinderMesh`, `SphereMesh` (not CSG: only MeshInstance3D nodes get the painting). Give each
|
|
101
|
+
material one flat colour (red = tile roof, yellow =
|
|
102
|
+
thatch, dark blue = slate, cream = plaster walls, grey = stone, brown = wood, tall brown slabs = doors, green =
|
|
103
|
+
grass, pink low blocks = flower beds): the colours tell the painter what each block is, and the paint-over prompt
|
|
104
|
+
repeats them as a colour key. Name door and step slabs `..._door` / `..._steps`: they are hidden in the game.
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
World (Node3D, painted_world.gd: player_path, start_location)
|
|
108
|
+
Village Node3D, painted_location.gd (paint, frame_whole = false)
|
|
109
|
+
PaintCamera Camera3D ORTHOGONAL, KEEP_WIDTH, size = frame width in metres (40 for a village square)
|
|
110
|
+
rotation_degrees = Vector3(-30, 45, 0) # 30 down, 45 around; never change it later
|
|
111
|
+
position = frame centre - forward * 60, far = 200
|
|
112
|
+
Painted Node3D every block (or blockout_builder.gd reading a spec), Ground walkable
|
|
113
|
+
Cottage Node3D, painted_location.gd (frame_whole = true), 100 m off to the side
|
|
114
|
+
PaintCamera same rotation, size 14 for a 9 x 7.5 m room
|
|
115
|
+
Painted ...
|
|
116
|
+
DoorIn Area3D, painted_door.gd (to = Cottage, spawn = a Marker3D inside the room)
|
|
117
|
+
DoorOut Area3D, painted_door.gd (to = Village, spawn = a Marker3D outside the village door)
|
|
118
|
+
GameCamera Camera3D
|
|
119
|
+
Player CharacterBody3D, painted_player.gd (sheet, sheet_json)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
One world script owns the player, the camera and the doors; locations never move the player themselves.
|
|
123
|
+
`painted_world.gd` sets the player up after every child is ready, so the node order is free.
|
|
124
|
+
|
|
125
|
+
In a `.tscn`, the paint camera line for 30 down, 45 around is (Godot writes the basis by rows; hand-written
|
|
126
|
+
columns give a wrong camera):
|
|
127
|
+
`transform = Transform3D(0.707107, -0.353553, 0.612372, 0, 0.866025, 0.5, -0.707107, -0.353553, 0.612372, cx + 36.742, cy + 30, cz + 36.742)`
|
|
128
|
+
for a frame centred on (cx, cy, cz), 60 m back along the view.
|
|
129
|
+
|
|
130
|
+
**Write the blockout as a spec** (`_building-blocks/blockout_builder.gd` documents the JSON: box, prism, cyl,
|
|
131
|
+
sphere, poly ground, invisible wall blockers). The same file drives the engine (the builder is the location's
|
|
132
|
+
`Painted` node) and an engine-free wireframe preview over the concept (`tools/preview.py`), so the fitting loop
|
|
133
|
+
needs no engine runs.
|
|
134
|
+
|
|
135
|
+
- **Gable roofs are two parts:** a wall-coloured prism for the gable triangle plus two thin slanted roof slabs
|
|
136
|
+
with an overhang. A single roof-coloured prism makes the painter paint roof on the gable wall.
|
|
137
|
+
- **Edges and water:** put invisible `wall` blockers along water and ledge edges, with gaps at pier roots and
|
|
138
|
+
doorways. Ground made from a polygon is one-sided: use the spec's `poly` (two-sided collision) or a box.
|
|
139
|
+
|
|
140
|
+
Solid things get a `StaticBody3D` and a box/cylinder shape: walls, trunks, fence posts, the well, furniture.
|
|
141
|
+
Things the player walks behind need real height (houses, trees, stalls).
|
|
142
|
+
|
|
143
|
+
**Paint richness follows blockout density.** The painter details what the blocks give it. Add low blocks for
|
|
144
|
+
flower beds, barrels, crates, benches, lanterns and window boxes wherever the concept has them; a sparse blockout
|
|
145
|
+
comes back as a sparse painting. Only truly flat detail (cobbles, rugs, grass) can stay paint-only.
|
|
146
|
+
|
|
147
|
+
**Match the concept.** Read positions straight from the concept by inverting the orthographic camera
|
|
148
|
+
(`tools/cam.py <height> <px,py> ...` does it). With the
|
|
149
|
+
concept W x H pixels, `s` = pixels per metre (W / frame width), `elev` = 30 degrees and a pixel (sx, sy) on the
|
|
150
|
+
ground (a wall's bottom corner):
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
u = (sx - W/2) / s # metres along the camera's right axis
|
|
154
|
+
v = (H/2 - sy) / (s * sin(elev)) # metres along the ground, away from the camera
|
|
155
|
+
height = dy / (s * cos(elev)) # a vertical edge dy pixels long (wall, ridge, chimney)
|
|
156
|
+
world = target + right_ground * u + far_ground * v
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Three wall-bottom corners give a footprint; the ridge gives the roof height. Draw the spec over the concept with
|
|
160
|
+
`tools/preview.py` and move blocks until the red silhouettes line up, then build it in the engine.
|
|
161
|
+
If the blockout does not match the concept, the painting will not match the blocks.
|
|
162
|
+
|
|
163
|
+
### 3. Render the blockout from the paint camera
|
|
164
|
+
|
|
165
|
+
- Play with the location's `paint` left empty: `painted_world.gd` then shows the blockout through that
|
|
166
|
+
`PaintCamera`, lit by a sun and ambient light so its faces read (an unlit blockout comes out near black).
|
|
167
|
+
`summer_screenshot` `target: "game"` captures it.
|
|
168
|
+
- Exact PNG for the painter: copy `_building-blocks/capture_paint_view.gd`, make a scene with just that node
|
|
169
|
+
(`level` = the world scene, `camera_path` = the location's camera, `size` = 2048x1152), and play it in a run
|
|
170
|
+
that renders (the editor, or a windowed run; `--headless` renders nothing). It saves
|
|
171
|
+
`res://painted/blockout.png` and quits.
|
|
172
|
+
- `summer_screenshot` `target: "scene"` renders the saved scene without running scripts: a blockout built by a
|
|
173
|
+
script or the spec builder shows nothing there.
|
|
174
|
+
|
|
175
|
+
Then upload it: `summer_call` `assets.upload_begin`, post its form fields plus the file to `uploadUrl`, then
|
|
176
|
+
`assets.upload_complete` with `publicId`, `version`, `uploadSignature` (the `signature` of the upload's answer)
|
|
177
|
+
and `format`. Its answer carries the `fileUrl`.
|
|
178
|
+
|
|
179
|
+
### 4. Paint-over (strict image to image)
|
|
180
|
+
|
|
181
|
+
**Never pass the whole concept as a reference.** Even when the blockout rebuilds it one to one, frontier edit
|
|
182
|
+
models copy the full concept and ignore the blocks. Pass a **material sheet** instead: a 2x2 grid of close-up
|
|
183
|
+
crops from the concept (for a village: clay-tile roof with a timber-framed wall, thatch, market stall with
|
|
184
|
+
cobbles, slate roof with flower beds). It carries the style and materials but no layout.
|
|
185
|
+
|
|
186
|
+
With two images (image 1 = blockout render, image 2 = material sheet), the best frontier edit model you have, 16:9,
|
|
187
|
+
the largest size (4K):
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
Image 1 is a flat-coloured 3D blockout render of <place> from a fixed game camera. Image 2 is a sheet of four
|
|
191
|
+
close-up material samples from the finished concept art (<the four samples>). Image 2 is a style and
|
|
192
|
+
material reference only: never copy its layout or composition.
|
|
193
|
+
Repaint image 1 in exactly that style, materials, light and detail. This is a strict image-to-image
|
|
194
|
+
paint-over: keep every shape, edge and position of image 1 identical, pixel-aligned. Same camera, same
|
|
195
|
+
framing. Every <building, roof, chimney, dormer, door, steps, well, stall, crate, bench, barrel, fence, tree and
|
|
196
|
+
bush> stays exactly where image 1 has it, with exactly the same silhouette and size. Do not add, remove or move
|
|
197
|
+
anything. Do not add extra props, buildings or trees. Only paint surface detail inside the existing shapes.
|
|
198
|
+
Colour key of image 1: red = clay-tile roof, yellow = golden thatch roof, dark blue = slate roof, cream =
|
|
199
|
+
timber-framed plaster walls, grey = mossy stone (chimneys, well, low walls, steps), brown = worn wood (tall
|
|
200
|
+
brown slabs on walls = wooden doors), light brown floor = cobblestone plaza, green ground = grass, green
|
|
201
|
+
spheres = round leafy tree canopies, small green domes = flowering bushes, orange = lit lanterns and fruit
|
|
202
|
+
crates, pink low blocks = dense flower beds and window boxes.
|
|
203
|
+
<Light and finish: e.g. warm golden late-afternoon light, soft short contact shadows only (no long cast shadows
|
|
204
|
+
on the ground), glowing windows, painterly near-realistic detail as in image 2: ivy on walls, moss on stones,
|
|
205
|
+
rich textures>. No characters, no text, no border.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`summer_assets_generate_image` takes one `referenceImageUrl` (the blockout render): put the material and
|
|
209
|
+
style description into the prompt in words and keep the colour key. Use `model: "seedream-5-pro"`, `width`
|
|
210
|
+
2048, `height` 1152, `numImages: 1` and an `idempotencyKey`: it holds pixel alignment well and is the only
|
|
211
|
+
Summer model that returns 2048 px.
|
|
212
|
+
|
|
213
|
+
**Check alignment before you use it.** Overlay the blockout's edges (red) on the painting
|
|
214
|
+
(`tools/overlay.py <blockout.png> <painting.png> <out.png>`) and look: roof lines,
|
|
215
|
+
wall corners, the well and the stall must sit on the red lines. Reject any painting where objects moved, were
|
|
216
|
+
added, or the framing zoomed; generate again rather than project a drifted painting.
|
|
217
|
+
|
|
218
|
+
### 5. Resolution
|
|
219
|
+
|
|
220
|
+
Painting pixels per metre must be at least the screen's pixels per metre. A 4K painting (about 5500 px) over a
|
|
221
|
+
40 m frame gives 137 px/m; a 16 m view on a 1080p-class game view needs about 96-120 px/m, so it stays sharp. A
|
|
222
|
+
2048 px painting over 32 m (64 px/m) is soft at that view. For bigger worlds use more frames, not a wider frame.
|
|
223
|
+
|
|
224
|
+
**4K through Summer:** no Summer image model returns 4K. `tools/detail4k.py <painting_2k.png> <out_dir> "<style
|
|
225
|
+
words>"` upscales the 2K paint-over 2x, cuts nine overlapping 2048x1152 tiles, runs a strict "redraw sharper,
|
|
226
|
+
pixel-aligned" image-to-image pass on each with `seedream-5-pro` and blends them back. Nine generations; the
|
|
227
|
+
alignment holds.
|
|
228
|
+
|
|
229
|
+
### 6. Projection in the engine
|
|
230
|
+
|
|
231
|
+
Copy `_building-blocks/paint_projection.gdshader`, `painted_location.gd`, `painted_world.gd`,
|
|
232
|
+
`painted_door.gd` and `painted_player.gd` to `res://painted/`. Set each location's `paint`. On `_ready` a
|
|
233
|
+
location puts one `ShaderMaterial` on every mesh under its `Painted`; the shader takes each surface point's
|
|
234
|
+
position in that location's paint camera frame as its UV. No UV unwrapping, no baking.
|
|
235
|
+
|
|
236
|
+
- Keep the scene's tonemap **Linear**, exposure 1, no glow, no fog: the painting already holds the light.
|
|
237
|
+
- Import the painting lossless (Import dock: Compress Mode Lossless, mipmaps on); VRAM compression smears it.
|
|
238
|
+
- Verify: `_building-blocks/paintcam_check.gd` renders the painted world through a `PaintCamera` to a PNG; it
|
|
239
|
+
must match the painting. Then play and look at the real window (hard rule 9).
|
|
240
|
+
|
|
241
|
+
### 7. Camera rules
|
|
242
|
+
|
|
243
|
+
- The game camera has the paint camera's direction and only **moves** (follows the player). With an orthographic
|
|
244
|
+
camera, moving never reveals a surface the painting did not see. Never orbit or tilt it: turned views show the
|
|
245
|
+
painting's mistakes (a painted chimney next to the real one, roof edges smeared on the ground).
|
|
246
|
+
- Outdoors it shows about 16 m across; rooms are framed whole. `painted_world.gd` sizes and clamps it with the
|
|
247
|
+
real viewport aspect and sets the clear colour to the painting's edge colour.
|
|
248
|
+
- More world = more frames. Every frame uses the same direction, its own paint camera position and painting.
|
|
249
|
+
Paint neighbouring frames with an overlap strip so the seams match.
|
|
250
|
+
|
|
251
|
+
### 8. Interiors
|
|
252
|
+
|
|
253
|
+
Every village gets at least one enterable building. Each interior is its own location far away (for example 100 m
|
|
254
|
+
off to the side) with the **same** camera direction and a frame that holds the whole room with its back walls
|
|
255
|
+
(14 m for a 9 x 7.5 m room; 12 m cut the walls off), `frame_whole = true`. Lower
|
|
256
|
+
the two walls nearest the camera to knee height (a dollhouse cut-away) and leave a door gap of about 1.8 m.
|
|
257
|
+
Blockout, render, paint over (its own 4K paint-over, the same rules and colour key: warm floorboards, plaster,
|
|
258
|
+
beams, fireplace, bed, shelves, rug, "keep the area outside the room plain flat dark") and project exactly like
|
|
259
|
+
the outside. `painted_door.gd` triggers go both ways; put each spawn marker clear of the other door's trigger.
|
|
260
|
+
|
|
261
|
+
### 9. Characters
|
|
262
|
+
|
|
263
|
+
1. **Ready-made:** use the painted plug-in characters first: a man, a woman, the man with a sword and an old man,
|
|
264
|
+
8 directions, idle, walk and run (`hero_m_sword`: idle and walk). They live in the public repo
|
|
265
|
+
`SummerEngine/painted-characters`, pinned at commit `c70dae1b4043656ad23d5ab6d76fe992f593b6ba`. For `<id>`, import
|
|
266
|
+
`https://raw.githubusercontent.com/SummerEngine/painted-characters/c70dae1b4043656ad23d5ab6d76fe992f593b6ba/characters/<id>/<file>`
|
|
267
|
+
for the three files `<id>_sheet.png`, `<id>_sheet.json` and `<id>_frames.tres` into `res://characters/<id>/`
|
|
268
|
+
(`summer_import_from_url`; the `.tres` expects that path), then set `sheet` = `<id>_sheet.png` and
|
|
269
|
+
`sheet_json` = `<id>_sheet.json` on `painted_player.gd`. With a shell, `git clone` the repo and copy
|
|
270
|
+
`characters/` to the project root. Need a different look: make one.
|
|
271
|
+
2. **New character:** generate an 8-pose turnaround (or two 4-pose sheets) in the world's style on flat pure
|
|
272
|
+
green:
|
|
273
|
+
```
|
|
274
|
+
Character turnaround sheet in the art style of <the world>: <character>. Draw the same character 8 times,
|
|
275
|
+
same size, feet on one baseline: facing down toward the viewer, down-left, left, up-left, up (back view),
|
|
276
|
+
up-right, right, down-right. Seen from a high three-quarter top-down camera. Plain flat pure green
|
|
277
|
+
background (#00FF00), no ground, no shadows, no text.
|
|
278
|
+
```
|
|
279
|
+
Crop each pose, pad it to 9:16 with the same green, upload it, then `summer_call` `assets.generate_video`
|
|
280
|
+
(`model: "minimax-h3-max"`, `aspectRatio: "9:16"`, 5 s, an `idempotencyKey`): one clip per direction and
|
|
281
|
+
animation:
|
|
282
|
+
```
|
|
283
|
+
The character, <facing>, walks in place on the spot with a brisk, purposeful walk cycle: long confident strides, heel to toe, the front leg reaching far forward and the back leg pushing far back, arms swinging strongly opposite the legs, upright posture. The character
|
|
284
|
+
stays exactly centred at the same size and never moves across the frame or turns. Static locked camera, no
|
|
285
|
+
zoom. The plain flat pure green background stays perfectly flat and unchanged. Seamless loop.
|
|
286
|
+
```
|
|
287
|
+
That is the walk prompt for a default walk (a plain "steady, simple walk cycle" takes short steps and must be
|
|
288
|
+
over-sped). For a longer stride still: "walks in place on the spot with a long-legged power walk: very wide
|
|
289
|
+
steps, at each step the front heel lands far ahead and the back foot pushes off far behind, legs nearly fully
|
|
290
|
+
extended front to back, arms swinging wide, a quick purposeful pace."
|
|
291
|
+
Idle: "stands still in a relaxed idle: gentle breathing, one blink, feet planted". Run: "runs in place".
|
|
292
|
+
3. **Clip to sheet** (host with a shell and ffmpeg): key out the green by colour, take one cycle (skip the
|
|
293
|
+
first second), sample 8 frames evenly, crop every frame of every clip with the **same** box so the feet stay
|
|
294
|
+
on one line, and tile them into one sheet: one row per animation and direction (`idle_down`,
|
|
295
|
+
`walk_up_left`, `run_right`, ...). Write the json beside it: `{"cell_w", "cell_h", "frames", "rows",
|
|
296
|
+
"fps": {"idle", "walk", "run"}, "height_m", "stride_m": {"walk", "run"}, "cycles_per_s": {"walk", "run"}}`.
|
|
297
|
+
Measure once per kind: `stride_m` = how far a planted foot slides back during one cycle at `height_m`,
|
|
298
|
+
`cycles_per_s` = cycles per second at the sheet's fps. Look at every frame; regenerate a clip with a broken
|
|
299
|
+
frame.
|
|
300
|
+
Without video: `summer_call` `assets.generate_sprite_sheet` (8-frame walk from one picture, per direction).
|
|
301
|
+
4. **In the game:** `painted_player.gd` makes an `AnimatedSprite3D`: Y-billboard, unshaded, alpha cut (so painted
|
|
302
|
+
walls hide the character), height stretched by `1 / cos(camera pitch)`, 8 facings by 45 degree sectors (a
|
|
303
|
+
missing diagonal falls back to its side row), the game-type gait (hard rule 2), animation speed = speed /
|
|
304
|
+
natural speed.
|
|
305
|
+
Spawn points 0.5 m or more away from walls, or the flat card cuts into them.
|
|
306
|
+
|
|
307
|
+
### 10. Weapons
|
|
308
|
+
|
|
309
|
+
- **Variant sheet (best look):** edit the turnaround so the character holds the weapon, then animate the clips
|
|
310
|
+
again. One extra sheet per weapon. Never mirror a sheet with a held weapon.
|
|
311
|
+
- **Held sprite layer (cheap):** a second `Sprite3D` child with the weapon, a per-direction offset and draw order
|
|
312
|
+
(behind the body when facing up). Good for many weapons; the hand will not wrap around the grip.
|
|
313
|
+
|
|
314
|
+
## Common mistakes
|
|
315
|
+
|
|
316
|
+
- **The whole concept as a reference:** the painting copies the concept and ignores the blocks, even when the
|
|
317
|
+
blockout matches it. Pass a 2x2 material sheet cropped from the concept.
|
|
318
|
+
- **A sparse blockout:** the painting comes back sparse. Add low blocks for flower beds, crates, barrels, benches.
|
|
319
|
+
- **35 degrees against a generated concept:** generated "isometric" art is 30 degrees down; the blocks will not fit.
|
|
320
|
+
- **A tiny or giant hero:** check the hero against a door (door = hero x 1.15) in the first screenshot.
|
|
321
|
+
- **Sliding feet or the wrong gait:** speed_scale = speed / natural; cozy games walk by default and run on Shift.
|
|
322
|
+
- **4096 px asked from Summer's image models:** refused. 2048x1152 with seedream-5-pro, then the tiled 4K pass.
|
|
323
|
+
- **A new idempotencyKey after a timeout:** pays twice. Retry with the same key; keep numImages 1.
|
|
324
|
+
- **An unlit blockout capture, CSG blocks, a one-sided polygon ground, no water blockers:** see steps 2 and 3.
|
|
325
|
+
- **Long baked shadows:** they lie on the ground while the hero walks through them. Contact shadows only.
|
|
326
|
+
- **Floating dormers, blockout door slabs left visible:** dormers on the slope; hide door and step slabs.
|
|
327
|
+
- **Rotating the game camera:** shows painted detail on the wrong surfaces. Translate only.
|
|
328
|
+
- **Filmic/ACES tonemap or lights on painted meshes:** colours shift. Unshaded material, Linear tonemap.
|
|
329
|
+
- **Perspective camera:** moving it reveals hidden faces. Use orthographic.
|
|
330
|
+
- **Assuming a 16:9 window:** the clamp shows past the painting in the editor's game view. Use the real aspect.
|
|
331
|
+
|
|
332
|
+
## Optional: Blender route
|
|
333
|
+
|
|
334
|
+
If the host has Blender, `_building-blocks/blender-route.md` bakes the same projection into ordinary UVs and
|
|
335
|
+
exports glTF; use it when the scene must ship as plain textured meshes.
|
|
336
|
+
|
|
337
|
+
## See also
|
|
338
|
+
|
|
339
|
+
- `make-game` (genre mechanics), `concept-art`, `sprite-sheet`, `scene-composition`
|
|
340
|
+
|
|
341
|
+
<!-- shell-commands: generated from the operation catalog by npm run generate:registry; do not edit by hand -->
|
|
342
|
+
## From a shell
|
|
343
|
+
|
|
344
|
+
No Summer MCP tools in this session? Run each one as a command; when `summer --version` is missing or below 4.0, use `npx -y summer-engine@latest` in place of `summer`. Fields are flags in kebab-case (`--scene-path res://main.tscn`) or one `--input '<json>'`, and `summer ops describe <op>` prints the exact input. The `summer-cli` skill has the rest.
|
|
345
|
+
|
|
346
|
+
| In this skill | Command |
|
|
347
|
+
|---|---|
|
|
348
|
+
| `summer_assets_generate_image` | `summer assets generate-image` |
|
|
349
|
+
| `assets.generate_video` | `summer assets generate-video` |
|
|
350
|
+
| `assets.upload_begin` | `summer assets upload-begin` |
|
|
351
|
+
| `assets.upload_complete` | `summer assets upload-complete` |
|
|
352
|
+
| `summer_add_node` | `summer engine add-node` |
|
|
353
|
+
| `summer_create_scene` | `summer engine create-scene` |
|
|
354
|
+
| `summer_get_project_context` | `summer engine get-project-context` |
|
|
355
|
+
| `summer_get_script_errors` | `summer engine get-script-errors` |
|
|
356
|
+
| `summer_import_from_url` | `summer engine import-from-url` |
|
|
357
|
+
| `summer_play` | `summer engine play` |
|
|
358
|
+
| `summer_read_file` | `summer engine read-file` |
|
|
359
|
+
| `summer_run_script` | `summer engine run-script` |
|
|
360
|
+
| `summer_save_scene` | `summer engine save-scene` |
|
|
361
|
+
| `summer_screenshot` | `summer engine screenshot` |
|
|
362
|
+
| `summer_set_prop` | `summer engine set-prop` |
|
|
363
|
+
| `summer_stop` | `summer engine stop` |
|
|
364
|
+
| `summer_write_file` | `summer engine write-file` |
|
|
365
|
+
| `summer_jobs_wait` | `summer jobs wait` |
|
|
366
|
+
<!-- /shell-commands -->
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Blender route: bake the projection into UVs
|
|
2
|
+
|
|
3
|
+
Use this only when the host has Blender and the level must ship as plain textured meshes (no projection shader).
|
|
4
|
+
It gives the same picture as `paint_projection.gdshader`.
|
|
5
|
+
|
|
6
|
+
1. Build the blockout in Blender with the same orthographic camera: rotation (60, 0, 45) degrees in Blender's
|
|
7
|
+
Z-up axes (90 - 30 down, 45 around), `ortho_scale` = frame width in metres. Render it (Workbench, studio light,
|
|
8
|
+
outlines on) at 2048x1152 or larger.
|
|
9
|
+
2. Paint over the render (SKILL.md step 4) and resize the painting to the exact render size.
|
|
10
|
+
3. Project: for every mesh, add one UV layer and set each loop's UV to the camera-view position of its vertex.
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import bpy
|
|
14
|
+
from bpy_extras.object_utils import world_to_camera_view
|
|
15
|
+
|
|
16
|
+
scene, cam = bpy.context.scene, bpy.data.objects["PaintCamera"]
|
|
17
|
+
for ob in bpy.data.collections["blockout"].objects:
|
|
18
|
+
if ob.type != "MESH":
|
|
19
|
+
continue
|
|
20
|
+
me = ob.data
|
|
21
|
+
uv = me.uv_layers.new(name="proj")
|
|
22
|
+
uv.active = uv.active_render = True
|
|
23
|
+
for loop in me.loops:
|
|
24
|
+
p = world_to_camera_view(scene, cam, ob.matrix_world @ me.vertices[loop.vertex_index].co)
|
|
25
|
+
uv.data[loop.index].uv = (p.x, p.y)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
With an orthographic camera the UVs are exact per vertex, so no subdivision is needed.
|
|
29
|
+
4. One material for all meshes: the painting as base colour (texture extension EXTEND). Export glTF with separate
|
|
30
|
+
textures. Name solid objects `<name>-col` so the engine adds collision on import.
|
|
31
|
+
5. In the engine, override every imported mesh with an unshaded `StandardMaterial3D` that uses the painting, and
|
|
32
|
+
import the painting lossless. Blender (x, y, z) is engine (x, z, -y): rebuild the paint camera from the same
|
|
33
|
+
30 / 45 degree direction with `keep_aspect` KEEP_WIDTH and `size` = the ortho scale.
|