summer-engine 3.3.0 → 3.4.1
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 +2 -2
- package/.claude-plugin/plugin.json +4 -2
- package/.codex-plugin/plugin.json +5 -3
- package/.cursor-plugin/plugin.json +4 -2
- package/.factory-plugin/plugin.json +4 -2
- package/.opencode/INSTALL.md +8 -8
- package/.opencode/plugins/summer.js +2 -2
- package/AGENTS.md +7 -7
- package/CHANGELOG.md +50 -0
- package/GEMINI.md +1 -1
- package/NOTICE +1 -1
- package/README.md +32 -35
- package/assets/api-docs.json.gz +0 -0
- package/assets/autopilot/run.sh +2 -2
- package/assets/navigation/web-routes.json +1 -1
- package/commands/gameskill.md +2 -2
- package/commands/summer.md +25 -25
- package/dist/cli/commands/install.d.ts +10 -0
- package/dist/cli/commands/install.js +55 -10
- package/dist/cli/commands/open.d.ts +1 -1
- package/dist/cli/commands/run.d.ts +1 -1
- package/dist/cli/commands/run.js +1 -1
- package/dist/cli/commands/skills.js +2 -2
- package/dist/cli/commands/tool.d.ts +7 -0
- package/dist/cli/commands/tool.js +36 -1
- package/dist/core/api-client.d.ts +5 -6
- package/dist/core/api-client.js +12 -15
- package/dist/core/auth.js +2 -2
- package/dist/core/capabilities/asset-import.d.ts +0 -1
- package/dist/core/capabilities/camera-view.d.ts +1 -1
- package/dist/core/capabilities/camera-view.js +2 -2
- package/dist/core/capabilities/capture-gameplay.d.ts +69 -0
- package/dist/core/capabilities/capture-gameplay.js +283 -0
- package/dist/core/capabilities/connect-signal.d.ts +1 -2
- package/dist/core/capabilities/connect-signal.js +1 -2
- package/dist/core/capabilities/console-read.d.ts +2 -2
- package/dist/core/capabilities/console-read.js +2 -2
- package/dist/core/capabilities/creator.js +1 -1
- package/dist/core/capabilities/doctor.d.ts +9 -1
- package/dist/core/capabilities/doctor.js +47 -4
- package/dist/core/capabilities/engine-receipt.d.ts +5 -7
- package/dist/core/capabilities/engine-receipt.js +7 -9
- package/dist/core/capabilities/engine-run.d.ts +4 -0
- package/dist/core/capabilities/engine-run.js +33 -5
- package/dist/core/capabilities/export-engine-version.d.ts +15 -0
- package/dist/core/capabilities/export-engine-version.js +24 -0
- package/dist/core/capabilities/export-game.d.ts +9 -1
- package/dist/core/capabilities/export-game.js +115 -39
- package/dist/core/capabilities/export-presets.d.ts +1 -1
- package/dist/core/capabilities/export-presets.js +1 -1
- package/dist/core/capabilities/fabricate-mesh.d.ts +2 -3
- package/dist/core/capabilities/fabricate-mesh.js +2 -3
- package/dist/core/capabilities/frame-quality.d.ts +4 -4
- package/dist/core/capabilities/frame-quality.js +4 -4
- package/dist/core/capabilities/grep.d.ts +1 -1
- package/dist/core/capabilities/grep.js +1 -1
- package/dist/core/capabilities/image-generation.d.ts +9 -0
- package/dist/core/capabilities/image-generation.js +19 -1
- package/dist/core/capabilities/navigation/open.d.ts +1 -1
- package/dist/core/capabilities/navigation/open.js +1 -1
- package/dist/core/capabilities/navigation/render-product-map.js +1 -1
- package/dist/core/capabilities/navigation/targets.js +2 -2
- package/dist/core/capabilities/placement-batch.d.ts +1 -1
- package/dist/core/capabilities/placement-batch.js +2 -2
- package/dist/core/capabilities/play-determinism.d.ts +1 -1
- package/dist/core/capabilities/play-determinism.js +1 -1
- package/dist/core/capabilities/publish-build.d.ts +15 -2
- package/dist/core/capabilities/publish-build.js +78 -28
- package/dist/core/capabilities/publish-download.d.ts +1 -2
- package/dist/core/capabilities/publish-download.js +2 -3
- package/dist/core/capabilities/replace-node.d.ts +1 -3
- package/dist/core/capabilities/replace-node.js +1 -3
- package/dist/core/capabilities/runtime-control.d.ts +5 -7
- package/dist/core/capabilities/runtime-control.js +7 -9
- package/dist/core/capabilities/scene-batch.d.ts +1 -1
- package/dist/core/capabilities/scene-batch.js +1 -1
- package/dist/core/capabilities/scene-kind.js +1 -1
- package/dist/core/capabilities/scene-readback.d.ts +3 -4
- package/dist/core/capabilities/scene-readback.js +3 -4
- package/dist/core/capabilities/scene-script.d.ts +2 -2
- package/dist/core/capabilities/scene-script.js +2 -2
- package/dist/core/capabilities/seeing/shot-store.d.ts +1 -1
- package/dist/core/capabilities/seeing/shot-store.js +1 -1
- package/dist/core/capabilities/summer-bundle.d.ts +2 -3
- package/dist/core/capabilities/summer-bundle.js +2 -3
- package/dist/core/capabilities/surface-snap.d.ts +1 -1
- package/dist/core/capabilities/surface-snap.js +1 -1
- package/dist/core/capabilities/tool-dispatch.js +11 -1
- package/dist/core/capabilities/ui-control.d.ts +1 -2
- package/dist/core/capabilities/ui-control.js +1 -2
- package/dist/core/capabilities/world-snapshot.d.ts +1 -1
- package/dist/core/capabilities/world-snapshot.js +1 -1
- package/dist/core/capability-skew.d.ts +2 -3
- package/dist/core/capability-skew.js +4 -5
- package/dist/core/config.js +2 -2
- package/dist/core/engine-install.d.ts +16 -0
- package/dist/core/engine-install.js +32 -2
- package/dist/core/feedback/client.js +1 -1
- package/dist/core/hosted-mcp.d.ts +115 -0
- package/dist/core/hosted-mcp.js +164 -0
- package/dist/core/launch-posture.d.ts +6 -3
- package/dist/core/launch-posture.js +18 -5
- package/dist/core/library-read.js +1 -2
- package/dist/core/templates.d.ts +1 -2
- package/dist/core/templates.js +1 -2
- package/dist/mcp/hosted-mount.d.ts +13 -59
- package/dist/mcp/hosted-mount.js +24 -30
- package/dist/mcp/server.d.ts +2 -2
- package/dist/mcp/server.js +5 -4
- package/dist/mcp/tools/creator-tools.js +14 -4
- package/dist/mcp/tools/debug-tools.js +1 -1
- package/dist/mcp/tools/generate-tools.js +19 -9
- package/dist/mcp/tools/navigation-tools.d.ts +1 -1
- package/dist/mcp/tools/navigation-tools.js +1 -1
- package/dist/mcp/tools/spatial-tools.js +1 -1
- package/dist/mcp/tools/visual-tools.js +2 -2
- package/dist/mcp/tools/with-engine.d.ts +1 -2
- package/dist/mcp/tools/with-engine.js +1 -2
- package/gemini-extension.json +3 -1
- package/hooks/session-start.sh +2 -2
- package/integrations/README.md +70 -76
- package/integrations/claude/README.md +0 -3
- package/integrations/codex/README.md +1 -2
- package/integrations/copilot-jetbrains/README.md +1 -1
- package/integrations/cursor/README.md +1 -2
- package/integrations/factory/README.md +15 -11
- package/integrations/mistral-vibe/README.md +1 -1
- package/integrations/opencode/README.md +1 -1
- package/integrations/roo-code/README.md +1 -1
- package/integrations/rovo-dev/README.md +1 -1
- package/integrations/trae/README.md +1 -1
- package/integrations/windsurf/README.md +3 -3
- package/library/references/collaborative-protocol/collaborative-protocol.md +5 -5
- package/library/references/gd-style/gd-style.md +4 -6
- package/library/references/godot-version/godot-version.md +3 -3
- package/library/references/headless-routing/headless-routing.md +2 -2
- package/library/references/mcp-fresh-chat-playbook/mcp-fresh-chat-playbook.md +2 -2
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -16
- package/library/references/product-map/product-map.md +1 -1
- package/library/references/public-surface-language/public-surface-language.md +1 -1
- package/library/references/summer-folder/summer-folder.md +1 -1
- package/library/skills/3d-lighting/SKILL.md +4 -4
- package/library/skills/README.md +11 -9
- package/library/skills/adaptive-music/SKILL.md +7 -7
- package/library/skills/ai-characters-in-games/SKILL.md +1 -1
- package/library/skills/ambient-bed/SKILL.md +12 -14
- package/library/skills/animated-loop/SKILL.md +42 -42
- package/library/skills/animation-tree/SKILL.md +6 -6
- package/library/skills/art-direction/SKILL.md +8 -11
- package/library/skills/asset-strategy/SKILL.md +3 -3
- package/library/skills/audio-direction/SKILL.md +8 -10
- package/library/skills/auto-fire-targeting/SKILL.md +4 -3
- package/library/skills/bounded-engine-runs/SKILL.md +95 -0
- package/library/skills/bounded-engine-runs/resource.yaml +29 -0
- package/library/skills/brainstorm-game/SKILL.md +5 -5
- package/library/skills/brainstorming/SKILL.md +9 -15
- package/library/skills/celeste-momentum-platforming/SKILL.md +8 -13
- package/library/skills/celeste-momentum-platforming/resource.yaml +1 -1
- package/library/skills/character-animation-wiring/SKILL.md +2 -2
- package/library/skills/character-model/SKILL.md +15 -26
- package/library/skills/character-movement/SKILL.md +1 -1
- package/library/skills/character-movement/references/movement-3d.md +1 -1
- package/library/skills/character-portrait/SKILL.md +4 -4
- package/library/skills/cinematic-cutscene/SKILL.md +38 -38
- package/library/skills/combat-basics/SKILL.md +1 -1
- package/library/skills/compatibility-renderer-traps/SKILL.md +78 -0
- package/library/skills/compatibility-renderer-traps/resource.yaml +28 -0
- package/library/skills/concept-art/SKILL.md +4 -4
- package/library/skills/create-asset-sheet/SKILL.md +12 -31
- package/library/skills/debug/SKILL.md +5 -4
- package/library/skills/debugging-game-feel/SKILL.md +1 -4
- package/library/skills/debugging-game-feel/resource.yaml +1 -1
- package/library/skills/design-level/SKILL.md +5 -5
- package/library/skills/design-mechanic/SKILL.md +6 -6
- package/library/skills/design-npc/SKILL.md +8 -15
- package/library/skills/diagnosing-perf-regressions/SKILL.md +5 -10
- package/library/skills/dispatching-parallel-agents/SKILL.md +1 -19
- package/library/skills/environment-kit/SKILL.md +5 -5
- package/library/skills/export-and-ship/SKILL.md +25 -24
- package/library/skills/fabricating-assets/SKILL.md +1 -1
- package/library/skills/facial-and-lipsync/SKILL.md +5 -5
- package/library/skills/fps-controller/SKILL.md +17 -16
- package/library/skills/fps-controller/resource.yaml +0 -2
- package/library/skills/game-feel/SKILL.md +6 -7
- package/library/skills/gameskill/SKILL.md +3 -3
- package/library/skills/gdscript-patterns/SKILL.md +3 -3
- package/library/skills/generate-motion/SKILL.md +5 -22
- package/library/skills/godogen-visual-proof-game-generation/SKILL.md +72 -90
- package/library/skills/godogen-visual-proof-game-generation/resource.yaml +0 -1
- package/library/skills/headless-scripting/SKILL.md +8 -8
- package/library/skills/headless-scripting/resource.yaml +1 -0
- package/library/skills/in-game-purchases/SKILL.md +123 -118
- package/library/skills/in-game-purchases/resource.yaml +2 -2
- package/library/skills/instantiate-asset-pack/SKILL.md +7 -3
- package/library/skills/investigating-bugs/SKILL.md +3 -11
- package/library/skills/investigating-bugs/condition-based-waiting.md +0 -10
- package/library/skills/investigating-bugs/root-cause-tracing.md +0 -8
- package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +15 -15
- package/library/skills/lumera-single-image-scene-reconstruction/resource.yaml +0 -1
- package/library/skills/make-game/SKILL.md +3 -5
- package/library/skills/make-game/references/2d-platformer.md +1 -1
- package/library/skills/multiplayer-project/SKILL.md +1 -1
- package/library/skills/multiplayer-testing/SKILL.md +4 -4
- package/library/skills/music-track/SKILL.md +40 -38
- package/library/skills/new-project/SKILL.md +4 -6
- package/library/skills/organic-model/SKILL.md +9 -9
- package/library/skills/pixel-art/SKILL.md +6 -6
- package/library/skills/play/SKILL.md +3 -4
- package/library/skills/playtesting-a-feature/SKILL.md +4 -6
- package/library/skills/procedural-animation/SKILL.md +10 -11
- package/library/skills/prop-model/SKILL.md +4 -4
- package/library/skills/psx-retro-rendering/SKILL.md +20 -20
- package/library/skills/psx-retro-rendering/resource.yaml +2 -3
- package/library/skills/realtime-wet-surfaces/SKILL.md +15 -15
- package/library/skills/realtime-wet-surfaces/resource.yaml +1 -2
- package/library/skills/remote-deploy/SKILL.md +20 -21
- package/library/skills/retarget/SKILL.md +19 -23
- package/library/skills/running-in-the-cloud/SKILL.md +5 -5
- package/library/skills/scene-composition/SKILL.md +5 -5
- package/library/skills/scene-hierarchy-design/SKILL.md +3 -3
- package/library/skills/scene-hierarchy-design/resource.yaml +0 -1
- package/library/skills/scene-scripting/SKILL.md +3 -3
- package/library/skills/scene-to-level/SKILL.md +28 -31
- package/library/skills/skill-create/SKILL.md +1 -1
- package/library/skills/skill-improve/SKILL.md +9 -9
- package/library/skills/skill-test/SKILL.md +10 -10
- package/library/skills/skintokens-auto-rigging/SKILL.md +18 -18
- package/library/skills/skintokens-auto-rigging/resource.yaml +3 -3
- package/library/skills/skybox-panorama/SKILL.md +8 -9
- package/library/skills/sound-effect/SKILL.md +19 -19
- package/library/skills/spatial-placement/SKILL.md +2 -2
- package/library/skills/spatial-placement/references/kit-placement-tools.md +12 -22
- package/library/skills/sprite-sheet/SKILL.md +10 -10
- package/library/skills/summer-analytics/SKILL.md +3 -3
- package/library/skills/summer-friends/SKILL.md +10 -10
- package/library/skills/summer-leaderboards/SKILL.md +6 -6
- package/library/skills/summer-match-results/SKILL.md +13 -13
- package/library/skills/summer-matchmaking/SKILL.md +11 -11
- package/library/skills/summer-parties/SKILL.md +9 -9
- package/library/skills/summer-player-data/SKILL.md +12 -12
- package/library/skills/summer-store/SKILL.md +6 -6
- package/library/skills/summer-world-chat/SKILL.md +9 -9
- package/library/skills/summer-world-saves/SKILL.md +7 -7
- package/library/skills/text-to-motion/rigging-for-text-motion.md +1 -1
- package/library/skills/tileable-texture/SKILL.md +1 -1
- package/library/skills/trailer-shot/SKILL.md +36 -36
- package/library/skills/tune-performance/SKILL.md +13 -13
- package/library/skills/tune-performance/resource.yaml +1 -1
- package/library/skills/ui-graphics/SKILL.md +7 -7
- package/library/skills/use-widget-asset/SKILL.md +7 -7
- package/library/skills/using-summer/SKILL.md +5 -7
- package/library/skills/vehicle-model/SKILL.md +6 -7
- package/library/skills/vehicle-model/resource.yaml +2 -2
- package/library/skills/verification-before-completion/SKILL.md +5 -6
- package/library/skills/vfx-dissolve/SKILL.md +4 -4
- package/library/skills/vfx-fire/SKILL.md +6 -6
- package/library/skills/vfx-fire/_building-blocks/additive-billboard-particles.md +3 -3
- package/library/skills/vfx-hit-spark/SKILL.md +4 -4
- package/library/skills/vfx-hit-spark/_building-blocks/additive-billboard-particles.md +3 -3
- package/library/skills/vfx-lightning/SKILL.md +5 -5
- package/library/skills/vfx-lightning/_building-blocks/additive-billboard-particles.md +3 -3
- package/library/skills/vfx-lightning/_building-blocks/trauma-shake-snippet.md +9 -3
- package/library/skills/vfx-magic-glow/SKILL.md +4 -4
- package/library/skills/vfx-magic-glow/_building-blocks/additive-billboard-particles.md +3 -3
- package/library/skills/vfx-muzzle-flash/SKILL.md +5 -5
- package/library/skills/vfx-muzzle-flash/_building-blocks/additive-billboard-particles.md +3 -3
- package/library/skills/vfx-muzzle-flash/_building-blocks/trauma-shake-snippet.md +9 -3
- package/library/skills/vfx-smoke/SKILL.md +5 -5
- package/library/skills/vfx-water-ripple/SKILL.md +2 -2
- package/library/skills/vfx-water-ripple/_building-blocks/additive-billboard-particles.md +3 -3
- package/library/skills/voice-line/SKILL.md +9 -9
- package/library/skills/web-compatibility-look/resource.yaml +1 -0
- package/library/skills/world-building-3d/references/spatial-tools.md +2 -2
- package/library/skills/writing-plans/SKILL.md +4 -4
- package/library/skills/writing-skills/SKILL.md +8 -8
- package/library/tools/capture-gameplay/resource.yaml +73 -0
- package/library/tools/creator-publish/resource.yaml +4 -4
- package/library/tools/creator-releases/resource.yaml +5 -5
- package/library/tools/generate-image/resource.yaml +15 -1
- package/library/tools/publish-build/resource.yaml +6 -2
- package/package.json +1 -1
- package/registry/generated/aliases.json +1 -0
- package/registry/generated/counts.json +3 -3
- package/registry/generated/gemini-extension.json +3 -1
- package/registry/generated/index.json +248 -135
- package/registry/generated/marketplace.claude.json +2 -2
- package/registry/generated/plugin.claude.json +4 -2
- 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/skills-index.md +11 -9
- package/registry/generated/skills-registry.json +33 -6
- package/registry/schemas/domains.json +1 -1
|
@@ -21,7 +21,7 @@ This is the widest capability surface you have, and it is the one you are least
|
|
|
21
21
|
<engine-binary> --headless --disable-crash-handler --path <project-dir> -s res://<script>.gd
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
**Always pass `--disable-crash-handler` on an agent-driven run.** Summer's handler shells out to `atos` from inside a signal handler; when anything does go wrong it turns a clean failure into a hang or a cascade
|
|
24
|
+
**Always pass `--disable-crash-handler` on an agent-driven run.** Summer's handler shells out to `atos` from inside a signal handler; when anything does go wrong it turns a clean failure into a hang or a cascade of crashes.
|
|
25
25
|
|
|
26
26
|
### Lint before you boot
|
|
27
27
|
|
|
@@ -53,7 +53,7 @@ Exit codes lie in both directions here.
|
|
|
53
53
|
<EXTREMELY-IMPORTANT>
|
|
54
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.
|
|
55
55
|
|
|
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)
|
|
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
58
|
If you genuinely believe the user needs to see the editor, ask them first.
|
|
59
59
|
</EXTREMELY-IMPORTANT>
|
|
@@ -73,12 +73,12 @@ If neither is available (an older engine build that predates `engineBinaryPath`,
|
|
|
73
73
|
| Linux | `~/.summer/engine/summer-linux-x86_64`, or `$SUMMER_ENGINE_BINARY` (see `running-in-the-cloud`) |
|
|
74
74
|
|
|
75
75
|
<EXTREMELY-IMPORTANT>
|
|
76
|
-
There is no `godot` binary on a Summer user's machine. `godot --headless`, `godot4`, `/usr/local/bin/godot` — none of these exist. A command built on that name fails with "command not found"
|
|
76
|
+
There is no `godot` binary on a Summer user's machine. `godot --headless`, `godot4`, `/usr/local/bin/godot` — none of these exist. A command built on that name fails with "command not found" for every user, and no amount of retrying changes it.
|
|
77
77
|
</EXTREMELY-IMPORTANT>
|
|
78
78
|
|
|
79
79
|
### The script must extend `SceneTree` or `MainLoop`
|
|
80
80
|
|
|
81
|
-
`-s` does not load an arbitrary script.
|
|
81
|
+
`-s` does not load an arbitrary script. The engine instantiates it as the process's main loop, and rejects anything that is not one.
|
|
82
82
|
|
|
83
83
|
```gdscript
|
|
84
84
|
extends SceneTree
|
|
@@ -92,7 +92,7 @@ func _initialize():
|
|
|
92
92
|
|
|
93
93
|
Always call `quit()`. There is no other exit.
|
|
94
94
|
|
|
95
|
-
**The trap:** a script extending `Node` (the reflex, since almost all GDScript does) is a wedge, not an error. The engine's rejection path calls `OS.alert()`, and on macOS that is an `NSAlert` `runModal` with **no headless guard
|
|
95
|
+
**The trap:** a script extending `Node` (the reflex, since almost all GDScript does) is a wedge, not an error. The engine's rejection path calls `OS.alert()`, and on macOS that is an `NSAlert` `runModal` with **no headless guard**. The process blocks forever on a modal dialog that has no window to appear in. You get **no output at all** and a hung process that must be killed. Measured: five orphaned processes accumulated in one session before the cause was found.
|
|
96
96
|
|
|
97
97
|
If a headless run produces zero output and never returns, check the first line of your script before you check anything else.
|
|
98
98
|
|
|
@@ -262,13 +262,13 @@ Measured on 0.5.55: `port 6550 -> 6551`, new token, editor still alive on 6550 a
|
|
|
262
262
|
|
|
263
263
|
So on a shipped build: run `--import` against a throwaway copy where you can, warn the user before running it against their open project, and tell them to restart the editor afterwards if their agent connection drops.
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
A later engine fix stops batch-mode invocations (`--import`, `--summer-verify`, `--export-*`, `-s`, `--headless`, `--quit-after`) from publishing. On a build with that fix this warning does not apply; if you cannot tell which build is installed, follow the precautions above. Plain `--headless -s` never started the server on any build, so everything else in this skill is unaffected.
|
|
266
266
|
</EXTREMELY-IMPORTANT>
|
|
267
267
|
|
|
268
268
|
Two lifecycle facts that decide the shape of every headless run:
|
|
269
269
|
|
|
270
270
|
- **There is a hard work-completion floor between 3 and 5 seconds.** Fresh project, 8 small PNGs, editor killed at N seconds: at **3s, 0/8 imports landed in 10/10 cycles** — it boots, gets killed mid-scan, and accomplishes nothing. At **5s, 8/8 landed every cycle.** Never give an import a 3-second budget.
|
|
271
|
-
- **`--headless --editor` is not a filesystem watcher.** It never notices files created after boot — 6 assets added 12s in, 45s wait, 0 imported. The rescan is driven by `NOTIFICATION_APPLICATION_FOCUS_IN
|
|
271
|
+
- **`--headless --editor` is not a filesystem watcher.** It never notices files created after boot — 6 assets added 12s in, 45s wait, 0 imported. The rescan is driven by `NOTIFICATION_APPLICATION_FOCUS_IN`, and headless never fires a focus event. A long-lived headless editor serves a boot-time snapshot forever.
|
|
272
272
|
|
|
273
273
|
Both ends of the lifecycle are broken, differently: short runs do no work, long ones go stale. **Boot → act → exit is the only shape that works today.**
|
|
274
274
|
|
|
@@ -379,7 +379,7 @@ Four measured instances of the same shape:
|
|
|
379
379
|
|
|
380
380
|
1. Write the script with `summer_write_file` (or your own shell) into the project.
|
|
381
381
|
2. Get the binary from `summer_get_project_context` → `engineBinaryPath`.
|
|
382
|
-
3. Run it. **Read stdout
|
|
382
|
+
3. Run it. **Read stdout and stderr**: your `print()` output is on stdout, script errors are on stderr, and a script that failed to parse still exits 0.
|
|
383
383
|
4. Verify the artifact exists on disk and check the `ResourceSaver.save()` return value. "The script ran" is not "the resource was written".
|
|
384
384
|
5. If you wrote raw asset files, run `--import`.
|
|
385
385
|
6. Delete throwaway scripts. Do not leave `probe_temp_3.gd` in a user's project.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: in-game-purchases
|
|
3
|
-
description: "Sell items for Sparks
|
|
3
|
+
description: "Sell items for Sparks in a game shop via the Summer purchase sheet: checkout, results, not enough Sparks, inventory unlocks, authority grants, store policy."
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: gameplay
|
|
@@ -11,14 +11,19 @@ paths: ["**/*.gd"]
|
|
|
11
11
|
# In-game purchases with Sparks
|
|
12
12
|
|
|
13
13
|
Sparks are Summer's currency. A game never takes money, never holds a
|
|
14
|
-
balance and never approves a payment. It asks Summer
|
|
15
|
-
purchase sheet over the game, and the game reacts to the
|
|
16
|
-
result.
|
|
14
|
+
balance and never approves a payment. It asks Summer for a checkout, Summer
|
|
15
|
+
shows its own purchase sheet over the game, and the game reacts to the
|
|
16
|
+
authoritative result.
|
|
17
17
|
|
|
18
18
|
| The player wants to | Call | Validated by |
|
|
19
19
|
| --- | --- | --- |
|
|
20
20
|
| buy an item with Sparks they have | `Summer.client.store.request_checkout(lines)` | the Summer ledger (debit) |
|
|
21
|
-
| buy Sparks because they are short |
|
|
21
|
+
| buy Sparks because they are short | no game call: the player gets Sparks in the Summer app | the Summer app |
|
|
22
|
+
|
|
23
|
+
The engine has no call that sells Sparks from inside the game. When a
|
|
24
|
+
checkout fails with `insufficient_funds`, tell the player they need more
|
|
25
|
+
Sparks and that they can get them in the Summer app, then let them press Buy
|
|
26
|
+
again.
|
|
22
27
|
|
|
23
28
|
## When to sell with Sparks
|
|
24
29
|
|
|
@@ -28,9 +33,9 @@ result. There are two calls and they follow the same shape:
|
|
|
28
33
|
game.
|
|
29
34
|
- Do not invent your own currency that is bought with money. *Why:* Summer
|
|
30
35
|
can only refund, protect and pay you out for Sparks purchases.
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
- Open the shop only from an explicit shop or buy button. *Why:* the Summer
|
|
37
|
+
sheet interrupts play; surprise payment prompts read as pressure and get
|
|
38
|
+
games reported.
|
|
34
39
|
|
|
35
40
|
## Rules and the reason for each
|
|
36
41
|
|
|
@@ -38,66 +43,66 @@ result. There are two calls and they follow the same shape:
|
|
|
38
43
|
`Summer.client.items` shows the player owns it. *Why:* the receipt proves
|
|
39
44
|
the debit; the inventory projection is what the platform guarantees the
|
|
40
45
|
player owns, including after a crash or on another device.
|
|
41
|
-
2. **Never send prices
|
|
42
|
-
|
|
43
|
-
client-supplied price is exactly what a
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
2. **Never send prices or amounts.** The game passes an offer ID and a
|
|
47
|
+
quantity (`SummerCheckoutLine.create(offer_id, quantity)`). *Why:* the
|
|
48
|
+
platform prices everything; a client-supplied price is exactly what a
|
|
49
|
+
cheater edits.
|
|
50
|
+
3. **One call is one purchase.** Every `request_checkout` creates a new
|
|
51
|
+
identity. Never call again to "retry" an unknown outcome
|
|
52
|
+
(`SummerCheckoutOperation.is_outcome_unknown()`). *Why:* the first request
|
|
53
|
+
may already be charged; the SDK recovers it and delivers the result on the
|
|
54
|
+
signal.
|
|
55
|
+
4. **Handle results in `checkout_status_changed`, and deduplicate by
|
|
49
56
|
`request_id` plus `version`.** Connect normally (not deferred) before
|
|
50
|
-
requesting.
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
requesting. To draw a checkout panel, read `get_checkout_statuses()` and
|
|
58
|
+
`has_pending_checkouts()` instead of keeping your own list. *Why:* results
|
|
59
|
+
can arrive after a restart or twice after a crash; a synchronous handler is
|
|
60
|
+
how the SDK knows the result was delivered.
|
|
61
|
+
5. **Treat `manual_review` and `pending` as not done.** *Why:* the platform
|
|
53
62
|
has not decided yet; showing success or failure would be a guess.
|
|
54
63
|
6. **Check readiness and hide what is unavailable.**
|
|
55
|
-
`check_checkout_readiness()` and `
|
|
56
|
-
a `SummerResult`. *Why:* editor play,
|
|
57
|
-
do not offer purchases; a dead button
|
|
64
|
+
`check_checkout_readiness()` (buying) and `check_browse_readiness()`
|
|
65
|
+
(listing with `list_items()`) return a `SummerResult`. *Why:* editor play,
|
|
66
|
+
guest sessions and older Summer apps do not offer purchases; a dead button
|
|
67
|
+
is worse than no button.
|
|
58
68
|
|
|
59
69
|
## Result states
|
|
60
70
|
|
|
61
|
-
|
|
71
|
+
`checkout_status_changed(status: SummerCheckoutStatus)` delivers a status
|
|
72
|
+
whose `state` is one of:
|
|
62
73
|
|
|
63
74
|
| State | Meaning | What the game does |
|
|
64
75
|
| --- | --- | --- |
|
|
65
76
|
| `awaiting_approval` | the Summer sheet is open | nothing; optionally dim the shop |
|
|
66
|
-
| `pending` |
|
|
67
|
-
| `purchased` | done; Sparks debited
|
|
77
|
+
| `pending` | the debit is in progress | show "processing" |
|
|
78
|
+
| `purchased` | done; Sparks debited, `status.receipt` is set | refresh items and unlock from inventory |
|
|
68
79
|
| `declined` | the player closed the sheet | return to the shop quietly |
|
|
69
|
-
| `expired` | the sheet
|
|
70
|
-
| `rejected` | refused; read `error_code` |
|
|
80
|
+
| `expired` | the sheet timed out | same as declined |
|
|
81
|
+
| `rejected` | refused; read `error_code` | `insufficient_funds`: "Not enough Sparks. Get Sparks in the Summer app." Other codes: "The purchase was not completed." |
|
|
71
82
|
| `manual_review` | platform is checking it | "We are confirming this purchase" |
|
|
72
|
-
| `refunded` | Sparks only: a credited purchase was refunded or charged back (`full_refund`, `dispute_lost`) | nothing to undo; Summer already took the Sparks back. Refresh any balance display |
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
(only adults with a saved age can buy Sparks). Show a short message and no
|
|
77
|
-
retry button. *Why:* both limits are platform policy; retrying changes nothing.
|
|
84
|
+
`status.is_terminal()` tells you whether the state can still change. Unknown
|
|
85
|
+
future `error_code` values never mean success.
|
|
78
86
|
|
|
79
|
-
The operation returned by
|
|
80
|
-
`purchased
|
|
81
|
-
or `sparks_purchase_declined`. The status signal is the one to build UI on.
|
|
87
|
+
The operation returned by `request_checkout` also completes: ok on
|
|
88
|
+
`purchased`, a failure otherwise. The status signal is the one to build UI on.
|
|
82
89
|
|
|
83
90
|
## Minimal complete example
|
|
84
91
|
|
|
85
92
|
```gdscript
|
|
86
93
|
extends Node
|
|
87
|
-
## A one-item shop. Buys `offer_id
|
|
88
|
-
## Sparks through the Summer sheet, then they press Buy again.
|
|
94
|
+
## A one-item shop. Buys `offer_id` and unlocks from inventory.
|
|
89
95
|
|
|
90
96
|
@export var offer_id := "offer_sword"
|
|
91
97
|
@export var definition_id := "item_sword"
|
|
92
|
-
@export var price_sparks := 250 # display only; the platform charges its own price
|
|
93
98
|
|
|
94
99
|
signal message(text: String)
|
|
95
100
|
var _seen := {}
|
|
96
101
|
|
|
97
102
|
func _ready() -> void:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
store.
|
|
103
|
+
if Summer.client == null:
|
|
104
|
+
return # not running as a player's game
|
|
105
|
+
Summer.client.store.checkout_status_changed.connect(_on_checkout)
|
|
101
106
|
Summer.client.items.refreshed.connect(_sync_owned)
|
|
102
107
|
_sync_owned()
|
|
103
108
|
|
|
@@ -108,13 +113,7 @@ func buy() -> void:
|
|
|
108
113
|
var lines: Array[SummerCheckoutLine] = [SummerCheckoutLine.create(offer_id, 1)]
|
|
109
114
|
Summer.client.store.request_checkout(lines) # result arrives in _on_checkout
|
|
110
115
|
|
|
111
|
-
func
|
|
112
|
-
if not Summer.client.store.check_sparks_purchase_readiness().ok:
|
|
113
|
-
message.emit("Get Sparks from the Summer app.")
|
|
114
|
-
return
|
|
115
|
-
Summer.client.store.request_sparks_purchase(price_sparks) # hint only
|
|
116
|
-
|
|
117
|
-
func _first_time(status) -> bool:
|
|
116
|
+
func _first_time(status: SummerCheckoutStatus) -> bool:
|
|
118
117
|
var key := "%s:%d" % [status.request_id, status.version]
|
|
119
118
|
if _seen.has(key):
|
|
120
119
|
return false
|
|
@@ -129,7 +128,7 @@ func _on_checkout(status: SummerCheckoutStatus) -> void:
|
|
|
129
128
|
Summer.client.items.refresh() # ownership comes from inventory
|
|
130
129
|
&"rejected":
|
|
131
130
|
if status.error_code == &"insufficient_funds":
|
|
132
|
-
message.emit("Not enough Sparks.
|
|
131
|
+
message.emit("Not enough Sparks. Get Sparks in the Summer app, then buy again.")
|
|
133
132
|
else:
|
|
134
133
|
message.emit("The purchase was not completed.")
|
|
135
134
|
&"manual_review":
|
|
@@ -137,84 +136,91 @@ func _on_checkout(status: SummerCheckoutStatus) -> void:
|
|
|
137
136
|
&"declined", &"expired":
|
|
138
137
|
pass
|
|
139
138
|
|
|
140
|
-
func _on_sparks(status: SummerSparksPurchaseStatus) -> void:
|
|
141
|
-
if not _first_time(status):
|
|
142
|
-
return
|
|
143
|
-
match status.state:
|
|
144
|
-
&"purchased":
|
|
145
|
-
message.emit("%d Sparks added." % status.receipt.sparks_credited)
|
|
146
|
-
&"rejected":
|
|
147
|
-
message.emit("The payment did not go through.")
|
|
148
|
-
&"manual_review":
|
|
149
|
-
message.emit("We are confirming your payment.")
|
|
150
|
-
|
|
151
139
|
func _sync_owned() -> void:
|
|
152
140
|
if Summer.client.items.has_owned_definition(definition_id):
|
|
153
141
|
message.emit("Sword unlocked.") # the only place the item is granted
|
|
154
142
|
```
|
|
155
143
|
|
|
156
|
-
After Sparks are added the player presses Buy again. That is a new checkout
|
|
157
|
-
and Summer shows it again. *Why:* the player confirms each spend separately.
|
|
158
|
-
|
|
159
144
|
## Multiplayer: granting an effect on a dedicated authority
|
|
160
145
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
146
|
+
Anything the Sparks buy ("Grow now", "Summon rain") is a checkout for an
|
|
147
|
+
item, and on a server the authority must never grant it because a client says
|
|
148
|
+
it paid. *Why:* a client message is the one thing a cheater controls.
|
|
149
|
+
|
|
150
|
+
Model the effect as a catalog item with instance ownership (each purchase is a
|
|
151
|
+
separate owned item, not a stack). *Why:* a stackable item shares one owned
|
|
152
|
+
item ID across purchases, so the ID could not tell two purchases apart.
|
|
153
|
+
|
|
154
|
+
The client checks out; the receipt's `items[i].owned_item_ids` are the owned
|
|
155
|
+
items. The client sends the authority only an owned item ID. The authority:
|
|
156
|
+
|
|
157
|
+
1. reads that player's inventory with
|
|
158
|
+
`Summer.authority.items.inventory_for_session(session)` and checks the
|
|
159
|
+
item is there, owned, and of the right definition;
|
|
160
|
+
2. checks its own record of redeemed item IDs, kept in the player's secret
|
|
161
|
+
player data (`Summer.authority.player_data`), so the item grants once per
|
|
162
|
+
player in every world;
|
|
163
|
+
3. writes the new record, and applies the effect only after that write
|
|
164
|
+
succeeds.
|
|
176
165
|
|
|
177
166
|
```gdscript
|
|
178
|
-
# On the dedicated authority.
|
|
167
|
+
# On the dedicated authority.
|
|
168
|
+
const EFFECT_DEFINITION := "item_grow_now"
|
|
169
|
+
|
|
179
170
|
func redeem(session: SummerSession, owned_item_id: String) -> void:
|
|
171
|
+
var inv := Summer.authority.items.inventory_for_session(session)
|
|
172
|
+
var read: SummerResult = await inv.get_result_or_completed_signal()
|
|
173
|
+
if not read.ok:
|
|
174
|
+
return # unavailable: the client may ask again later
|
|
175
|
+
var item: SummerInventoryItem = null
|
|
176
|
+
for candidate in inv.items:
|
|
177
|
+
if candidate.get_owned_item_id() == owned_item_id:
|
|
178
|
+
item = candidate
|
|
179
|
+
if item == null or not item.is_owned() or item.get_definition_id() != EFFECT_DEFINITION:
|
|
180
|
+
return # not owned by this player: never grant
|
|
181
|
+
|
|
182
|
+
var load_op := Summer.authority.player_data.load(session)
|
|
183
|
+
var loaded: SummerResult = await load_op.get_result_or_completed_signal()
|
|
184
|
+
if not loaded.ok:
|
|
185
|
+
return
|
|
186
|
+
var data: Dictionary = load_op.secret_record.data
|
|
187
|
+
var redeemed: Dictionary = data.get("redeemed", {})
|
|
180
188
|
if redeemed.has(owned_item_id):
|
|
181
189
|
return # a repeated message grants once
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
var
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
189
|
-
redeemed[owned_item_id] = op.command_id # record, apply, then save the world
|
|
190
|
+
redeemed[owned_item_id] = true
|
|
191
|
+
data["redeemed"] = redeemed
|
|
192
|
+
var save_id := "redeem_" + owned_item_id.sha256_text().substr(0, 40)
|
|
193
|
+
var commit := Summer.authority.player_data.commit_secret(session, save_id, data)
|
|
194
|
+
var saved: SummerResult = await commit.get_result_or_completed_signal()
|
|
195
|
+
if not saved.ok:
|
|
196
|
+
return # retryable: commit again with the same save_id
|
|
190
197
|
apply_grow_now(session)
|
|
191
198
|
```
|
|
192
199
|
|
|
193
|
-
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
- Apply the effect when the
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
- The save ID comes from the owned item ID. *Why:* resending the same save ID
|
|
201
|
+
with the same content returns the earlier commit (`commit.replayed`), so a
|
|
202
|
+
retry after a timeout records the redemption once.
|
|
203
|
+
- Apply the effect when the commit succeeds even if `commit.replayed` is true
|
|
204
|
+
and the effect is not in your world yet. *Why:* a replay means the
|
|
205
|
+
redemption was recorded earlier, but your world may have crashed before it
|
|
206
|
+
applied the effect.
|
|
207
|
+
- The engine has no call that uses up an owned item. The item stays in the
|
|
208
|
+
player's inventory after it is redeemed; the redeemed list is what stops a
|
|
209
|
+
second grant. Show redeemed items as used in your UI.
|
|
202
210
|
|
|
203
211
|
## Idempotency
|
|
204
212
|
|
|
205
|
-
The SDK generates the request ID and replays it across transport
|
|
206
|
-
app restarts; the platform
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
message or play an effect twice.
|
|
213
|
+
The SDK generates the checkout request ID and replays it across transport
|
|
214
|
+
failures and app restarts; the platform debits a checkout once per request.
|
|
215
|
+
Your only job is the `request_id:version` dedupe above, so a replayed signal
|
|
216
|
+
does not show a message or play an effect twice.
|
|
210
217
|
|
|
211
218
|
## Per-surface behaviour
|
|
212
219
|
|
|
213
|
-
- **Summer Games app on iOS:** a native Summer sheet over the game.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
- **Web:** the same sheet in the page, paid with Stripe.
|
|
220
|
+
- **Summer Games app on iOS:** a native Summer sheet over the game.
|
|
221
|
+
- **Summer desktop app:** an overlay sheet; the result returns to the game on
|
|
222
|
+
the signal.
|
|
223
|
+
- **Web:** the same sheet in the page.
|
|
218
224
|
- **Editor play and local runs:** readiness is `unavailable`. Build the
|
|
219
225
|
unavailable path first.
|
|
220
226
|
|
|
@@ -222,31 +228,30 @@ The game code is identical on every surface.
|
|
|
222
228
|
|
|
223
229
|
## Testing
|
|
224
230
|
|
|
225
|
-
- Test against Summer staging, which runs
|
|
226
|
-
|
|
227
|
-
builds. *Why:* no real money moves and results are identical to production.
|
|
231
|
+
- Test against Summer staging, which runs in sandbox mode. *Why:* no real
|
|
232
|
+
money moves and results are identical to production.
|
|
228
233
|
- Walk every state: decline the sheet, let it expire, buy with too few
|
|
229
|
-
Sparks,
|
|
230
|
-
pending and relaunch; the result must still arrive once.
|
|
234
|
+
Sparks, get Sparks in the Summer app, then buy the item. Kill the game while
|
|
235
|
+
a checkout is pending and relaunch; the result must still arrive once.
|
|
231
236
|
- Verify the unlock comes from `items.refreshed`, not from the checkout
|
|
232
237
|
signal.
|
|
233
238
|
|
|
234
239
|
## Store policy notes
|
|
235
240
|
|
|
236
241
|
- Apple requires In-App Purchase for digital goods and currency sold inside
|
|
237
|
-
iOS apps. Summer's iOS sheet
|
|
238
|
-
web prices or "cheaper on the web" text inside the game. *Why:* it
|
|
239
|
-
the Summer app removed from the App Store for every game.
|
|
242
|
+
iOS apps. Summer's iOS sheet and app handle this; never add your own payment
|
|
243
|
+
links, web prices or "cheaper on the web" text inside the game. *Why:* it
|
|
244
|
+
can get the Summer app removed from the App Store for every game.
|
|
240
245
|
- Randomized paid rewards must disclose their odds before purchase (Apple and
|
|
241
246
|
most regions require it).
|
|
242
247
|
- Say what a purchase gives in plain words next to the price.
|
|
243
248
|
|
|
244
249
|
## Availability
|
|
245
250
|
|
|
246
|
-
`request_checkout`
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
`request_checkout`, `list_items`, `Summer.client.items`,
|
|
252
|
+
`Summer.authority.items.inventory_for_session` and `Summer.authority.player_data`
|
|
253
|
+
ship in the engine today. Buying Sparks inside the game does not: players get
|
|
254
|
+
Sparks in the Summer app.
|
|
250
255
|
|
|
251
256
|
## See also
|
|
252
257
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
id: skill/in-game-purchases
|
|
2
2
|
kind: skill
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
summary: "Sell items for Sparks
|
|
4
|
+
summary: "Sell items for Sparks in a game shop via the Summer purchase sheet: checkout, results, not enough Sparks, inventory unlocks, authority grants, store policy."
|
|
5
5
|
use_when:
|
|
6
6
|
- "adding a shop, buy button or paid item to a Summer game and wiring request_checkout"
|
|
7
|
-
- "
|
|
7
|
+
- "the player does not have enough Sparks (checkout rejected with insufficient_funds) and the game should tell them how to buy more Sparks"
|
|
8
8
|
- "deciding whether an item should be sold for Sparks, or handling pending, declined, expired, rejected or manual_review purchase results"
|
|
9
9
|
do_not_use_when:
|
|
10
10
|
- "designing multiplayer state ownership unrelated to purchases (use multiplayer-state)"
|
|
@@ -27,7 +27,7 @@ For wiring individual widget slices (9-slice panels, progress bars, toggles), th
|
|
|
27
27
|
|
|
28
28
|
- User wants a single slice → import it directly as a `Sprite2D` (or `use-widget-asset` if it's a UI widget).
|
|
29
29
|
- User wants to **generate** a new pack → `create-asset-sheet`.
|
|
30
|
-
- User wants to apply a slice as a material/texture on a 3D mesh → not the pack flow; see `
|
|
30
|
+
- User wants to apply a slice as a material/texture on a 3D mesh → not the pack flow; see `asset-strategy`.
|
|
31
31
|
|
|
32
32
|
## Pack JSON shape
|
|
33
33
|
|
|
@@ -98,12 +98,15 @@ Delegate the actual wiring (percentage-to-pixel conversion, node-specific props)
|
|
|
98
98
|
|
|
99
99
|
## Examples
|
|
100
100
|
|
|
101
|
+
Both examples are `summer_batch` arguments; `scenePath` names the scene that receives the nodes.
|
|
102
|
+
|
|
101
103
|
### Example 1 — Standalone slice import
|
|
102
104
|
|
|
103
105
|
Pack has one non-composite slice, `crate_wooden`, no widget metadata. Place it at scene origin:
|
|
104
106
|
|
|
105
107
|
```json
|
|
106
108
|
{
|
|
109
|
+
"scenePath": "res://scenes/level.tscn",
|
|
107
110
|
"ops": [
|
|
108
111
|
{
|
|
109
112
|
"op": "AddNode",
|
|
@@ -138,6 +141,7 @@ Pack has a composite parent `settings_panel` (filtered out) plus three children:
|
|
|
138
141
|
|
|
139
142
|
```json
|
|
140
143
|
{
|
|
144
|
+
"scenePath": "res://ui/settings.tscn",
|
|
141
145
|
"ops": [
|
|
142
146
|
{
|
|
143
147
|
"op": "AddNode",
|
|
@@ -224,7 +228,7 @@ Pack has a composite parent `settings_panel` (filtered out) plus three children:
|
|
|
224
228
|
|
|
225
229
|
After this, hand `panel_bg` and `apply_button` to `use-widget-asset` to set `patch_margin_*` from their `widget.frameMargins`.
|
|
226
230
|
|
|
227
|
-
Note the ops format: `position` is the **
|
|
231
|
+
Note the ops format: `position` is the **engine variant string** `"Vector2(0, 0)"`, not a JSON object. `z_index` is a bare integer. This is the format Summer Engine expects — see `../../references/mcp-tools-reference/mcp-tools-reference.md`.
|
|
228
232
|
|
|
229
233
|
## Failure modes
|
|
230
234
|
|
|
@@ -240,4 +244,4 @@ Note the ops format: `position` is the **Godot string** `"Vector2(0, 0)"`, not a
|
|
|
240
244
|
|
|
241
245
|
- `create-asset-sheet` — production side; how the pack was made.
|
|
242
246
|
- `use-widget-asset` — wiring an individual widget slice (NinePatchRect, TextureProgressBar geometry).
|
|
243
|
-
- `
|
|
247
|
+
- `asset-strategy` — broader find-or-generate -> import -> apply flow.
|
|
@@ -230,9 +230,9 @@ If you catch yourself thinking:
|
|
|
230
230
|
|
|
231
231
|
**ALL of these mean: STOP. Return to Phase 1.**
|
|
232
232
|
|
|
233
|
-
**If 3+ fixes failed:** Question the architecture (
|
|
233
|
+
**If 3+ fixes failed:** Question the architecture (Phase 4, step 5)
|
|
234
234
|
|
|
235
|
-
## the
|
|
235
|
+
## Signals From the User That You're Doing It Wrong
|
|
236
236
|
|
|
237
237
|
**Watch for these redirections:**
|
|
238
238
|
- "Is that not happening?" - You assumed without verifying
|
|
@@ -274,7 +274,7 @@ If systematic investigation reveals issue is truly environmental, timing-depende
|
|
|
274
274
|
3. Implement appropriate handling (retry, timeout, error message)
|
|
275
275
|
4. Add monitoring/logging for future investigation
|
|
276
276
|
|
|
277
|
-
**But:**
|
|
277
|
+
**But:** most "no root cause" cases are incomplete investigation.
|
|
278
278
|
|
|
279
279
|
## Supporting Techniques
|
|
280
280
|
|
|
@@ -288,11 +288,3 @@ These techniques are part of systematic debugging and available in this director
|
|
|
288
288
|
- **verification-before-completion** - Verify fix worked before claiming success
|
|
289
289
|
- **debug** - The Summer-specific triage loop (script errors → console → debugger → probe)
|
|
290
290
|
- **playtesting-a-feature** - When the fix is a gameplay behaviour that has to be walked
|
|
291
|
-
|
|
292
|
-
## Real-World Impact
|
|
293
|
-
|
|
294
|
-
From debugging sessions:
|
|
295
|
-
- Systematic approach: 15-30 minutes to fix
|
|
296
|
-
- Random fixes approach: 2-3 hours of thrashing
|
|
297
|
-
- First-time fix rate: 95% vs 40%
|
|
298
|
-
- New bugs introduced: Near zero vs common
|
|
@@ -79,8 +79,6 @@ async function waitFor<T>(
|
|
|
79
79
|
}
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
See `condition-based-waiting-example.ts` in this directory for complete implementation with domain-specific helpers (`waitForEvent`, `waitForEventCount`, `waitForEventMatch`) from actual debugging session.
|
|
83
|
-
|
|
84
82
|
## Common Mistakes
|
|
85
83
|
|
|
86
84
|
**Bad: Polling too fast:** `setTimeout(check, 1)` - wastes CPU
|
|
@@ -105,11 +103,3 @@ await new Promise(r => setTimeout(r, 200)); // Then: wait for timed behavior
|
|
|
105
103
|
1. First wait for triggering condition
|
|
106
104
|
2. Based on known timing (not guessing)
|
|
107
105
|
3. Comment explaining WHY
|
|
108
|
-
|
|
109
|
-
## Real-World Impact
|
|
110
|
-
|
|
111
|
-
From debugging session (2025-10-03):
|
|
112
|
-
- Fixed 15 flaky tests across 3 files
|
|
113
|
-
- Pass rate: 60% → 100%
|
|
114
|
-
- Execution time: 40% faster
|
|
115
|
-
- No more race conditions
|
|
@@ -153,11 +153,3 @@ digraph principle {
|
|
|
153
153
|
**Before operation:** Log before the dangerous operation, not after it fails
|
|
154
154
|
**Include context:** Directory, cwd, environment variables, timestamps
|
|
155
155
|
**Capture stack:** `new Error().stack` shows complete call chain
|
|
156
|
-
|
|
157
|
-
## Real-World Impact
|
|
158
|
-
|
|
159
|
-
From debugging session (2025-10-03):
|
|
160
|
-
- Found root cause through 5-level trace
|
|
161
|
-
- Fixed at source (getter validation)
|
|
162
|
-
- Added 4 layers of defense
|
|
163
|
-
- 1847 tests passed, zero pollution
|