summer-engine 3.0.0 → 3.2.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 +2 -2
- package/.claude-plugin/plugin.json +27 -5
- package/.codex-plugin/plugin.json +28 -6
- package/.cursor-plugin/plugin.json +27 -5
- package/.factory-plugin/plugin.json +27 -5
- package/.opencode/plugins/summer.js +1 -1
- package/CHANGELOG.md +120 -0
- package/README.md +22 -7
- package/assets/audit/scene_audit.gd +4136 -0
- package/assets/seeing/seeing_probe.gd +1873 -0
- package/dist/cli/commands/setup.js +6 -19
- package/dist/cli/commands/skills.js +57 -32
- package/dist/core/api-client.d.ts +9 -1
- package/dist/core/api-client.js +21 -4
- package/dist/core/capabilities/agent-playbook.js +46 -0
- package/dist/core/capabilities/audit/accept.d.ts +55 -0
- package/dist/core/capabilities/audit/accept.js +147 -0
- package/dist/core/capabilities/audit/args.d.ts +95 -0
- package/dist/core/capabilities/audit/args.js +89 -0
- package/dist/core/capabilities/audit/audit.d.ts +56 -0
- package/dist/core/capabilities/audit/audit.js +287 -0
- package/dist/core/capabilities/audit/frame.d.ts +14 -0
- package/dist/core/capabilities/audit/frame.js +35 -0
- package/dist/core/capabilities/audit/gaps.d.ts +96 -0
- package/dist/core/capabilities/audit/gaps.js +257 -0
- package/dist/core/capabilities/audit/judge.d.ts +162 -0
- package/dist/core/capabilities/audit/judge.js +1134 -0
- package/dist/core/capabilities/audit/math.d.ts +110 -0
- package/dist/core/capabilities/audit/math.js +263 -0
- package/dist/core/capabilities/audit/summary.d.ts +74 -0
- package/dist/core/capabilities/audit/summary.js +212 -0
- package/dist/core/capabilities/board.d.ts +31 -0
- package/dist/core/capabilities/board.js +43 -0
- package/dist/core/capabilities/camera-view.d.ts +4 -2
- package/dist/core/capabilities/camera-view.js +6 -3
- package/dist/core/capabilities/connect-signal.d.ts +85 -0
- package/dist/core/capabilities/connect-signal.js +285 -0
- package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
- package/dist/core/capabilities/engine-fallbacks.js +5 -0
- package/dist/core/capabilities/engine-ops.d.ts +5 -1
- package/dist/core/capabilities/engine-ops.js +0 -3
- package/dist/core/capabilities/engine-receipt.d.ts +12 -0
- package/dist/core/capabilities/engine-receipt.js +26 -0
- package/dist/core/capabilities/file-read.d.ts +64 -0
- package/dist/core/capabilities/file-read.js +325 -0
- package/dist/core/capabilities/game-task-plan.js +4 -2
- package/dist/core/capabilities/grep.d.ts +60 -0
- package/dist/core/capabilities/grep.js +190 -0
- package/dist/core/capabilities/inspect-node.d.ts +56 -0
- package/dist/core/capabilities/inspect-node.js +225 -0
- package/dist/core/capabilities/inspect-resource.d.ts +61 -0
- package/dist/core/capabilities/inspect-resource.js +376 -0
- package/dist/core/capabilities/math3d.d.ts +28 -0
- package/dist/core/capabilities/math3d.js +88 -0
- package/dist/core/capabilities/motion-generation.d.ts +62 -0
- package/dist/core/capabilities/motion-generation.js +138 -0
- package/dist/core/capabilities/placement-batch.d.ts +102 -0
- package/dist/core/capabilities/placement-batch.js +483 -0
- package/dist/core/capabilities/placement-math.d.ts +70 -0
- package/dist/core/capabilities/placement-math.js +209 -0
- package/dist/core/capabilities/placement-script.d.ts +42 -0
- package/dist/core/capabilities/placement-script.js +1096 -0
- package/dist/core/capabilities/placement.d.ts +485 -0
- package/dist/core/capabilities/placement.js +1731 -0
- package/dist/core/capabilities/project-context.d.ts +33 -2
- package/dist/core/capabilities/project-context.js +87 -4
- package/dist/core/capabilities/replace-node.d.ts +91 -0
- package/dist/core/capabilities/replace-node.js +423 -0
- package/dist/core/capabilities/runtime-control.d.ts +20 -4
- package/dist/core/capabilities/runtime-control.js +67 -2
- package/dist/core/capabilities/scene-batch.d.ts +63 -0
- package/dist/core/capabilities/scene-batch.js +394 -0
- package/dist/core/capabilities/scene-readback.d.ts +36 -0
- package/dist/core/capabilities/scene-readback.js +54 -0
- package/dist/core/capabilities/seeing/args.d.ts +348 -0
- package/dist/core/capabilities/seeing/args.js +178 -0
- package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
- package/dist/core/capabilities/seeing/candidates.js +282 -0
- package/dist/core/capabilities/seeing/math.d.ts +134 -0
- package/dist/core/capabilities/seeing/math.js +269 -0
- package/dist/core/capabilities/seeing/probe.d.ts +62 -0
- package/dist/core/capabilities/seeing/probe.js +188 -0
- package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
- package/dist/core/capabilities/seeing/scoring.js +639 -0
- package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
- package/dist/core/capabilities/seeing/seeing.js +1341 -0
- package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
- package/dist/core/capabilities/seeing/shot-store.js +204 -0
- package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
- package/dist/core/capabilities/surface-snap-mesh.js +425 -0
- package/dist/core/capabilities/surface-snap.d.ts +77 -0
- package/dist/core/capabilities/surface-snap.js +461 -0
- package/dist/core/capabilities/tool-dispatch.js +231 -72
- package/dist/core/capabilities/tscn.d.ts +85 -0
- package/dist/core/capabilities/tscn.js +391 -0
- package/dist/core/capabilities/world-snapshot.d.ts +58 -0
- package/dist/core/capabilities/world-snapshot.js +150 -0
- package/dist/core/capability-skew.d.ts +5 -5
- package/dist/core/capability-skew.js +14 -6
- package/dist/core/headless/worker-engine-client.d.ts +1 -1
- package/dist/core/headless/worker-engine-client.js +2 -2
- package/dist/core/library-read.d.ts +37 -5
- package/dist/core/library-read.js +264 -33
- package/dist/core/library-search.d.ts +2 -2
- package/dist/core/skills-registry.d.ts +9 -1
- package/dist/core/skills-registry.js +25 -2
- package/dist/installer/agent-config.d.ts +9 -4
- package/dist/installer/agent-config.js +194 -392
- package/dist/installer/agent-table.d.ts +119 -0
- package/dist/installer/agent-table.js +619 -0
- package/dist/installer/setup.js +4 -2
- package/dist/installer/skill-locations.d.ts +8 -17
- package/dist/installer/skill-locations.js +22 -101
- package/dist/installer/version-check.d.ts +5 -1
- package/dist/installer/version-check.js +38 -28
- package/dist/mcp/server.js +9 -3
- package/dist/mcp/tools/asset-tools.js +21 -3
- package/dist/mcp/tools/audit-tools.d.ts +23 -0
- package/dist/mcp/tools/audit-tools.js +60 -0
- package/dist/mcp/tools/debug-tools.js +3 -1
- package/dist/mcp/tools/file-tools.js +17 -4
- package/dist/mcp/tools/generate-tools.js +74 -66
- package/dist/mcp/tools/library-tools.js +2 -0
- package/dist/mcp/tools/perception-tools.js +6 -19
- package/dist/mcp/tools/placement-tools.d.ts +24 -0
- package/dist/mcp/tools/placement-tools.js +91 -0
- package/dist/mcp/tools/project-tools.js +18 -15
- package/dist/mcp/tools/scene-tools.js +71 -83
- package/dist/mcp/tools/seeing-tools.d.ts +24 -0
- package/dist/mcp/tools/seeing-tools.js +64 -0
- package/dist/mcp/tools/spatial-tools.js +17 -9
- package/dist/mcp/tools/visual-tools.js +59 -7
- package/gemini-extension.json +26 -4
- package/integrations/README.md +48 -19
- package/integrations/amp/README.md +12 -0
- package/integrations/amp/manifest-target.json +3 -0
- package/integrations/antigravity/README.md +12 -0
- package/integrations/antigravity/manifest-target.json +3 -0
- package/integrations/claude-desktop/README.md +12 -0
- package/integrations/claude-desktop/manifest-target.json +3 -0
- package/integrations/cline/README.md +8 -9
- package/integrations/cline-cli/README.md +12 -0
- package/integrations/cline-cli/manifest-target.json +3 -0
- package/integrations/copilot-jetbrains/README.md +12 -0
- package/integrations/copilot-jetbrains/manifest-target.json +3 -0
- package/integrations/crush/README.md +12 -0
- package/integrations/crush/manifest-target.json +3 -0
- package/integrations/github-copilot/README.md +8 -8
- package/integrations/goose/README.md +12 -0
- package/integrations/goose/manifest-target.json +3 -0
- package/integrations/grok-build/README.md +12 -0
- package/integrations/grok-build/manifest-target.json +3 -0
- package/integrations/hermes/README.md +12 -0
- package/integrations/hermes/manifest-target.json +3 -0
- package/integrations/junie/README.md +12 -0
- package/integrations/junie/manifest-target.json +3 -0
- package/integrations/kilo-code/README.md +6 -10
- package/integrations/kimi-code/README.md +12 -0
- package/integrations/kimi-code/manifest-target.json +3 -0
- package/integrations/kiro/README.md +12 -0
- package/integrations/kiro/manifest-target.json +3 -0
- package/integrations/lm-studio/README.md +8 -8
- package/integrations/mistral-vibe/README.md +12 -0
- package/integrations/mistral-vibe/manifest-target.json +3 -0
- package/integrations/opencode/README.md +9 -12
- package/integrations/qoder/README.md +12 -0
- package/integrations/qoder/manifest-target.json +3 -0
- package/integrations/qwen-code/README.md +12 -0
- package/integrations/qwen-code/manifest-target.json +3 -0
- package/integrations/roo-code/README.md +8 -7
- package/integrations/rovo-dev/README.md +12 -0
- package/integrations/rovo-dev/manifest-target.json +3 -0
- package/integrations/trae/README.md +12 -0
- package/integrations/trae/manifest-target.json +3 -0
- package/integrations/visual-studio/README.md +12 -0
- package/integrations/visual-studio/manifest-target.json +3 -0
- package/integrations/vscode-copilot/README.md +9 -9
- package/integrations/warp/README.md +12 -0
- package/integrations/warp/manifest-target.json +3 -0
- package/integrations/windsurf/README.md +8 -9
- package/integrations/zed/README.md +12 -0
- package/integrations/zed/manifest-target.json +3 -0
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
- package/library/references/mcp-tools-reference/resource.yaml +1 -1
- package/library/references/summer-folder/resource.yaml +1 -1
- package/library/references/summer-folder/summer-folder.md +1 -1
- package/library/skills/3d-lighting/SKILL.md +1 -1
- package/library/skills/README.md +264 -0
- package/library/skills/adaptive-music/SKILL.md +1 -1
- package/library/skills/agent-playtesting/SKILL.md +1 -1
- package/library/skills/ai-characters-in-games/SKILL.md +220 -0
- package/library/skills/ai-characters-in-games/resource.yaml +30 -0
- package/library/skills/ambient-bed/SKILL.md +1 -1
- package/library/skills/animated-loop/SKILL.md +1 -1
- package/library/skills/animation-tree/SKILL.md +1 -1
- package/library/skills/art-direction/SKILL.md +1 -1
- package/library/skills/asset-strategy/SKILL.md +2 -1
- package/library/skills/asset-strategy/resource.yaml +2 -1
- package/library/skills/audio-direction/SKILL.md +1 -1
- package/library/skills/auto-fire-targeting/SKILL.md +1 -1
- package/library/skills/brainstorm-game/SKILL.md +1 -1
- package/library/skills/brainstorming/SKILL.md +1 -1
- package/library/skills/browse-templates/SKILL.md +3 -3
- package/library/skills/browse-templates/resource.yaml +1 -1
- package/library/skills/camera-rigs/SKILL.md +128 -0
- package/library/skills/camera-rigs/resource.yaml +29 -0
- package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
- package/library/skills/character-animation-wiring/SKILL.md +1 -1
- package/library/skills/character-model/SKILL.md +1 -1
- package/library/skills/character-movement/SKILL.md +326 -0
- package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
- package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
- package/library/skills/character-movement/references/movement-3d.md +136 -0
- package/library/skills/character-movement/references/platformer-feel.md +83 -0
- package/library/skills/character-movement/resource.yaml +40 -0
- package/library/skills/character-portrait/SKILL.md +1 -1
- package/library/skills/cinematic-cutscene/SKILL.md +1 -1
- package/library/skills/combat-basics/SKILL.md +159 -0
- package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
- package/library/skills/combat-basics/resource.yaml +34 -0
- package/library/skills/concept-art/SKILL.md +1 -1
- package/library/skills/create-asset-sheet/SKILL.md +1 -1
- package/library/skills/debug/SKILL.md +1 -1
- package/library/skills/debugging-game-feel/SKILL.md +1 -1
- package/library/skills/design-level/SKILL.md +1 -1
- package/library/skills/design-mechanic/SKILL.md +1 -1
- package/library/skills/design-npc/SKILL.md +1 -1
- package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
- package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
- package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
- package/library/skills/environment-kit/SKILL.md +1 -1
- package/library/skills/export-and-ship/SKILL.md +1 -1
- package/library/skills/fabricating-assets/SKILL.md +1 -1
- package/library/skills/facial-and-lipsync/SKILL.md +1 -1
- package/library/skills/fps-controller/SKILL.md +9 -7
- package/library/skills/fps-controller/resource.yaml +4 -1
- package/library/skills/game-feel/SKILL.md +1 -1
- package/library/skills/gameskill/SKILL.md +1 -1
- package/library/skills/gdscript-patterns/SKILL.md +1 -1
- package/library/skills/generate-motion/SKILL.md +9 -9
- package/library/skills/generate-motion/resource.yaml +2 -1
- package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
- package/library/skills/headless-scripting/SKILL.md +1 -1
- package/library/skills/in-game-purchases/SKILL.md +254 -0
- package/library/skills/in-game-purchases/resource.yaml +29 -0
- package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
- package/library/skills/investigating-bugs/SKILL.md +1 -1
- package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
- package/library/skills/make-game/SKILL.md +25 -3
- package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
- package/library/skills/make-game/references/2d-platformer.md +117 -0
- package/library/skills/make-game/references/2d-rpg-content.md +234 -0
- package/library/skills/make-game/references/2d-rpg.md +241 -0
- package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
- package/library/skills/make-game/references/2d-survivors.md +237 -0
- package/library/skills/make-game/references/3d-fps-systems.md +216 -0
- package/library/skills/make-game/references/3d-fps.md +177 -0
- package/library/skills/make-game/references/3d-horror-systems.md +186 -0
- package/library/skills/make-game/references/3d-horror.md +201 -0
- package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
- package/library/skills/make-game/references/3d-third-person.md +215 -0
- package/library/skills/make-game/resource.yaml +6 -1
- package/library/skills/multiplayer/SKILL.md +150 -0
- package/library/skills/multiplayer/resource.yaml +33 -0
- package/library/skills/multiplayer-movement/SKILL.md +510 -0
- package/library/skills/multiplayer-movement/files.md +501 -0
- package/library/skills/multiplayer-movement/resource.yaml +30 -0
- package/library/skills/multiplayer-project/SKILL.md +521 -0
- package/library/skills/multiplayer-project/files.md +448 -0
- package/library/skills/multiplayer-project/resource.yaml +36 -0
- package/library/skills/multiplayer-publish/SKILL.md +229 -0
- package/library/skills/multiplayer-publish/export-errors.md +89 -0
- package/library/skills/multiplayer-publish/resource.yaml +28 -0
- package/library/skills/multiplayer-state/SKILL.md +438 -0
- package/library/skills/multiplayer-state/files.md +592 -0
- package/library/skills/multiplayer-state/resource.yaml +35 -0
- package/library/skills/multiplayer-testing/SKILL.md +236 -0
- package/library/skills/multiplayer-testing/resource.yaml +39 -0
- package/library/skills/music-track/SKILL.md +1 -1
- package/library/skills/navigate-summer/SKILL.md +1 -1
- package/library/skills/new-project/SKILL.md +1 -1
- package/library/skills/organic-model/SKILL.md +1 -1
- package/library/skills/pixel-art/SKILL.md +1 -1
- package/library/skills/play/SKILL.md +1 -1
- package/library/skills/playtesting-a-feature/SKILL.md +1 -1
- package/library/skills/procedural-animation/SKILL.md +2 -2
- package/library/skills/procedural-animation/resource.yaml +1 -1
- package/library/skills/prop-model/SKILL.md +1 -1
- package/library/skills/psx-retro-rendering/SKILL.md +1 -1
- package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
- package/library/skills/remote-deploy/SKILL.md +1 -1
- package/library/skills/retarget/SKILL.md +1 -1
- package/library/skills/running-in-the-cloud/SKILL.md +1 -1
- package/library/skills/save-load/SKILL.md +156 -0
- package/library/skills/save-load/resource.yaml +27 -0
- package/library/skills/scene-composition/SKILL.md +1 -1
- package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
- package/library/skills/scene-scripting/SKILL.md +1 -1
- package/library/skills/scene-to-level/SKILL.md +1 -1
- package/library/skills/skill-create/SKILL.md +1 -1
- package/library/skills/skill-improve/SKILL.md +1 -1
- package/library/skills/skill-test/SKILL.md +1 -1
- package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
- package/library/skills/skybox-panorama/SKILL.md +1 -1
- package/library/skills/sound-effect/SKILL.md +1 -1
- package/library/skills/spatial-placement/SKILL.md +134 -3
- package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
- package/library/skills/spatial-placement/resource.yaml +16 -2
- package/library/skills/sprite-sheet/SKILL.md +1 -1
- package/library/skills/summer-analytics/SKILL.md +147 -0
- package/library/skills/summer-analytics/resource.yaml +28 -0
- package/library/skills/summer-friends/SKILL.md +226 -0
- package/library/skills/summer-friends/resource.yaml +28 -0
- package/library/skills/summer-leaderboards/SKILL.md +231 -0
- package/library/skills/summer-leaderboards/resource.yaml +30 -0
- package/library/skills/summer-match-results/SKILL.md +286 -0
- package/library/skills/summer-match-results/resource.yaml +32 -0
- package/library/skills/summer-matchmaking/SKILL.md +301 -0
- package/library/skills/summer-matchmaking/resource.yaml +32 -0
- package/library/skills/summer-parties/SKILL.md +253 -0
- package/library/skills/summer-parties/resource.yaml +30 -0
- package/library/skills/summer-player-data/SKILL.md +322 -0
- package/library/skills/summer-player-data/resource.yaml +30 -0
- package/library/skills/summer-store/SKILL.md +271 -0
- package/library/skills/summer-store/resource.yaml +29 -0
- package/library/skills/summer-world-chat/SKILL.md +195 -0
- package/library/skills/summer-world-chat/resource.yaml +30 -0
- package/library/skills/summer-world-saves/SKILL.md +284 -0
- package/library/skills/summer-world-saves/resource.yaml +29 -0
- package/library/skills/text-to-motion/SKILL.md +99 -0
- package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
- package/library/skills/text-to-motion/resource.yaml +41 -0
- package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
- package/library/skills/tileable-texture/SKILL.md +1 -1
- package/library/skills/trailer-shot/SKILL.md +1 -1
- package/library/skills/tune-performance/SKILL.md +1 -1
- package/library/skills/ui-basics/SKILL.md +10 -1
- package/library/skills/ui-graphics/SKILL.md +1 -1
- package/library/skills/use-widget-asset/SKILL.md +1 -1
- package/library/skills/using-summer/SKILL.md +2 -2
- package/library/skills/using-summer/resource.yaml +2 -2
- package/library/skills/vehicle-model/SKILL.md +1 -1
- package/library/skills/verification-before-completion/SKILL.md +1 -1
- package/library/skills/verifying-scenes/SKILL.md +76 -2
- package/library/skills/verifying-scenes/resource.yaml +13 -2
- package/library/skills/vfx-dissolve/SKILL.md +1 -1
- package/library/skills/vfx-fire/SKILL.md +1 -1
- package/library/skills/vfx-hit-spark/SKILL.md +1 -1
- package/library/skills/vfx-lightning/SKILL.md +1 -1
- package/library/skills/vfx-magic-glow/SKILL.md +1 -1
- package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
- package/library/skills/vfx-smoke/SKILL.md +1 -1
- package/library/skills/vfx-water-ripple/SKILL.md +1 -1
- package/library/skills/voice-line/SKILL.md +1 -1
- package/library/skills/web-and-touch-input/SKILL.md +38 -0
- package/library/skills/web-and-touch-input/resource.yaml +28 -0
- package/library/skills/web-compatibility-look/SKILL.md +62 -0
- package/library/skills/web-compatibility-look/resource.yaml +30 -0
- package/library/skills/world-building-3d/SKILL.md +8 -1
- package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
- package/library/skills/world-building-3d/resource.yaml +2 -1
- package/library/skills/writing-plans/SKILL.md +1 -1
- package/library/skills/writing-skills/SKILL.md +1 -1
- package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
- package/library/tools/attach-to-surface/resource.yaml +142 -0
- package/library/tools/batch/resource.yaml +9 -3
- package/library/tools/connect-ports/resource.yaml +120 -0
- package/library/tools/connect-signal/resource.yaml +3 -2
- package/library/tools/debug-views/resource.yaml +94 -0
- package/library/tools/frame-nodes/resource.yaml +104 -0
- package/library/tools/frame-shot/resource.yaml +134 -0
- package/library/tools/generate-motion/resource.yaml +44 -9
- package/library/tools/get-board/resource.yaml +50 -0
- package/library/tools/get-project-context/resource.yaml +13 -2
- package/library/tools/grep/resource.yaml +77 -0
- package/library/tools/inspect-asset/resource.yaml +71 -0
- package/library/tools/inspect-node/resource.yaml +9 -2
- package/library/tools/inspect-resource/resource.yaml +16 -5
- package/library/tools/instantiate-scene/resource.yaml +27 -2
- package/library/tools/measure/resource.yaml +96 -0
- package/library/tools/place-adjacent/resource.yaml +113 -0
- package/library/tools/play/resource.yaml +15 -2
- package/library/tools/raycast/resource.yaml +101 -0
- package/library/tools/read-file/resource.yaml +36 -2
- package/library/tools/read-library/resource.yaml +2 -2
- package/library/tools/repeat-along/resource.yaml +129 -0
- package/library/tools/replace-node/resource.yaml +11 -5
- package/library/tools/scene-audit/resource.yaml +144 -0
- package/library/tools/screenshot/resource.yaml +13 -2
- package/library/tools/search-assets/resource.yaml +18 -0
- package/library/tools/shot-sheet/resource.yaml +110 -0
- package/library/tools/snap-to-surface/resource.yaml +4 -1
- package/library/tools/world-snapshot/resource.yaml +24 -3
- package/library/tools/zoom/resource.yaml +105 -0
- package/package.json +3 -3
- package/registry/generated/aliases.json +17 -3
- package/registry/generated/counts.json +3 -3
- package/registry/generated/gemini-extension.json +26 -4
- package/registry/generated/index.json +2154 -469
- package/registry/generated/marketplace.claude.json +2 -2
- package/registry/generated/plugin.claude.json +27 -5
- package/registry/generated/plugin.codex.json +28 -6
- package/registry/generated/plugin.cursor.json +27 -5
- package/registry/generated/plugin.factory.json +27 -5
- package/registry/generated/skills-index.md +264 -0
- package/registry/generated/skills-registry.json +901 -206
- package/registry/generated/templates-registry.json +2 -2
- package/library/skills/host-authoritative-state/SKILL.md +0 -332
- package/library/skills/host-authoritative-state/resource.yaml +0 -28
- package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
- package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
- package/library/skills/setup-multiplayer/SKILL.md +0 -336
- package/library/skills/setup-multiplayer/resource.yaml +0 -28
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: character-movement
|
|
3
|
+
description: "Player controllers for 2D and 3D, plus the canonical third-person controller for Summer humanoid packages: movement owns translation, clips follow state."
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Codex, Windsurf, Gemini, OpenCode]
|
|
6
|
+
category: character-controllers
|
|
7
|
+
user-invocable: false
|
|
8
|
+
allowed-tools: Read Grep summer_read_file summer_write_file summer_replace_text summer_get_scene_tree summer_add_node summer_set_prop summer_batch summer_input_map_bind summer_save_scene summer_get_script_errors summer_get_diagnostics summer_play summer_stop
|
|
9
|
+
paths: ["**/*.gd", "**/*.tscn"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Character Movement
|
|
13
|
+
|
|
14
|
+
The player controller is the first thing you build and the thing the user feels
|
|
15
|
+
in the first 3 seconds. Ship the smallest correct controller, then tune feel.
|
|
16
|
+
|
|
17
|
+
Trigger phrases: "add player movement", "the player can't move / falls through
|
|
18
|
+
the floor", "wire my imported character as the player", "walk/run/jump
|
|
19
|
+
animations", "mouse look", "make the jump feel better".
|
|
20
|
+
|
|
21
|
+
Supporting files live in this skill's `references/` folder, next to this
|
|
22
|
+
SKILL.md. Open only the one the task needs:
|
|
23
|
+
|
|
24
|
+
| File | Read when |
|
|
25
|
+
|------|-----------|
|
|
26
|
+
| `references/default-third-person-controller.gd` | standard playable third-person Summer humanoid package; copy this exact controller instead of rewriting it |
|
|
27
|
+
| `references/default-third-person-verification-probe.gd` | runtime proof for that controller; pass it unchanged as a `RunVerification` `probe_source` |
|
|
28
|
+
| `references/platformer-feel.md` | jump feels bad, coyote time, jump buffering, variable jump height, one-way platforms |
|
|
29
|
+
| `references/movement-3d.md` | FPS/third-person controllers, mouse look, sprint, crouch, spring-arm camera |
|
|
30
|
+
|
|
31
|
+
## Default playable Summer character
|
|
32
|
+
|
|
33
|
+
For a standard playable third-person Summer humanoid package, install this
|
|
34
|
+
skill's `references/default-third-person-controller.gd` unchanged as the player
|
|
35
|
+
script. Do not rewrite or reconstruct it from the snippets below. Customize the
|
|
36
|
+
installed file only when the user explicitly asks for different controls or
|
|
37
|
+
behavior.
|
|
38
|
+
|
|
39
|
+
Install it byte-exact:
|
|
40
|
+
|
|
41
|
+
1. Take the full text of `references/default-third-person-controller.gd` from
|
|
42
|
+
this skill's folder, unchanged (tabs, comments and all).
|
|
43
|
+
2. New destination:
|
|
44
|
+
`summer_write_file(path="res://scripts/player.gd", content=<that text>, create_only=true)`.
|
|
45
|
+
Existing destination: `summer_read_file(path="res://scripts/player.gd")`
|
|
46
|
+
first, then `summer_write_file(path=..., content=<that text>, expected_sha256=<sha256 from the read>)`.
|
|
47
|
+
3. Confirm the copy is exact: the write receipt's sha256 must equal the sha256
|
|
48
|
+
of the source file (hash it locally when you have a shell; otherwise
|
|
49
|
+
`summer_read_file` the result and compare it to the source text).
|
|
50
|
+
|
|
51
|
+
Do not edit the installed file, add roles, or add an `AnimationTree` merely
|
|
52
|
+
because the user selected more package clips: choosing clips is not a request
|
|
53
|
+
to customize controls or behavior. When the user does explicitly request
|
|
54
|
+
different controls or behavior, install the exact canonical source first, then
|
|
55
|
+
`summer_read_file` the installed project file and change it with
|
|
56
|
+
`summer_replace_text`. Configure the manifest path and node paths on the scene
|
|
57
|
+
instance.
|
|
58
|
+
|
|
59
|
+
Required main-scene shape:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
Main (Node3D)
|
|
63
|
+
Player (CharacterBody3D) # template script
|
|
64
|
+
CollisionShape3D # capsule
|
|
65
|
+
CharacterRotationRoot (Node3D) # only this node turns
|
|
66
|
+
Character # imported character.tscn instance
|
|
67
|
+
CameraYaw (Node3D)
|
|
68
|
+
CameraPitch (Node3D)
|
|
69
|
+
SpringArm3D
|
|
70
|
+
Camera3D # current = true
|
|
71
|
+
Ground / level geometry # world siblings of Player
|
|
72
|
+
DirectionalLight3D / WorldEnvironment
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
When authoring a new main scene as `.tscn` text (written whole with
|
|
76
|
+
`summer_write_file`, never a hand edit of a scene open in the editor), use this
|
|
77
|
+
exact serialization pattern. Replace only the imported package paths when they
|
|
78
|
+
differ:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
[gd_scene load_steps=7 format=3]
|
|
82
|
+
|
|
83
|
+
[ext_resource type="Script" path="res://scripts/player.gd" id="1_controller"]
|
|
84
|
+
[ext_resource type="PackedScene" path="res://characters/imported/character.tscn" id="2_character"]
|
|
85
|
+
|
|
86
|
+
[sub_resource type="CapsuleShape3D" id="PlayerCapsule"]
|
|
87
|
+
radius = 0.45
|
|
88
|
+
height = 1.8
|
|
89
|
+
|
|
90
|
+
[sub_resource type="BoxShape3D" id="GroundShape"]
|
|
91
|
+
size = Vector3(20, 0.5, 20)
|
|
92
|
+
|
|
93
|
+
[sub_resource type="BoxMesh" id="GroundMesh"]
|
|
94
|
+
size = Vector3(20, 0.5, 20)
|
|
95
|
+
|
|
96
|
+
[sub_resource type="Environment" id="WorldEnvironment"]
|
|
97
|
+
background_mode = 1
|
|
98
|
+
background_color = Color(0.12, 0.18, 0.3, 1)
|
|
99
|
+
ambient_light_energy = 0.6
|
|
100
|
+
|
|
101
|
+
[node name="Main" type="Node3D"]
|
|
102
|
+
|
|
103
|
+
[node name="Player" type="CharacterBody3D" parent="."]
|
|
104
|
+
position = Vector3(0, 1, 0)
|
|
105
|
+
script = ExtResource("1_controller")
|
|
106
|
+
character_manifest_path = "res://characters/imported/character.json"
|
|
107
|
+
|
|
108
|
+
[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"]
|
|
109
|
+
shape = SubResource("PlayerCapsule")
|
|
110
|
+
|
|
111
|
+
[node name="CharacterRotationRoot" type="Node3D" parent="Player"]
|
|
112
|
+
|
|
113
|
+
[node name="Character" parent="Player/CharacterRotationRoot" instance=ExtResource("2_character")]
|
|
114
|
+
|
|
115
|
+
[node name="CameraYaw" type="Node3D" parent="Player"]
|
|
116
|
+
|
|
117
|
+
[node name="CameraPitch" type="Node3D" parent="Player/CameraYaw"]
|
|
118
|
+
rotation = Vector3(-0.349066, 0, 0)
|
|
119
|
+
|
|
120
|
+
[node name="SpringArm3D" type="SpringArm3D" parent="Player/CameraYaw/CameraPitch"]
|
|
121
|
+
spring_length = 5.0
|
|
122
|
+
|
|
123
|
+
[node name="Camera3D" type="Camera3D" parent="Player/CameraYaw/CameraPitch/SpringArm3D"]
|
|
124
|
+
current = true
|
|
125
|
+
|
|
126
|
+
[node name="Ground" type="StaticBody3D" parent="."]
|
|
127
|
+
position = Vector3(0, -0.25, 0)
|
|
128
|
+
|
|
129
|
+
[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"]
|
|
130
|
+
mesh = SubResource("GroundMesh")
|
|
131
|
+
|
|
132
|
+
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"]
|
|
133
|
+
shape = SubResource("GroundShape")
|
|
134
|
+
|
|
135
|
+
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
|
136
|
+
rotation_degrees = Vector3(-55, -30, 0)
|
|
137
|
+
shadow_enabled = true
|
|
138
|
+
|
|
139
|
+
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
|
140
|
+
environment = SubResource("WorldEnvironment")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Every nested `parent` is the complete path from the scene root, excluding the
|
|
144
|
+
root node's own name. Never shorten
|
|
145
|
+
`parent="Player/CameraYaw/CameraPitch"` to `parent="CameraPitch"`. A
|
|
146
|
+
`PackedScene` instance belongs in the `[node ...]` header and has no `type`;
|
|
147
|
+
never write a typed `Node3D` followed by `instance = ExtResource(...)` in the
|
|
148
|
+
node body. The playable body is a child of the world root. Ground, level
|
|
149
|
+
geometry, lights, and environment remain siblings of `Player`, never children
|
|
150
|
+
of it, so they do not move with the player.
|
|
151
|
+
|
|
152
|
+
Set `character_manifest_path` to the imported package's `character.json`. Bind
|
|
153
|
+
`move_left`, `move_right`, `move_forward`, `move_back`, `jump`, and `sprint`
|
|
154
|
+
before running, one `summer_input_map_bind` per action (e.g.
|
|
155
|
+
`summer_input_map_bind(name="move_forward", events=[{"type": "key", "key": "W"}])`);
|
|
156
|
+
`ui_cancel` is a built-in action — confirm it is still bound. The controller
|
|
157
|
+
asserts every one of them at `_ready`. Do not attach this template during generic import or
|
|
158
|
+
to an NPC unless the user explicitly asks for player-style control.
|
|
159
|
+
|
|
160
|
+
The default camera has horizontal mouse orbit only. `CameraPitch` is set once to
|
|
161
|
+
a modest downward angle and vertical mouse motion does not change it. The
|
|
162
|
+
controller keeps a short floor snap plus a small downward grounded velocity so
|
|
163
|
+
ordinary horizontal movement does not create a false airborne `Jump` state. It
|
|
164
|
+
also records the spawn point and respawns after falling below `respawn_below_y`.
|
|
165
|
+
|
|
166
|
+
A bind T/A-pose survives every static check: the AnimationPlayer is wired, the
|
|
167
|
+
clip is named `Idle`, and the files on disk all read correctly. Only a running
|
|
168
|
+
frame separates that from a character actually at rest.
|
|
169
|
+
|
|
170
|
+
**Runtime proof.** Read this skill's
|
|
171
|
+
`references/default-third-person-verification-probe.gd` and pass its full text
|
|
172
|
+
unchanged as the `probe_source` of a `RunVerification` op, which runs it in a
|
|
173
|
+
hidden, disposable game instance that never touches the editor:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
summer_batch(ops=[{"op": "RunVerification", "max_seconds": 30, "probe_source": "<the probe file, unchanged>"}])
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The probe samples the live Skeleton3D after
|
|
180
|
+
the player reaches the floor, requires the real resting clip to be named `Idle`,
|
|
181
|
+
verifies that its pose actually changes, rejects an idle whose hands remain level
|
|
182
|
+
with the upper arms like a bind T/A-pose, saves separate idle and moving frames,
|
|
183
|
+
verifies W moves toward world `-Z`, and verifies vertical mouse input leaves
|
|
184
|
+
camera pitch unchanged. Every boolean in `results` must be `true`; open the saved
|
|
185
|
+
idle and moving frames listed in `frames` before you describe them. A `false` is
|
|
186
|
+
a finding to fix, not a flaky probe.
|
|
187
|
+
|
|
188
|
+
**If the probe cannot run** (the op returns `ok: false` with a `failure_reason`
|
|
189
|
+
such as `spawn_failed`, or the engine build lacks the op), the runtime question
|
|
190
|
+
belongs to the user. Do not paste the probe into the project. Finish on the
|
|
191
|
+
saved state: the manifest path written into the
|
|
192
|
+
Player node, the four semantic roles present, CameraYaw at identity and
|
|
193
|
+
CameraPitch at its fixed angle in the `.tscn` text, the InputMap actions bound,
|
|
194
|
+
and clean diagnostics. Then tell the user which idle clip should be playing at
|
|
195
|
+
rest, so it is the first thing they look at on Play. That is a complete
|
|
196
|
+
integration handed off for a playtest, not an incomplete one.
|
|
197
|
+
|
|
198
|
+
## Order of operations
|
|
199
|
+
|
|
200
|
+
1. Root node must be `CharacterBody2D` or `CharacterBody3D`. `move_and_slide()`
|
|
201
|
+
only exists on these. RigidBody is for physics props, not players.
|
|
202
|
+
2. Give it a `CollisionShape2D/3D` with a real shape (CapsuleShape for 3D humans,
|
|
203
|
+
RectangleShape/CapsuleShape2D for 2D). No shape = falls through everything.
|
|
204
|
+
3. Read gravity from project settings, never hardcode it, so tuning one value
|
|
205
|
+
fixes the whole game: `ProjectSettings.get_setting("physics/2d/default_gravity")`.
|
|
206
|
+
4. Bind input actions BEFORE the script references them (`move_left`, `jump`, ...).
|
|
207
|
+
Referencing an unbound action is a silent no-op that reads as "controls dead".
|
|
208
|
+
5. Compile-check, then run and watch it move. Feel is a user call, not a still frame.
|
|
209
|
+
|
|
210
|
+
## 2D side-scroller controller (the 40% every 2D game shares)
|
|
211
|
+
|
|
212
|
+
```gdscript
|
|
213
|
+
extends CharacterBody2D
|
|
214
|
+
|
|
215
|
+
@export var speed: float = 200.0
|
|
216
|
+
@export var jump_velocity: float = -350.0 # negative = up in 2D
|
|
217
|
+
|
|
218
|
+
var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
|
|
219
|
+
|
|
220
|
+
func _physics_process(delta: float) -> void:
|
|
221
|
+
if not is_on_floor():
|
|
222
|
+
velocity.y += gravity * delta
|
|
223
|
+
if Input.is_action_just_pressed("jump") and is_on_floor():
|
|
224
|
+
velocity.y = jump_velocity
|
|
225
|
+
var dir := Input.get_axis("move_left", "move_right")
|
|
226
|
+
velocity.x = dir * speed if dir else move_toward(velocity.x, 0.0, speed)
|
|
227
|
+
move_and_slide()
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Flip the sprite with `$Sprite2D.flip_h = velocity.x < 0` only when `velocity.x != 0`.
|
|
231
|
+
For real platformer feel (coyote time, jump buffer, variable height) load
|
|
232
|
+
`references/platformer-feel.md`.
|
|
233
|
+
|
|
234
|
+
## Top-down controller (RPG / twin-stick / survivors)
|
|
235
|
+
|
|
236
|
+
No gravity. 8-directional, normalize so diagonals are not faster.
|
|
237
|
+
|
|
238
|
+
```gdscript
|
|
239
|
+
extends CharacterBody2D
|
|
240
|
+
|
|
241
|
+
@export var speed: float = 220.0
|
|
242
|
+
|
|
243
|
+
func _physics_process(_delta: float) -> void:
|
|
244
|
+
var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
|
|
245
|
+
velocity = dir * speed
|
|
246
|
+
move_and_slide()
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Survivors-style games with 200+ agents: enemies are `Area2D` moved with
|
|
250
|
+
`position += dir * speed * delta`, NOT physics bodies. See the `make-game`
|
|
251
|
+
skill's `../make-game/references/2d-survivors.md`. The PLAYER stays a CharacterBody2D.
|
|
252
|
+
|
|
253
|
+
## 3D controller (first + third person)
|
|
254
|
+
|
|
255
|
+
Both share the same body + gravity + `Input.get_vector` floor logic. The only
|
|
256
|
+
difference is where the camera lives and how look rotation is applied. Full
|
|
257
|
+
first-person and third-person controllers, mouse look, sprint, crouch, and
|
|
258
|
+
spring-arm setup are in `references/movement-3d.md` - load it for any 3D player.
|
|
259
|
+
|
|
260
|
+
Minimal 3D walk (no look yet):
|
|
261
|
+
|
|
262
|
+
```gdscript
|
|
263
|
+
extends CharacterBody3D
|
|
264
|
+
|
|
265
|
+
@export var speed: float = 5.0
|
|
266
|
+
@export var jump_velocity: float = 4.5
|
|
267
|
+
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
|
268
|
+
|
|
269
|
+
func _physics_process(delta: float) -> void:
|
|
270
|
+
if not is_on_floor():
|
|
271
|
+
velocity.y -= gravity * delta
|
|
272
|
+
if Input.is_action_just_pressed("jump") and is_on_floor():
|
|
273
|
+
velocity.y = jump_velocity
|
|
274
|
+
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
|
275
|
+
var direction := (transform.basis * Vector3(input_dir.x, 0.0, input_dir.y)).normalized()
|
|
276
|
+
if direction:
|
|
277
|
+
velocity.x = direction.x * speed
|
|
278
|
+
velocity.z = direction.z * speed
|
|
279
|
+
else:
|
|
280
|
+
velocity.x = move_toward(velocity.x, 0.0, speed)
|
|
281
|
+
velocity.z = move_toward(velocity.z, 0.0, speed)
|
|
282
|
+
move_and_slide()
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Summer humanoid package
|
|
286
|
+
|
|
287
|
+
When the player visual is a Summer character package:
|
|
288
|
+
|
|
289
|
+
1. Produce or import the package first — it comes from the shared character
|
|
290
|
+
pipeline (`character-model`; `summer_generate_3d` with rigging and animations)
|
|
291
|
+
and carries `character.tscn` plus its `character.json` manifest. Instantiate
|
|
292
|
+
`character.tscn`; for clip wiring without this controller see
|
|
293
|
+
`character-animation-wiring`.
|
|
294
|
+
2. Put the normalized wrapper under a `CharacterBody3D`; do not modify the package or
|
|
295
|
+
scale the body.
|
|
296
|
+
3. Let controller velocity and `move_and_slide()` own all scene translation. Idle, Walk,
|
|
297
|
+
Run, and Jump are in-place visual clips; never add their root motion to velocity.
|
|
298
|
+
4. Resolve the four clips from `character.json` semantic roles instead of guessing names.
|
|
299
|
+
Require every requested role; never substitute one role for another.
|
|
300
|
+
5. Select one state from physics: airborne -> Jump, stopped -> Idle, moving -> Walk,
|
|
301
|
+
sprinting -> Run. Airborne Jump has highest priority and never falls back to Walk/Run.
|
|
302
|
+
Change clips only when the state changes, so Jump plays once per takeoff.
|
|
303
|
+
6. Rotate the visual child toward non-zero movement while preserving the normalized
|
|
304
|
+
`-Z` forward axis. Turn only visual yaw; do not rotate the collision body merely to
|
|
305
|
+
turn the mesh. Keep the third-person camera behind the visual on local `+Z`.
|
|
306
|
+
|
|
307
|
+
Do not put player controls into the generation pipeline or generic character importer.
|
|
308
|
+
|
|
309
|
+
## Camera-follow basics
|
|
310
|
+
|
|
311
|
+
- 2D: add a `Camera2D` as a CHILD of the player (it is active while `enabled`,
|
|
312
|
+
the default), `position_smoothing_enabled = true`, speed 5-8. Add
|
|
313
|
+
`limit_left/right/top/bottom` so it never shows past the level edge. Full rigs
|
|
314
|
+
in the `camera-rigs` skill.
|
|
315
|
+
- 3D first-person: camera is a child of a `Head` node; yaw rotates the body,
|
|
316
|
+
pitch rotates the Head (never the body) to avoid gimbal lock.
|
|
317
|
+
- 3D third-person: camera on a `SpringArm3D` so walls push it in. See `camera-rigs`.
|
|
318
|
+
|
|
319
|
+
## Traps
|
|
320
|
+
|
|
321
|
+
- Scaling the CharacterBody node breaks collision + velocity. Scale the MESH/Sprite
|
|
322
|
+
child instead. In 3D, 1 unit = 1 meter; a human is ~1.0-2.0 tall.
|
|
323
|
+
- `is_on_floor()` is only valid AFTER `move_and_slide()` ran once this frame.
|
|
324
|
+
- Diagonal speed-up = you forgot to normalize the input vector.
|
|
325
|
+
- Mouse captured with no release traps the user. Always pair
|
|
326
|
+
`Input.MOUSE_MODE_CAPTURED` with a `ui_cancel` handler that sets it VISIBLE.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
class_name SummerThirdPersonController
|
|
2
|
+
extends CharacterBody3D
|
|
3
|
+
|
|
4
|
+
## Canonical controller for a playable Summer humanoid character package.
|
|
5
|
+
## Copy this file unchanged first. Customize the copy only when the user asks.
|
|
6
|
+
|
|
7
|
+
const REQUIRED_ROLES: Array[StringName] = [&"idle", &"walk", &"run", &"jump"]
|
|
8
|
+
const REQUIRED_ACTIONS: Array[StringName] = [
|
|
9
|
+
&"move_left",
|
|
10
|
+
&"move_right",
|
|
11
|
+
&"move_forward",
|
|
12
|
+
&"move_back",
|
|
13
|
+
&"jump",
|
|
14
|
+
&"sprint",
|
|
15
|
+
&"ui_cancel",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
@export_file("*.json") var character_manifest_path: String
|
|
19
|
+
|
|
20
|
+
@export_category("Movement")
|
|
21
|
+
@export var walk_speed: float = 4.0
|
|
22
|
+
@export var run_speed: float = 7.0
|
|
23
|
+
@export var acceleration: float = 24.0
|
|
24
|
+
@export var jump_velocity: float = 5.5
|
|
25
|
+
@export var turn_speed: float = 12.0
|
|
26
|
+
@export var floor_snap_distance: float = 0.3
|
|
27
|
+
@export var floor_stick_velocity: float = 0.5
|
|
28
|
+
|
|
29
|
+
@export_category("Camera")
|
|
30
|
+
@export var mouse_sensitivity: float = 0.002
|
|
31
|
+
@export var camera_height: float = 1.5
|
|
32
|
+
@export var camera_distance: float = 4.5
|
|
33
|
+
@export_flags_3d_physics var camera_collision_mask: int = 1
|
|
34
|
+
@export var camera_pitch_degrees: float = -20.0
|
|
35
|
+
|
|
36
|
+
@export_category("Respawn")
|
|
37
|
+
@export var respawn_below_y: float = -15.0
|
|
38
|
+
|
|
39
|
+
@export_category("Required Nodes")
|
|
40
|
+
@export_node_path("Node3D") var visual_root_path: NodePath = ^"CharacterRotationRoot"
|
|
41
|
+
@export_node_path("Node3D") var camera_yaw_path: NodePath = ^"CameraYaw"
|
|
42
|
+
@export_node_path("Node3D") var camera_pitch_path: NodePath = ^"CameraYaw/CameraPitch"
|
|
43
|
+
@export_node_path("SpringArm3D") var spring_arm_path: NodePath = ^"CameraYaw/CameraPitch/SpringArm3D"
|
|
44
|
+
@export_node_path("AnimationPlayer") var animation_player_path: NodePath = ^"CharacterRotationRoot/Character/Visual/AnimationPlayer"
|
|
45
|
+
|
|
46
|
+
@onready var _visual_root: Node3D = get_node(visual_root_path) as Node3D
|
|
47
|
+
@onready var _camera_yaw: Node3D = get_node(camera_yaw_path) as Node3D
|
|
48
|
+
@onready var _camera_pitch: Node3D = get_node(camera_pitch_path) as Node3D
|
|
49
|
+
@onready var _spring_arm: SpringArm3D = get_node(spring_arm_path) as SpringArm3D
|
|
50
|
+
@onready var _animation_player: AnimationPlayer = get_node(animation_player_path) as AnimationPlayer
|
|
51
|
+
|
|
52
|
+
var _gravity: float = 0.0
|
|
53
|
+
var _spawn_position: Vector3
|
|
54
|
+
var _clips_by_role: Dictionary = {}
|
|
55
|
+
var _active_role: StringName = &""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
func _ready() -> void:
|
|
59
|
+
_validate_scene_contract()
|
|
60
|
+
_gravity = float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
|
61
|
+
_spawn_position = global_position
|
|
62
|
+
floor_snap_length = floor_snap_distance
|
|
63
|
+
_camera_yaw.position.y = camera_height
|
|
64
|
+
_camera_pitch.rotation = Vector3(deg_to_rad(camera_pitch_degrees), 0.0, 0.0)
|
|
65
|
+
_spring_arm.spring_length = camera_distance
|
|
66
|
+
_spring_arm.collision_mask = camera_collision_mask
|
|
67
|
+
_spring_arm.add_excluded_object(get_rid())
|
|
68
|
+
_configure_character_animation()
|
|
69
|
+
_play_role(&"idle")
|
|
70
|
+
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
func _unhandled_input(event: InputEvent) -> void:
|
|
74
|
+
if event.is_action_pressed(&"ui_cancel"):
|
|
75
|
+
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
|
76
|
+
return
|
|
77
|
+
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
|
78
|
+
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
79
|
+
if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED:
|
|
80
|
+
return
|
|
81
|
+
if event is InputEventMouseMotion:
|
|
82
|
+
_camera_yaw.rotate_y(-event.screen_relative.x * mouse_sensitivity)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
func _physics_process(delta: float) -> void:
|
|
86
|
+
var was_on_floor := is_on_floor()
|
|
87
|
+
if was_on_floor:
|
|
88
|
+
# A small downward velocity keeps the body snapped to flat and gently
|
|
89
|
+
# descending floors instead of producing a one-frame false airborne state.
|
|
90
|
+
velocity.y = -floor_stick_velocity
|
|
91
|
+
else:
|
|
92
|
+
velocity.y -= _gravity * delta
|
|
93
|
+
if Input.is_action_just_pressed(&"jump") and was_on_floor:
|
|
94
|
+
velocity.y = jump_velocity
|
|
95
|
+
|
|
96
|
+
var input_vector: Vector2 = Input.get_vector(
|
|
97
|
+
&"move_left",
|
|
98
|
+
&"move_right",
|
|
99
|
+
&"move_forward",
|
|
100
|
+
&"move_back"
|
|
101
|
+
)
|
|
102
|
+
var camera_forward: Vector3 = -_camera_yaw.global_transform.basis.z
|
|
103
|
+
var camera_right: Vector3 = _camera_yaw.global_transform.basis.x
|
|
104
|
+
camera_forward.y = 0.0
|
|
105
|
+
camera_right.y = 0.0
|
|
106
|
+
camera_forward = camera_forward.normalized()
|
|
107
|
+
camera_right = camera_right.normalized()
|
|
108
|
+
var movement_direction: Vector3 = (
|
|
109
|
+
camera_right * input_vector.x + camera_forward * -input_vector.y
|
|
110
|
+
)
|
|
111
|
+
if movement_direction.length_squared() > 1.0:
|
|
112
|
+
movement_direction = movement_direction.normalized()
|
|
113
|
+
|
|
114
|
+
var is_sprinting: bool = Input.is_action_pressed(&"sprint")
|
|
115
|
+
var target_speed: float = run_speed if is_sprinting else walk_speed
|
|
116
|
+
var target_velocity: Vector3 = movement_direction * target_speed
|
|
117
|
+
velocity.x = move_toward(velocity.x, target_velocity.x, acceleration * delta)
|
|
118
|
+
velocity.z = move_toward(velocity.z, target_velocity.z, acceleration * delta)
|
|
119
|
+
|
|
120
|
+
move_and_slide()
|
|
121
|
+
_turn_visual_toward(movement_direction, delta)
|
|
122
|
+
_update_animation_state(is_sprinting)
|
|
123
|
+
if global_position.y < respawn_below_y:
|
|
124
|
+
global_position = _spawn_position
|
|
125
|
+
velocity = Vector3.ZERO
|
|
126
|
+
_play_role(&"idle")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
func _validate_scene_contract() -> void:
|
|
130
|
+
assert(_visual_root != null, "Missing CharacterRotationRoot")
|
|
131
|
+
assert(_camera_yaw != null, "Missing CameraYaw")
|
|
132
|
+
assert(_camera_pitch != null, "Missing CameraPitch")
|
|
133
|
+
assert(_spring_arm != null, "Missing SpringArm3D")
|
|
134
|
+
assert(_animation_player != null, "Missing character AnimationPlayer")
|
|
135
|
+
assert(character_manifest_path != "", "Set character_manifest_path")
|
|
136
|
+
for action in REQUIRED_ACTIONS:
|
|
137
|
+
assert(InputMap.has_action(action), "Missing input action: %s" % action)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
func _configure_character_animation() -> void:
|
|
141
|
+
var file := FileAccess.open(character_manifest_path, FileAccess.READ)
|
|
142
|
+
assert(file != null, "Missing character manifest: %s" % character_manifest_path)
|
|
143
|
+
var manifest = JSON.parse_string(file.get_as_text())
|
|
144
|
+
assert(manifest is Dictionary, "Invalid character manifest JSON")
|
|
145
|
+
assert(manifest.get("status") == "ready", "Character package is not ready")
|
|
146
|
+
assert(
|
|
147
|
+
manifest.get("normalization", {}).get("forwardAxis") == "-Z",
|
|
148
|
+
"Character package forward axis must be -Z"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
for entry in manifest.get("animations", []):
|
|
152
|
+
if not entry is Dictionary:
|
|
153
|
+
continue
|
|
154
|
+
var role := StringName(String(entry.get("semanticRole", "")).to_lower())
|
|
155
|
+
if role not in REQUIRED_ROLES:
|
|
156
|
+
continue
|
|
157
|
+
var clip := StringName(String(entry.get("name", "")))
|
|
158
|
+
assert(clip != &"", "Requested character role has no clip: %s" % role)
|
|
159
|
+
assert(not _clips_by_role.has(role), "Ambiguous character role: %s" % role)
|
|
160
|
+
assert(_animation_player.has_animation(clip), "Manifest clip is not playable: %s" % clip)
|
|
161
|
+
_clips_by_role[role] = clip
|
|
162
|
+
|
|
163
|
+
for role in REQUIRED_ROLES:
|
|
164
|
+
assert(_clips_by_role.has(role), "Missing requested character role: %s" % role)
|
|
165
|
+
for role in [&"idle", &"walk", &"run"]:
|
|
166
|
+
_animation_player.get_animation(_clips_by_role[role]).loop_mode = Animation.LOOP_LINEAR
|
|
167
|
+
_animation_player.get_animation(_clips_by_role[&"jump"]).loop_mode = Animation.LOOP_NONE
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
func _update_animation_state(is_sprinting: bool) -> void:
|
|
171
|
+
var horizontal_speed := Vector2(velocity.x, velocity.z).length()
|
|
172
|
+
var next_role: StringName
|
|
173
|
+
if not is_on_floor():
|
|
174
|
+
next_role = &"jump"
|
|
175
|
+
elif horizontal_speed <= 0.05:
|
|
176
|
+
next_role = &"idle"
|
|
177
|
+
elif is_sprinting:
|
|
178
|
+
next_role = &"run"
|
|
179
|
+
else:
|
|
180
|
+
next_role = &"walk"
|
|
181
|
+
_play_role(next_role)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
func _play_role(role: StringName) -> void:
|
|
185
|
+
assert(_clips_by_role.has(role), "Missing requested character role: %s" % role)
|
|
186
|
+
if role == _active_role:
|
|
187
|
+
return
|
|
188
|
+
_animation_player.play(_clips_by_role[role])
|
|
189
|
+
# Apply the first keyed pose immediately. This prevents a visible bind-pose
|
|
190
|
+
# frame while the AnimationPlayer waits for its next process tick.
|
|
191
|
+
_animation_player.advance(0.0)
|
|
192
|
+
_active_role = role
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
func _turn_visual_toward(direction: Vector3, delta: float) -> void:
|
|
196
|
+
if direction.length_squared() <= 0.0001:
|
|
197
|
+
return
|
|
198
|
+
var local_direction: Vector3 = global_transform.basis.inverse() * direction
|
|
199
|
+
var target_yaw := atan2(-local_direction.x, -local_direction.z)
|
|
200
|
+
var weight := 1.0 - exp(-turn_speed * delta)
|
|
201
|
+
_visual_root.rotation.y = lerp_angle(_visual_root.rotation.y, target_yaw, weight)
|
package/library/skills/character-movement/references/default-third-person-verification-probe.gd
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
extends SummerProbeBase
|
|
2
|
+
|
|
3
|
+
## Runtime proof for the canonical playable humanoid controller.
|
|
4
|
+
## Pass this source unchanged as the probe_source of a RunVerification op:
|
|
5
|
+
## summer_batch(ops=[{"op": "RunVerification", "max_seconds": 30, "probe_source": <this file>}])
|
|
6
|
+
##
|
|
7
|
+
## If RunVerification cannot run, this file is not part of your job: finish on
|
|
8
|
+
## the saved state and hand the playtest to the user. Do not paste this into a
|
|
9
|
+
## script, a scene, or the project.
|
|
10
|
+
## Saved frames come back in the result's `frames`; every reported boolean must
|
|
11
|
+
## be true.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
func _find_first(node: Node, type_name: StringName) -> Node:
|
|
15
|
+
if node.is_class(type_name):
|
|
16
|
+
return node
|
|
17
|
+
for child in node.get_children():
|
|
18
|
+
var found := _find_first(child, type_name)
|
|
19
|
+
if found != null:
|
|
20
|
+
return found
|
|
21
|
+
return null
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
func _pose_delta(before: Transform3D, after: Transform3D) -> float:
|
|
25
|
+
var translation_delta := before.origin.distance_to(after.origin)
|
|
26
|
+
var rotation_delta := before.basis.get_rotation_quaternion().angle_to(
|
|
27
|
+
after.basis.get_rotation_quaternion()
|
|
28
|
+
)
|
|
29
|
+
return maxf(translation_delta, rotation_delta)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
func _arm_down_ratio(
|
|
33
|
+
skeleton: Skeleton3D,
|
|
34
|
+
upper_arm_name: StringName,
|
|
35
|
+
hand_name: StringName
|
|
36
|
+
) -> float:
|
|
37
|
+
var upper_arm_index := skeleton.find_bone(upper_arm_name)
|
|
38
|
+
var hand_index := skeleton.find_bone(hand_name)
|
|
39
|
+
if upper_arm_index < 0 or hand_index < 0:
|
|
40
|
+
return -1.0
|
|
41
|
+
var upper_arm_position := skeleton.get_bone_global_pose(upper_arm_index).origin
|
|
42
|
+
var hand_position := skeleton.get_bone_global_pose(hand_index).origin
|
|
43
|
+
var arm_vector := hand_position - upper_arm_position
|
|
44
|
+
if arm_vector.length_squared() <= 0.000001:
|
|
45
|
+
return -1.0
|
|
46
|
+
return (upper_arm_position.y - hand_position.y) / arm_vector.length()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
func _ready() -> void:
|
|
50
|
+
await super._ready()
|
|
51
|
+
await settle(20)
|
|
52
|
+
|
|
53
|
+
var scene := get_tree().current_scene
|
|
54
|
+
var player := _find_first(scene, &"CharacterBody3D") as CharacterBody3D
|
|
55
|
+
report("player_exists", player != null)
|
|
56
|
+
if player == null:
|
|
57
|
+
finish()
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
# Fresh scenes commonly spawn the capsule above the platform. Sampling after
|
|
61
|
+
# a fixed 20 frames can catch the initial Jump clip and falsely call it idle.
|
|
62
|
+
# Wait a bounded amount for real floor contact, then give the controller one
|
|
63
|
+
# short state transition window before measuring the resting animation.
|
|
64
|
+
for frame_index in 120:
|
|
65
|
+
if player.is_on_floor():
|
|
66
|
+
break
|
|
67
|
+
await settle(1)
|
|
68
|
+
report("idle_grounded", player.is_on_floor())
|
|
69
|
+
await settle(12)
|
|
70
|
+
|
|
71
|
+
var animation_player := _find_first(player, &"AnimationPlayer") as AnimationPlayer
|
|
72
|
+
var skeleton := _find_first(player, &"Skeleton3D") as Skeleton3D
|
|
73
|
+
report("animation_player_exists", animation_player != null)
|
|
74
|
+
report("skeleton_exists", skeleton != null)
|
|
75
|
+
if animation_player == null or skeleton == null:
|
|
76
|
+
finish()
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
var idle_animation := String(animation_player.current_animation)
|
|
80
|
+
report("idle_animation", idle_animation)
|
|
81
|
+
report(
|
|
82
|
+
"idle_named",
|
|
83
|
+
idle_animation == "Idle" or idle_animation.ends_with("/Idle")
|
|
84
|
+
)
|
|
85
|
+
report("idle_playing", animation_player.is_playing())
|
|
86
|
+
|
|
87
|
+
var before: Array[Transform3D] = []
|
|
88
|
+
for bone_index in skeleton.get_bone_count():
|
|
89
|
+
before.append(skeleton.get_bone_global_pose(bone_index))
|
|
90
|
+
await settle(24)
|
|
91
|
+
var maximum_pose_delta := 0.0
|
|
92
|
+
for bone_index in skeleton.get_bone_count():
|
|
93
|
+
maximum_pose_delta = maxf(
|
|
94
|
+
maximum_pose_delta,
|
|
95
|
+
_pose_delta(
|
|
96
|
+
before[bone_index],
|
|
97
|
+
skeleton.get_bone_global_pose(bone_index)
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
report("idle_pose_delta", maximum_pose_delta)
|
|
101
|
+
report("idle_moves_skeleton", maximum_pose_delta > 0.0001)
|
|
102
|
+
|
|
103
|
+
var left_arm_down_ratio := _arm_down_ratio(
|
|
104
|
+
skeleton,
|
|
105
|
+
&"LeftArm",
|
|
106
|
+
&"LeftHand"
|
|
107
|
+
)
|
|
108
|
+
var right_arm_down_ratio := _arm_down_ratio(
|
|
109
|
+
skeleton,
|
|
110
|
+
&"RightArm",
|
|
111
|
+
&"RightHand"
|
|
112
|
+
)
|
|
113
|
+
var idle_arm_bones_exist := (
|
|
114
|
+
left_arm_down_ratio >= 0.0 and right_arm_down_ratio >= 0.0
|
|
115
|
+
)
|
|
116
|
+
var idle_arms_relaxed := (
|
|
117
|
+
idle_arm_bones_exist
|
|
118
|
+
and minf(left_arm_down_ratio, right_arm_down_ratio) > 0.2
|
|
119
|
+
and (left_arm_down_ratio + right_arm_down_ratio) * 0.5 > 0.55
|
|
120
|
+
)
|
|
121
|
+
report("idle_arm_bones_exist", idle_arm_bones_exist)
|
|
122
|
+
report("idle_left_arm_down_ratio", left_arm_down_ratio)
|
|
123
|
+
report("idle_right_arm_down_ratio", right_arm_down_ratio)
|
|
124
|
+
report("idle_arms_relaxed", idle_arms_relaxed)
|
|
125
|
+
await save_frame("canonical-third-person-idle")
|
|
126
|
+
|
|
127
|
+
var camera_pitch := player.get_node_or_null("CameraYaw/CameraPitch") as Node3D
|
|
128
|
+
report("camera_pitch_exists", camera_pitch != null)
|
|
129
|
+
if camera_pitch != null:
|
|
130
|
+
var pitch_before := camera_pitch.rotation
|
|
131
|
+
var vertical_mouse := InputEventMouseMotion.new()
|
|
132
|
+
vertical_mouse.relative = Vector2(0.0, 160.0)
|
|
133
|
+
player._unhandled_input(vertical_mouse)
|
|
134
|
+
report(
|
|
135
|
+
"vertical_mouse_keeps_fixed_pitch",
|
|
136
|
+
camera_pitch.rotation.is_equal_approx(pitch_before)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
var start_position := player.global_position
|
|
140
|
+
Input.action_press(&"move_forward")
|
|
141
|
+
await settle(24)
|
|
142
|
+
var moving_animation := animation_player.current_animation
|
|
143
|
+
var moving_position := player.global_position
|
|
144
|
+
Input.action_release(&"move_forward")
|
|
145
|
+
report("forward_progress", start_position.z - moving_position.z)
|
|
146
|
+
report("forward_moves_toward_minus_z", moving_position.z < start_position.z)
|
|
147
|
+
report("locomotion_animation", moving_animation)
|
|
148
|
+
report(
|
|
149
|
+
"locomotion_animation_active",
|
|
150
|
+
moving_animation == "Walk" or moving_animation == "Run"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
await save_frame("canonical-third-person-moving")
|
|
154
|
+
finish()
|