summer-engine 1.3.2 → 1.4.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/plugin.json +59 -0
- package/.codex-plugin/plugin.json +38 -0
- package/.cursor-plugin/plugin.json +42 -0
- package/.mcp.json +8 -0
- package/.opencode/plugins/summer.js +49 -0
- package/README.md +13 -0
- package/dist/lib/skills-registry.d.ts +80 -0
- package/dist/lib/skills-registry.js +172 -0
- package/gemini-extension.json +21 -0
- package/hooks/hooks-cursor.json +21 -0
- package/hooks/hooks.json +31 -0
- package/hooks/pre-commit-doctor.sh +123 -0
- package/hooks/run-hook.cmd +23 -0
- package/hooks/session-start.sh +120 -0
- package/marketplace.json +24 -0
- package/package.json +9 -1
- package/skills/_tests/specs/peer-to-peer-multiplayer.md +99 -0
- package/skills/asset-pipeline/asset-strategy/SKILL.md +8 -0
- package/skills/catalog.yaml +82 -0
- package/skills/character-controllers/fps-controller/SKILL.md +27 -0
- package/skills/multiplayer-and-networking/peer-to-peer-multiplayer/SKILL.md +378 -0
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +20 -0
- package/skills/scene-and-project/make-game/SKILL.md +10 -0
- package/skills/scene-and-project/scene-composition/SKILL.md +8 -0
- package/skills/ui-and-ux/ui-basics/SKILL.md +28 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Summer Engine — Pre-commit doctor hook (OPT-IN)
|
|
3
|
+
#
|
|
4
|
+
# Event: PreToolUse (matcher: Bash, if: "Bash(git commit*)")
|
|
5
|
+
# Purpose: Run `summer doctor` before any git commit Claude is about to make.
|
|
6
|
+
# Block the commit on FAIL. Allow with warnings on WARN.
|
|
7
|
+
#
|
|
8
|
+
# Status: OPT-IN. Not registered in the Summer plugin manifest by default.
|
|
9
|
+
#
|
|
10
|
+
# To enable, add to ~/.claude/settings.json (or .claude/settings.json):
|
|
11
|
+
#
|
|
12
|
+
# {
|
|
13
|
+
# "hooks": {
|
|
14
|
+
# "PreToolUse": [
|
|
15
|
+
# {
|
|
16
|
+
# "matcher": "Bash",
|
|
17
|
+
# "hooks": [
|
|
18
|
+
# {
|
|
19
|
+
# "type": "command",
|
|
20
|
+
# "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-commit-doctor.sh",
|
|
21
|
+
# "if": "Bash(git commit*)",
|
|
22
|
+
# "timeout": 15
|
|
23
|
+
# }
|
|
24
|
+
# ]
|
|
25
|
+
# }
|
|
26
|
+
# ]
|
|
27
|
+
# }
|
|
28
|
+
# }
|
|
29
|
+
#
|
|
30
|
+
# Then: chmod +x ${CLAUDE_PLUGIN_ROOT}/hooks/pre-commit-doctor.sh
|
|
31
|
+
#
|
|
32
|
+
# Input: JSON on stdin: { tool_name, tool_input: { command, ... }, ... }
|
|
33
|
+
# Output: On FAIL: stderr explanation, exit 2 (blocks commit).
|
|
34
|
+
# On WARN: stderr warnings, exit 0 (allows commit).
|
|
35
|
+
# On PASS or no `summer` CLI: silent, exit 0.
|
|
36
|
+
#
|
|
37
|
+
# Portability: bash 3.2+, POSIX-friendly. jq optional.
|
|
38
|
+
|
|
39
|
+
set +e
|
|
40
|
+
|
|
41
|
+
INPUT=$(cat)
|
|
42
|
+
|
|
43
|
+
# ---------- Parse the command ----------
|
|
44
|
+
COMMAND=""
|
|
45
|
+
if command -v jq >/dev/null 2>&1; then
|
|
46
|
+
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
47
|
+
fi
|
|
48
|
+
if [ -z "$COMMAND" ]; then
|
|
49
|
+
COMMAND=$(printf '%s' "$INPUT" \
|
|
50
|
+
| grep -oE '"command"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
51
|
+
| head -1 \
|
|
52
|
+
| sed 's/^"command"[[:space:]]*:[[:space:]]*"//;s/"$//')
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# ---------- Bail early if not a git commit ----------
|
|
56
|
+
if ! printf '%s' "$COMMAND" | grep -qE '^[[:space:]]*git[[:space:]]+commit'; then
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# ---------- Bail if `summer` CLI missing ----------
|
|
61
|
+
if ! command -v summer >/dev/null 2>&1; then
|
|
62
|
+
# Don't block — user may have installed via plugin only.
|
|
63
|
+
exit 0
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# ---------- Run doctor ----------
|
|
67
|
+
DOCTOR_OUT=$(summer doctor --json 2>/dev/null)
|
|
68
|
+
if [ -z "$DOCTOR_OUT" ]; then
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ---------- Parse status ----------
|
|
73
|
+
HAS_FAIL=0
|
|
74
|
+
HAS_WARN=0
|
|
75
|
+
FAIL_MSGS=""
|
|
76
|
+
WARN_MSGS=""
|
|
77
|
+
|
|
78
|
+
if command -v jq >/dev/null 2>&1; then
|
|
79
|
+
FAIL_MSGS=$(printf '%s' "$DOCTOR_OUT" \
|
|
80
|
+
| jq -r '.checks[]? | select(.status == "FAIL") | " - " + (.name // "?") + ": " + (.message // "")' 2>/dev/null)
|
|
81
|
+
WARN_MSGS=$(printf '%s' "$DOCTOR_OUT" \
|
|
82
|
+
| jq -r '.checks[]? | select(.status == "WARN") | " - " + (.name // "?") + ": " + (.message // "")' 2>/dev/null)
|
|
83
|
+
[ -n "$FAIL_MSGS" ] && HAS_FAIL=1
|
|
84
|
+
[ -n "$WARN_MSGS" ] && HAS_WARN=1
|
|
85
|
+
else
|
|
86
|
+
# Fallback: substring sniffing
|
|
87
|
+
if printf '%s' "$DOCTOR_OUT" | grep -q '"status"[[:space:]]*:[[:space:]]*"FAIL"'; then
|
|
88
|
+
HAS_FAIL=1
|
|
89
|
+
FAIL_MSGS=$(printf '%s' "$DOCTOR_OUT" \
|
|
90
|
+
| grep -oE '"status"[[:space:]]*:[[:space:]]*"FAIL"[^}]*"message"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
91
|
+
| sed -E 's/.*"message"[[:space:]]*:[[:space:]]*"([^"]*)"/ - \1/')
|
|
92
|
+
fi
|
|
93
|
+
if printf '%s' "$DOCTOR_OUT" | grep -q '"status"[[:space:]]*:[[:space:]]*"WARN"'; then
|
|
94
|
+
HAS_WARN=1
|
|
95
|
+
WARN_MSGS=$(printf '%s' "$DOCTOR_OUT" \
|
|
96
|
+
| grep -oE '"status"[[:space:]]*:[[:space:]]*"WARN"[^}]*"message"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
97
|
+
| sed -E 's/.*"message"[[:space:]]*:[[:space:]]*"([^"]*)"/ - \1/')
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# ---------- FAIL: block ----------
|
|
102
|
+
if [ "$HAS_FAIL" -eq 1 ]; then
|
|
103
|
+
{
|
|
104
|
+
echo "=== Summer doctor: FAIL — commit blocked ==="
|
|
105
|
+
echo "$FAIL_MSGS"
|
|
106
|
+
echo ""
|
|
107
|
+
echo "Fix the failures above, or run: summer doctor"
|
|
108
|
+
echo "To bypass once: disable the pre-commit-doctor hook in settings.json."
|
|
109
|
+
echo "============================================"
|
|
110
|
+
} >&2
|
|
111
|
+
exit 2
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# ---------- WARN: allow with notice ----------
|
|
115
|
+
if [ "$HAS_WARN" -eq 1 ]; then
|
|
116
|
+
{
|
|
117
|
+
echo "=== Summer doctor: WARN — commit allowed ==="
|
|
118
|
+
echo "$WARN_MSGS"
|
|
119
|
+
echo "============================================"
|
|
120
|
+
} >&2
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
exit 0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cross-platform hook dispatcher.
|
|
3
|
+
# Usage: run-hook.cmd <hook-name>
|
|
4
|
+
# Reads stdin, forwards to <plugin-root>/hooks/<hook-name>.sh
|
|
5
|
+
# On Windows, Claude Code / Cursor / Codex invoke this via Git-Bash.
|
|
6
|
+
|
|
7
|
+
HOOK_NAME="$1"
|
|
8
|
+
shift || true
|
|
9
|
+
|
|
10
|
+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
HOOK_SCRIPT="$HOOK_DIR/$HOOK_NAME.sh"
|
|
12
|
+
|
|
13
|
+
if [ ! -f "$HOOK_SCRIPT" ]; then
|
|
14
|
+
# Missing hook = no-op (don't break the host).
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if [ ! -x "$HOOK_SCRIPT" ]; then
|
|
19
|
+
# Not executable yet (likely fresh checkout). Fall back to bash invocation.
|
|
20
|
+
exec bash "$HOOK_SCRIPT" "$@"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
exec "$HOOK_SCRIPT" "$@"
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Summer Engine — SessionStart hook
|
|
3
|
+
#
|
|
4
|
+
# Event: SessionStart (matcher: startup|clear|compact)
|
|
5
|
+
# Purpose: Orient Claude on every fresh Summer-enabled session.
|
|
6
|
+
# Detect Godot project + GameSoul + doctor health, surface a one-line
|
|
7
|
+
# Bob-style greeting as additional context.
|
|
8
|
+
#
|
|
9
|
+
# Input: JSON on stdin with { session_id, source, model, cwd, ... }
|
|
10
|
+
# Common Claude Code env vars: $CLAUDE_PROJECT_DIR, $CLAUDE_PLUGIN_ROOT
|
|
11
|
+
# Output: JSON on stdout with hookSpecificOutput.additionalContext
|
|
12
|
+
# (also emits Cursor / Copilot CLI variants based on host env vars)
|
|
13
|
+
# Exit: Always 0 — never block session start.
|
|
14
|
+
#
|
|
15
|
+
# Portability: bash 3.2+ (macOS default), POSIX-friendly, works on Git Bash.
|
|
16
|
+
# Uses `grep -E` not `grep -P`. Falls back gracefully when jq
|
|
17
|
+
# and `summer` are missing.
|
|
18
|
+
|
|
19
|
+
set +e # Hooks must never kill the session.
|
|
20
|
+
|
|
21
|
+
# ---------- Resolve project dir ----------
|
|
22
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
23
|
+
|
|
24
|
+
# ---------- Build the orientation lines (max 3) ----------
|
|
25
|
+
LINES=()
|
|
26
|
+
|
|
27
|
+
# Line 1: Summer ready + skill count
|
|
28
|
+
SKILL_COUNT=""
|
|
29
|
+
if command -v summer >/dev/null 2>&1; then
|
|
30
|
+
# `summer skills count` is best-effort; ignore failure
|
|
31
|
+
SKILL_COUNT=$(summer skills count 2>/dev/null | grep -oE '[0-9]+' | head -1)
|
|
32
|
+
fi
|
|
33
|
+
if [ -n "$SKILL_COUNT" ]; then
|
|
34
|
+
LINES+=("Summer ready. ${SKILL_COUNT} skills.")
|
|
35
|
+
else
|
|
36
|
+
LINES+=("Summer ready.")
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Line 2: Godot project + GameSoul one-liner (only if project.godot exists)
|
|
40
|
+
if [ -f "${PROJECT_DIR}/project.godot" ]; then
|
|
41
|
+
PROJECT_NAME=$(grep -E '^config/name=' "${PROJECT_DIR}/project.godot" 2>/dev/null \
|
|
42
|
+
| head -1 | sed 's/^config\/name=//;s/^"//;s/"$//')
|
|
43
|
+
[ -z "$PROJECT_NAME" ] && PROJECT_NAME=$(basename "$PROJECT_DIR")
|
|
44
|
+
|
|
45
|
+
SOUL_FILE="${PROJECT_DIR}/.summer/GameSoul.md"
|
|
46
|
+
if [ -f "$SOUL_FILE" ]; then
|
|
47
|
+
# First non-empty, non-heading paragraph (one line)
|
|
48
|
+
SOUL_LINE=$(awk 'BEGIN{p=""} /^[^#[:space:]]/ && NF>0 {p=$0; exit} END{print p}' \
|
|
49
|
+
"$SOUL_FILE" 2>/dev/null | cut -c1-120)
|
|
50
|
+
if [ -n "$SOUL_LINE" ]; then
|
|
51
|
+
LINES+=("Godot project: ${PROJECT_NAME}. GameSoul: ${SOUL_LINE}")
|
|
52
|
+
else
|
|
53
|
+
LINES+=("Godot project: ${PROJECT_NAME}.")
|
|
54
|
+
fi
|
|
55
|
+
else
|
|
56
|
+
LINES+=("Godot project: ${PROJECT_NAME}.")
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Line 3: doctor FAIL one-liner (only on FAIL — silent on PASS/WARN)
|
|
61
|
+
if command -v summer >/dev/null 2>&1; then
|
|
62
|
+
DOCTOR_OUT=$(summer doctor --json 2>/dev/null)
|
|
63
|
+
if [ -n "$DOCTOR_OUT" ]; then
|
|
64
|
+
FAIL_REASON=""
|
|
65
|
+
if command -v jq >/dev/null 2>&1; then
|
|
66
|
+
FAIL_REASON=$(printf '%s' "$DOCTOR_OUT" \
|
|
67
|
+
| jq -r 'first(.checks[]? | select(.status == "FAIL") | .message) // empty' 2>/dev/null)
|
|
68
|
+
else
|
|
69
|
+
# Crude fallback: first "message" near a "FAIL"
|
|
70
|
+
FAIL_REASON=$(printf '%s' "$DOCTOR_OUT" \
|
|
71
|
+
| grep -oE '"status"[[:space:]]*:[[:space:]]*"FAIL"[^}]*"message"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
72
|
+
| head -1 \
|
|
73
|
+
| grep -oE '"message"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
74
|
+
| sed 's/.*"message"[[:space:]]*:[[:space:]]*"//;s/"$//')
|
|
75
|
+
fi
|
|
76
|
+
if [ -n "$FAIL_REASON" ]; then
|
|
77
|
+
LINES+=("Summer setup needs attention: ${FAIL_REASON}. Run: summer doctor")
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# ---------- Compose context ----------
|
|
83
|
+
CONTEXT=""
|
|
84
|
+
for line in "${LINES[@]}"; do
|
|
85
|
+
if [ -z "$CONTEXT" ]; then CONTEXT="$line"
|
|
86
|
+
else CONTEXT="${CONTEXT}"$'\n'"$line"
|
|
87
|
+
fi
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
# Bail with empty JSON if we somehow have no lines
|
|
91
|
+
if [ -z "$CONTEXT" ]; then
|
|
92
|
+
printf '{}\n'
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ---------- JSON-escape for embedding ----------
|
|
97
|
+
escape_for_json() {
|
|
98
|
+
local s="$1"
|
|
99
|
+
s="${s//\\/\\\\}"
|
|
100
|
+
s="${s//\"/\\\"}"
|
|
101
|
+
s="${s//$'\n'/\\n}"
|
|
102
|
+
s="${s//$'\r'/\\r}"
|
|
103
|
+
s="${s//$'\t'/\\t}"
|
|
104
|
+
printf '%s' "$s"
|
|
105
|
+
}
|
|
106
|
+
CONTEXT_ESC=$(escape_for_json "$CONTEXT")
|
|
107
|
+
|
|
108
|
+
# ---------- Emit per-host shape ----------
|
|
109
|
+
# Cursor: top-level additional_context (snake_case)
|
|
110
|
+
# Claude Code: nested hookSpecificOutput.additionalContext
|
|
111
|
+
# Copilot CLI / SDK standard: top-level additionalContext (camelCase)
|
|
112
|
+
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
|
|
113
|
+
printf '{"additional_context":"%s"}\n' "$CONTEXT_ESC"
|
|
114
|
+
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
|
|
115
|
+
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$CONTEXT_ESC"
|
|
116
|
+
else
|
|
117
|
+
printf '{"additionalContext":"%s"}\n' "$CONTEXT_ESC"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
exit 0
|
package/marketplace.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
|
|
3
|
+
"name": "summer",
|
|
4
|
+
"description": "Summer Engine plugins for Claude Code",
|
|
5
|
+
"owner": { "name": "Summer Engine", "email": "founders@summerengine.com" },
|
|
6
|
+
"plugins": [
|
|
7
|
+
{
|
|
8
|
+
"name": "summer",
|
|
9
|
+
"source": "./",
|
|
10
|
+
"version": "1.4.0",
|
|
11
|
+
"description": "AI game-dev studio: 19 skills under summer: namespace, MCP bridge, session-start + pre-commit hooks.",
|
|
12
|
+
"author": { "name": "Summer Engine", "email": "founders@summerengine.com" },
|
|
13
|
+
"category": "game-development",
|
|
14
|
+
"tags": ["game-dev", "godot", "ai-game-engine"],
|
|
15
|
+
"keywords": ["game-dev", "godot", "ai-game-engine", "skills"],
|
|
16
|
+
"brandColor": "#FF8F17",
|
|
17
|
+
"capabilities": ["Interactive", "Read", "Write"],
|
|
18
|
+
"defaultPrompt": [
|
|
19
|
+
"I want to make a game.",
|
|
20
|
+
"/summer:brainstorm-game"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "summer-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "CLI and MCP tools for Summer Engine — the AI-native game engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"game-engine",
|
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"dist/",
|
|
27
27
|
"skills/",
|
|
28
|
+
"hooks/",
|
|
29
|
+
".claude-plugin/",
|
|
30
|
+
".cursor-plugin/",
|
|
31
|
+
".codex-plugin/",
|
|
32
|
+
".opencode/",
|
|
33
|
+
"gemini-extension.json",
|
|
34
|
+
"marketplace.json",
|
|
35
|
+
".mcp.json",
|
|
28
36
|
"README.md",
|
|
29
37
|
"LICENSE",
|
|
30
38
|
"CHANGELOG.md"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Skill Spec: /peer-to-peer-multiplayer
|
|
2
|
+
|
|
3
|
+
## Fixture
|
|
4
|
+
|
|
5
|
+
- A Godot 4.5 / Summer Engine project that does NOT yet have multiplayer.
|
|
6
|
+
- Project may be empty or may have an existing single-player scene.
|
|
7
|
+
- Summer MCP tools available; engine running on localhost:6550.
|
|
8
|
+
|
|
9
|
+
## Case 1: Happy Path — fresh multiplayer architecture from scratch
|
|
10
|
+
|
|
11
|
+
**Input:** "I want to add 2-player co-op to my game. Players will connect through Steam friend invites."
|
|
12
|
+
|
|
13
|
+
**Expected behavior:**
|
|
14
|
+
|
|
15
|
+
1. Skill confirms P2P is the right architecture (Steam friend invite ≤8 players → P2P, not dedicated server).
|
|
16
|
+
2. Skill walks the four layers in order, checkpointing between each.
|
|
17
|
+
3. Layer 1: asks "May I create `autoloads/network_manager.gd`?" — creates it on user OK, calls `summer_project_setting` to register the autoload.
|
|
18
|
+
4. Layer 2: asks "May I create `autoloads/game_state.gd` and walk through the authority decision matrix?" — creates it, prompts user for game-specific state fields and proposes ownership.
|
|
19
|
+
5. Layer 3: explains the three RPC patterns with examples; doesn't auto-apply (this is reference material until concrete game logic exists).
|
|
20
|
+
6. Layer 4: defers prediction/interpolation until there's a player scene to apply it to.
|
|
21
|
+
|
|
22
|
+
**Expected MCP tool sequence (in order, partial):**
|
|
23
|
+
|
|
24
|
+
1. `summer_get_scene_tree` — see what already exists.
|
|
25
|
+
2. `summer_get_project_context` — read autoload list to avoid name collisions.
|
|
26
|
+
3. (User approves Layer 1) `Write autoloads/network_manager.gd`.
|
|
27
|
+
4. `summer_project_setting(key="autoload/NetworkManager", value="*res://autoloads/network_manager.gd")`.
|
|
28
|
+
5. (User approves Layer 2) `Write autoloads/game_state.gd`.
|
|
29
|
+
6. `summer_project_setting(key="autoload/GameState", value="*res://autoloads/game_state.gd")`.
|
|
30
|
+
7. `summer_save_scene` and `summer_get_script_errors` to verify clean.
|
|
31
|
+
|
|
32
|
+
**Assertions:**
|
|
33
|
+
|
|
34
|
+
- [ ] Skill explicitly checks Step 0 (P2P vs. client-server) before any code is written.
|
|
35
|
+
- [ ] Skill creates Layer 1 (NetworkManager) before Layer 2 (GameState).
|
|
36
|
+
- [ ] NetworkManager is the only place that calls `multiplayer.peer_connected.connect()` directly. GameState listens to NetworkManager signals, NOT to the multiplayer API directly.
|
|
37
|
+
- [ ] GameState uses `@rpc("authority", "call_remote", "reliable")` for host-broadcast functions and `@rpc("any_peer", "call_remote", "reliable")` with a `is_host` guard for client-request functions.
|
|
38
|
+
- [ ] Skill walks the user through the authority decision matrix before writing GameState. Doesn't dump generic state fields without asking what the game has.
|
|
39
|
+
- [ ] Skill asks "May I…" before each new file creation and before the autoload registration.
|
|
40
|
+
- [ ] Skill does NOT apply prediction/interpolation in Layer 4 unless there's an existing player scene to wire into.
|
|
41
|
+
- [ ] At any layer, `summer_get_script_errors` is called after the file write to confirm clean compile.
|
|
42
|
+
|
|
43
|
+
## Case 2: Failure Path — user wants matchmaking at scale
|
|
44
|
+
|
|
45
|
+
**Input:** "I'm building a competitive shooter. I want matchmaking with anti-cheat for 10,000 concurrent matches."
|
|
46
|
+
|
|
47
|
+
**Expected behavior:**
|
|
48
|
+
|
|
49
|
+
- Skill recognizes Step 0: this is dedicated client-server territory, not P2P.
|
|
50
|
+
- Skill explains why P2P is wrong (host can cheat, no anti-cheat hooks, scale concerns).
|
|
51
|
+
- Skill defers to `/summer:client-server-multiplayer` (when shipped) OR explains the user needs to roll a custom server.
|
|
52
|
+
- Does NOT start writing P2P NetworkManager code anyway.
|
|
53
|
+
|
|
54
|
+
**Assertions:**
|
|
55
|
+
|
|
56
|
+
- [ ] Skill stops at Step 0 — does NOT proceed to Layer 1.
|
|
57
|
+
- [ ] Skill explains the architecture mismatch in one sentence.
|
|
58
|
+
- [ ] Skill names the right alternative (client-server) and which skill to use instead.
|
|
59
|
+
|
|
60
|
+
## Case 3: Edge Case — retrofitting multiplayer to a single-player game
|
|
61
|
+
|
|
62
|
+
**Input:** "I have a single-player platformer that's mostly done. Can you add multiplayer?"
|
|
63
|
+
|
|
64
|
+
**Expected behavior:**
|
|
65
|
+
|
|
66
|
+
- Skill is honest about the cost: retrofitting multiplayer is 5× harder than starting MP-first.
|
|
67
|
+
- Skill asks: "Are you committed? It will require auditing every state mutation in your existing code. Time estimate: significant."
|
|
68
|
+
- If user proceeds: skill walks the same 4 layers but adds an AUDIT phase before Layer 2: identify every place existing code writes to state that should be host-authoritative.
|
|
69
|
+
- If user balks: skill points to alternatives (release MP as a sequel; ship single-player; add async leaderboards instead).
|
|
70
|
+
|
|
71
|
+
**Assertions:**
|
|
72
|
+
|
|
73
|
+
- [ ] Skill warns about retrofit cost BEFORE starting Layer 1.
|
|
74
|
+
- [ ] Skill adds an AUDIT step that doesn't exist in the happy-path workflow.
|
|
75
|
+
- [ ] Skill never silently proceeds as if the game were greenfield.
|
|
76
|
+
|
|
77
|
+
## Case 4: No Summer MCP — fallback path
|
|
78
|
+
|
|
79
|
+
**Fixture:** Same as Case 1, but Summer MCP unavailable.
|
|
80
|
+
|
|
81
|
+
**Input:** "Add multiplayer to my Godot game (P2P, friend invite)."
|
|
82
|
+
|
|
83
|
+
**Expected behavior:**
|
|
84
|
+
|
|
85
|
+
- Skill detects MCP unavailable.
|
|
86
|
+
- Walks the same 4 layers.
|
|
87
|
+
- Instead of `summer_project_setting`, asks the user to manually edit `project.godot`'s `[autoload]` section — provides the exact lines to paste.
|
|
88
|
+
- Instead of `summer_save_scene` / `summer_get_script_errors`, asks the user to save and check errors via the Godot editor.
|
|
89
|
+
- All file writes still go through `Write` host tool with "May I…" approval per file.
|
|
90
|
+
|
|
91
|
+
**Assertions:**
|
|
92
|
+
|
|
93
|
+
- [ ] Skill detects MCP unavailable; doesn't blindly call `summer_*` tools and fail.
|
|
94
|
+
- [ ] Project.godot edits are provided as exact paste-able lines.
|
|
95
|
+
- [ ] Workflow shape (4 layers, checkpoints between) is identical regardless of MCP availability.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
This spec runs via `/skill-test peer-to-peer-multiplayer spec` (see `_meta/skill-test/SKILL.md`).
|
|
@@ -233,3 +233,11 @@ summer_generate_audio(capability="text_to_speech", text="You shall not pass!", v
|
|
|
233
233
|
- **Extremely thin objects** (paper, cloth, flags): 3D gen produces thick meshes. Better to use MeshInstance3D with a plane + texture + shader.
|
|
234
234
|
- **Emissive/glowing objects**: Generate the mesh, add emissive material in engine. Don't rely on the glow being in the mesh.
|
|
235
235
|
- **LOD (Level of Detail)**: Generate one version. If perf needs LOD, use Godot's LOD system or generate a second low-poly version.
|
|
236
|
+
|
|
237
|
+
## Fallback
|
|
238
|
+
|
|
239
|
+
No fallback for this — Summer MCP required for the generation pipelines (`summer_generate_image`, `summer_generate_3d`, `summer_generate_audio`, `summer_search_assets`, `summer_import_from_url`). If MCP isn't connected, the user must source assets externally (Sketchfab, Quaternius, Kenney, AmbientCG) and import via Godot's import system.
|
|
240
|
+
|
|
241
|
+
## Collaborative protocol
|
|
242
|
+
|
|
243
|
+
This skill triggers metered generation (image / 3D / audio) and mutates the scene with imported assets. Always ask before generating ("May I generate a 3D treasure chest via image-to-3D? This is one metered generation.") and before importing ("May I import the result to `res://assets/models/chest.glb`?"). See `../../_shared/collaborative-protocol.md`.
|
package/skills/catalog.yaml
CHANGED
|
@@ -48,6 +48,13 @@ skills:
|
|
|
48
48
|
public: true
|
|
49
49
|
|
|
50
50
|
# ── gameplay-mechanics ──
|
|
51
|
+
- name: design-mechanic
|
|
52
|
+
category: gameplay-mechanics
|
|
53
|
+
status: HAVE
|
|
54
|
+
public: true
|
|
55
|
+
recommended: true
|
|
56
|
+
user-invocable: true
|
|
57
|
+
last-tested: 2026-05-05
|
|
51
58
|
- name: melee-combat
|
|
52
59
|
category: gameplay-mechanics
|
|
53
60
|
status: NEXT
|
|
@@ -132,6 +139,13 @@ skills:
|
|
|
132
139
|
public: true
|
|
133
140
|
|
|
134
141
|
# ── scene-and-project ──
|
|
142
|
+
- name: brainstorm-game
|
|
143
|
+
category: scene-and-project
|
|
144
|
+
status: HAVE
|
|
145
|
+
public: true
|
|
146
|
+
recommended: true
|
|
147
|
+
user-invocable: true
|
|
148
|
+
last-tested: 2026-05-05
|
|
135
149
|
- name: scene-composition
|
|
136
150
|
category: scene-and-project
|
|
137
151
|
status: HAVE
|
|
@@ -177,6 +191,13 @@ skills:
|
|
|
177
191
|
public: true
|
|
178
192
|
|
|
179
193
|
# ── rendering-and-lighting ──
|
|
194
|
+
- name: art-direction
|
|
195
|
+
category: rendering-and-lighting
|
|
196
|
+
status: HAVE
|
|
197
|
+
public: true
|
|
198
|
+
recommended: true
|
|
199
|
+
user-invocable: true
|
|
200
|
+
last-tested: 2026-05-05
|
|
180
201
|
- name: 3d-lighting
|
|
181
202
|
category: rendering-and-lighting
|
|
182
203
|
status: HAVE
|
|
@@ -255,6 +276,13 @@ skills:
|
|
|
255
276
|
public: true
|
|
256
277
|
|
|
257
278
|
# ── visual-effects ──
|
|
279
|
+
- name: vfx
|
|
280
|
+
category: visual-effects
|
|
281
|
+
status: HAVE
|
|
282
|
+
public: true
|
|
283
|
+
recommended: true
|
|
284
|
+
user-invocable: true
|
|
285
|
+
last-tested: 2026-05-05
|
|
258
286
|
- name: gpuparticles-3d-basics
|
|
259
287
|
category: visual-effects
|
|
260
288
|
status: NEXT
|
|
@@ -333,6 +361,13 @@ skills:
|
|
|
333
361
|
public: true
|
|
334
362
|
|
|
335
363
|
# ── audio ──
|
|
364
|
+
- name: audio-direction
|
|
365
|
+
category: audio
|
|
366
|
+
status: HAVE
|
|
367
|
+
public: true
|
|
368
|
+
recommended: true
|
|
369
|
+
user-invocable: true
|
|
370
|
+
last-tested: 2026-05-05
|
|
336
371
|
- name: audio-bus-setup
|
|
337
372
|
category: audio
|
|
338
373
|
status: NEXT
|
|
@@ -393,6 +428,25 @@ skills:
|
|
|
393
428
|
public: true
|
|
394
429
|
|
|
395
430
|
# ── multiplayer-and-networking ──
|
|
431
|
+
- name: setup-multiplayer
|
|
432
|
+
category: multiplayer-and-networking
|
|
433
|
+
status: HAVE
|
|
434
|
+
public: true
|
|
435
|
+
recommended: true
|
|
436
|
+
user-invocable: true
|
|
437
|
+
last-tested: 2026-05-05
|
|
438
|
+
- name: peer-to-peer-multiplayer
|
|
439
|
+
category: multiplayer-and-networking
|
|
440
|
+
status: NEXT
|
|
441
|
+
public: true
|
|
442
|
+
recommended: true
|
|
443
|
+
user-invocable: true
|
|
444
|
+
- name: host-authoritative-state
|
|
445
|
+
category: multiplayer-and-networking
|
|
446
|
+
status: NEXT
|
|
447
|
+
public: true
|
|
448
|
+
recommended: true
|
|
449
|
+
user-invocable: true
|
|
396
450
|
- name: multiplayerapi-basics
|
|
397
451
|
category: multiplayer-and-networking
|
|
398
452
|
status: NEXT
|
|
@@ -423,6 +477,13 @@ skills:
|
|
|
423
477
|
public: true
|
|
424
478
|
|
|
425
479
|
# ── ai-and-npcs ──
|
|
480
|
+
- name: design-npc
|
|
481
|
+
category: ai-and-npcs
|
|
482
|
+
status: HAVE
|
|
483
|
+
public: true
|
|
484
|
+
recommended: true
|
|
485
|
+
user-invocable: true
|
|
486
|
+
last-tested: 2026-05-05
|
|
426
487
|
- name: navmesh-pathfinding
|
|
427
488
|
category: ai-and-npcs
|
|
428
489
|
status: NEXT
|
|
@@ -453,6 +514,13 @@ skills:
|
|
|
453
514
|
public: true
|
|
454
515
|
|
|
455
516
|
# ── level-design ──
|
|
517
|
+
- name: design-level
|
|
518
|
+
category: level-design
|
|
519
|
+
status: HAVE
|
|
520
|
+
public: true
|
|
521
|
+
recommended: true
|
|
522
|
+
user-invocable: true
|
|
523
|
+
last-tested: 2026-05-05
|
|
456
524
|
- name: gridmap-building
|
|
457
525
|
category: level-design
|
|
458
526
|
status: NEXT
|
|
@@ -479,6 +547,13 @@ skills:
|
|
|
479
547
|
public: true
|
|
480
548
|
|
|
481
549
|
# ── performance ──
|
|
550
|
+
- name: tune-performance
|
|
551
|
+
category: performance
|
|
552
|
+
status: HAVE
|
|
553
|
+
public: true
|
|
554
|
+
recommended: true
|
|
555
|
+
user-invocable: true
|
|
556
|
+
last-tested: 2026-05-05
|
|
482
557
|
- name: profiling-godot
|
|
483
558
|
category: performance
|
|
484
559
|
status: NEXT
|
|
@@ -624,6 +699,13 @@ skills:
|
|
|
624
699
|
public: true
|
|
625
700
|
|
|
626
701
|
# ── deployment ──
|
|
702
|
+
- name: export-and-ship
|
|
703
|
+
category: deployment
|
|
704
|
+
status: HAVE
|
|
705
|
+
public: true
|
|
706
|
+
recommended: true
|
|
707
|
+
user-invocable: true
|
|
708
|
+
last-tested: 2026-05-05
|
|
627
709
|
- name: export-presets
|
|
628
710
|
category: deployment
|
|
629
711
|
status: NEXT
|
|
@@ -131,3 +131,30 @@ For `summer_set_resource_property` on CapsuleShape3D:
|
|
|
131
131
|
- **Falling through floor:** Ensure the floor has a StaticBody3D or similar with a CollisionShape3D
|
|
132
132
|
- **Camera clipping:** If the camera goes inside geometry, enable `near` on the Camera3D or add collision exception
|
|
133
133
|
- **Mouse capture:** For FPS, you typically need `Input.mouse_mode = Input.MOUSE_MODE_CAPTURED` in `_ready()` and a way to release (e.g., Escape)
|
|
134
|
+
|
|
135
|
+
## Fallback (no MCP — edit `.tscn` directly)
|
|
136
|
+
|
|
137
|
+
If Summer MCP isn't connected, write the scene by hand. Save as `res://player.tscn`:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
[gd_scene load_steps=2 format=3]
|
|
141
|
+
|
|
142
|
+
[sub_resource type="CapsuleShape3D" id="1"]
|
|
143
|
+
radius = 0.4
|
|
144
|
+
height = 1.6
|
|
145
|
+
|
|
146
|
+
[node name="Player" type="CharacterBody3D"]
|
|
147
|
+
position = Vector3(0, 1, 0)
|
|
148
|
+
|
|
149
|
+
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
|
150
|
+
shape = SubResource("1")
|
|
151
|
+
|
|
152
|
+
[node name="Camera3D" type="Camera3D" parent="."]
|
|
153
|
+
position = Vector3(0, 1.6, 0)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Then attach `player.gd` (script body above) via the inspector.
|
|
157
|
+
|
|
158
|
+
## Collaborative protocol
|
|
159
|
+
|
|
160
|
+
This skill writes scene nodes and a `.gd` script. Always ask before applying. Group writes per phase: "May I add the Player + CollisionShape3D + Camera3D, bind WASD/jump InputMap actions, and attach `player.gd`?" See `../../_shared/collaborative-protocol.md`.
|