summer-engine 3.1.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 +102 -0
- package/README.md +18 -3
- package/assets/audit/scene_audit.gd +4136 -0
- package/assets/seeing/seeing_probe.gd +1873 -0
- package/dist/cli/commands/skills.js +20 -2
- 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 +18 -2
- 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/installer/agent-config.js +5 -3
- package/dist/installer/agent-table.d.ts +16 -0
- package/dist/installer/agent-table.js +52 -17
- 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/amp/README.md +1 -1
- package/integrations/crush/README.md +1 -1
- package/integrations/grok-build/README.md +1 -1
- package/integrations/hermes/README.md +1 -1
- package/integrations/kimi-code/README.md +1 -1
- package/integrations/mistral-vibe/README.md +1 -1
- package/integrations/opencode/README.md +1 -1
- package/integrations/rovo-dev/README.md +1 -1
- package/integrations/vscode-copilot/README.md +1 -1
- package/integrations/warp/README.md +1 -1
- package/integrations/windsurf/README.md +1 -1
- 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 +36 -14
- 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 +1 -1
- 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 +36 -14
- package/registry/generated/skills-registry.json +421 -124
- 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,62 @@
|
|
|
1
|
+
export declare const KERNEL_PATH: string;
|
|
2
|
+
export declare function loadKernelSource(): string;
|
|
3
|
+
/** Engine paths always use forward slashes (Windows accepts them too). */
|
|
4
|
+
export declare function enginePath(path: string): string;
|
|
5
|
+
/** Escape a string for a quoted value in a text scene (.tscn): the engine's
|
|
6
|
+
* variant parser unescapes \\ and \" ; newlines may stay literal. */
|
|
7
|
+
export declare function escapeTscnString(value: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* The wrapper scene. The ONLY caller-derived value in it is the target scene
|
|
10
|
+
* path, which must already have passed validateScenePath (res://, no quotes,
|
|
11
|
+
* backslashes, newlines or `$`); it is escaped again here as defence in depth.
|
|
12
|
+
* Every other argument travels as data in config.json, which the kernel finds
|
|
13
|
+
* through its own script path and parses as JSON — nothing is spliced into
|
|
14
|
+
* GDScript source.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildWrapperScene(targetScenePath: string, kernelSource: string): string;
|
|
17
|
+
/** The engine reads ScenePreview through the shared ops path. */
|
|
18
|
+
export interface ProbeClient {
|
|
19
|
+
executeOps(ops: Record<string, unknown>[], options?: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export interface ProbeImage {
|
|
22
|
+
base64: string;
|
|
23
|
+
mime: string;
|
|
24
|
+
width?: number;
|
|
25
|
+
height?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ProbeRun {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
/** The kernel's result.json, when it got far enough to write one. */
|
|
30
|
+
result: Record<string, unknown> | null;
|
|
31
|
+
/** The composed frame ScenePreview read back (render mode). */
|
|
32
|
+
image?: ProbeImage;
|
|
33
|
+
/** The temp directory: captures live here until dispose(). */
|
|
34
|
+
dir: string;
|
|
35
|
+
failureReason?: string;
|
|
36
|
+
error?: string;
|
|
37
|
+
dispose(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export interface RunProbeOptions {
|
|
40
|
+
scenePath: string;
|
|
41
|
+
config: Record<string, unknown>;
|
|
42
|
+
/** Another kernel to run the same private-copy way (default: the seeing
|
|
43
|
+
* kernel). summer_scene_audit passes assets/audit/scene_audit.gd. */
|
|
44
|
+
kernel?: string;
|
|
45
|
+
/** ScenePreview output size; the canvas for render mode, tiny for analyze. */
|
|
46
|
+
size: [number, number];
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
}
|
|
49
|
+
export declare const PROBE_DIR_PREFIX = "summer-seeing-";
|
|
50
|
+
/**
|
|
51
|
+
* Per-call run directory for the wrapper scene, its config and captures:
|
|
52
|
+
* mkdtemp DIRECTLY in the OS temp directory (random name, mode 0700). There is
|
|
53
|
+
* deliberately no shared fixed parent such as <tmp>/summer-engine/seeing: on
|
|
54
|
+
* a multi-user machine (Linux /tmp) another user could pre-create or symlink
|
|
55
|
+
* that parent and swap the wrapper scene the engine then loads and runs as
|
|
56
|
+
* code. The directory is re-checked before anything is written into it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function makeProbeDir(): Promise<string>;
|
|
59
|
+
/** Refuse a run directory that is not a real directory owned by this user
|
|
60
|
+
* with no group/other permissions (symlink, shared, or foreign). */
|
|
61
|
+
export declare function assertPrivateDir(dir: string): Promise<void>;
|
|
62
|
+
export declare function runProbe(client: ProbeClient, options: RunProbeOptions, dirOverride?: string): Promise<ProbeRun>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run the seeing kernel (assets/seeing/seeing_probe.gd) inside the engine.
|
|
3
|
+
*
|
|
4
|
+
* How: write a throwaway wrapper scene to a fresh OS temp directory — it
|
|
5
|
+
* instances the target scene as "Subject" and carries the kernel as a
|
|
6
|
+
* built-in @tool script — then render that wrapper with the existing
|
|
7
|
+
* ScenePreview op (absolute scene_path). ScenePreview instantiates it in an
|
|
8
|
+
* offscreen SubViewport with its own World3D, so the kernel works on a private
|
|
9
|
+
* copy: the edited scene, its undo history and every project file stay
|
|
10
|
+
* untouched (ScenePreview is read-only, and the op executor discards the empty
|
|
11
|
+
* undo action it opens). The kernel writes result.json (and tile captures,
|
|
12
|
+
* when asked) into the same temp directory; the caller reads them and the
|
|
13
|
+
* directory is removed afterwards. No engine change, no child process.
|
|
14
|
+
*
|
|
15
|
+
* Why not RunSceneScript / RunEditorScript: RunSceneScript marks the open scene
|
|
16
|
+
* unsaved after every run, even a read-only one; RunEditorScript boots a
|
|
17
|
+
* headless child editor that has no renderer at all.
|
|
18
|
+
*/
|
|
19
|
+
import { lstat, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
20
|
+
import { readFileSync } from "node:fs";
|
|
21
|
+
import { tmpdir } from "node:os";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { PACKAGE_ROOT } from "../../package-root.js";
|
|
24
|
+
import { getFailureReason } from "../engine-receipt.js";
|
|
25
|
+
export const KERNEL_PATH = join(PACKAGE_ROOT, "assets", "seeing", "seeing_probe.gd");
|
|
26
|
+
let kernelCache = null;
|
|
27
|
+
export function loadKernelSource() {
|
|
28
|
+
if (kernelCache === null)
|
|
29
|
+
kernelCache = readFileSync(KERNEL_PATH, "utf-8");
|
|
30
|
+
return kernelCache;
|
|
31
|
+
}
|
|
32
|
+
/** Engine paths always use forward slashes (Windows accepts them too). */
|
|
33
|
+
export function enginePath(path) {
|
|
34
|
+
return path.replace(/\\/g, "/");
|
|
35
|
+
}
|
|
36
|
+
/** Escape a string for a quoted value in a text scene (.tscn): the engine's
|
|
37
|
+
* variant parser unescapes \\ and \" ; newlines may stay literal. */
|
|
38
|
+
export function escapeTscnString(value) {
|
|
39
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The wrapper scene. The ONLY caller-derived value in it is the target scene
|
|
43
|
+
* path, which must already have passed validateScenePath (res://, no quotes,
|
|
44
|
+
* backslashes, newlines or `$`); it is escaped again here as defence in depth.
|
|
45
|
+
* Every other argument travels as data in config.json, which the kernel finds
|
|
46
|
+
* through its own script path and parses as JSON — nothing is spliced into
|
|
47
|
+
* GDScript source.
|
|
48
|
+
*/
|
|
49
|
+
export function buildWrapperScene(targetScenePath, kernelSource) {
|
|
50
|
+
const script = kernelSource;
|
|
51
|
+
return [
|
|
52
|
+
"[gd_scene format=3]",
|
|
53
|
+
"",
|
|
54
|
+
`[ext_resource type="PackedScene" path="${escapeTscnString(targetScenePath)}" id="1_subject"]`,
|
|
55
|
+
"",
|
|
56
|
+
'[sub_resource type="GDScript" id="GDScript_seeing"]',
|
|
57
|
+
`script/source = "${escapeTscnString(script)}"`,
|
|
58
|
+
"",
|
|
59
|
+
'[node name="SummerSeeing" type="Node3D"]',
|
|
60
|
+
"",
|
|
61
|
+
'[node name="Subject" parent="." instance=ExtResource("1_subject")]',
|
|
62
|
+
"",
|
|
63
|
+
'[node name="SeeingProbe" type="Node" parent="."]',
|
|
64
|
+
'script = SubResource("GDScript_seeing")',
|
|
65
|
+
"",
|
|
66
|
+
].join("\n");
|
|
67
|
+
}
|
|
68
|
+
function firstResult(response) {
|
|
69
|
+
if (!response || typeof response !== "object")
|
|
70
|
+
return {};
|
|
71
|
+
const envelope = response;
|
|
72
|
+
const first = Array.isArray(envelope.results) ? envelope.results[0] : undefined;
|
|
73
|
+
if (first && typeof first === "object")
|
|
74
|
+
return first;
|
|
75
|
+
return envelope;
|
|
76
|
+
}
|
|
77
|
+
export const PROBE_DIR_PREFIX = "summer-seeing-";
|
|
78
|
+
/**
|
|
79
|
+
* Per-call run directory for the wrapper scene, its config and captures:
|
|
80
|
+
* mkdtemp DIRECTLY in the OS temp directory (random name, mode 0700). There is
|
|
81
|
+
* deliberately no shared fixed parent such as <tmp>/summer-engine/seeing: on
|
|
82
|
+
* a multi-user machine (Linux /tmp) another user could pre-create or symlink
|
|
83
|
+
* that parent and swap the wrapper scene the engine then loads and runs as
|
|
84
|
+
* code. The directory is re-checked before anything is written into it.
|
|
85
|
+
*/
|
|
86
|
+
export async function makeProbeDir() {
|
|
87
|
+
const dir = await mkdtemp(join(tmpdir(), PROBE_DIR_PREFIX));
|
|
88
|
+
await assertPrivateDir(dir);
|
|
89
|
+
return dir;
|
|
90
|
+
}
|
|
91
|
+
/** Refuse a run directory that is not a real directory owned by this user
|
|
92
|
+
* with no group/other permissions (symlink, shared, or foreign). */
|
|
93
|
+
export async function assertPrivateDir(dir) {
|
|
94
|
+
const info = await lstat(dir);
|
|
95
|
+
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
96
|
+
throw new Error(`Refusing seeing run directory ${dir}: not a real directory.`);
|
|
97
|
+
}
|
|
98
|
+
if (process.platform === "win32")
|
|
99
|
+
return;
|
|
100
|
+
if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
|
|
101
|
+
throw new Error(`Refusing seeing run directory ${dir}: owned by another user.`);
|
|
102
|
+
}
|
|
103
|
+
if ((info.mode & 0o077) !== 0) {
|
|
104
|
+
throw new Error(`Refusing seeing run directory ${dir}: group/other can access it (mode ${(info.mode & 0o777).toString(8)}).`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export async function runProbe(client, options, dirOverride) {
|
|
108
|
+
const dir = dirOverride ?? (await makeProbeDir());
|
|
109
|
+
await assertPrivateDir(dir);
|
|
110
|
+
const dispose = async () => {
|
|
111
|
+
await rm(dir, { recursive: true, force: true }).catch(() => undefined);
|
|
112
|
+
};
|
|
113
|
+
const configPath = join(dir, "config.json");
|
|
114
|
+
const wrapperPath = join(dir, "wrapper.tscn");
|
|
115
|
+
const config = { ...options.config, scene_path: options.scenePath };
|
|
116
|
+
await writeFile(configPath, JSON.stringify(config));
|
|
117
|
+
await writeFile(wrapperPath, buildWrapperScene(options.scenePath, options.kernel ?? loadKernelSource()));
|
|
118
|
+
let response;
|
|
119
|
+
try {
|
|
120
|
+
response = await client.executeOps([
|
|
121
|
+
{
|
|
122
|
+
op: "ScenePreview",
|
|
123
|
+
scene_path: enginePath(wrapperPath),
|
|
124
|
+
// A fixed pose keeps ScenePreview from injecting its flat preview
|
|
125
|
+
// environment or an auxiliary light into the shared world; the
|
|
126
|
+
// kernel turns this camera's own 3D pass off.
|
|
127
|
+
framing: "free",
|
|
128
|
+
camera_position: "Vector3(0, 10, 10)",
|
|
129
|
+
camera_look_at: "Vector3(0, 0, 0)",
|
|
130
|
+
size: options.size,
|
|
131
|
+
},
|
|
132
|
+
], undefined, options.timeoutMs ?? 120_000);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
return { ok: false, result: null, dir, failureReason: "transport", error: err instanceof Error ? err.message : String(err), dispose };
|
|
136
|
+
}
|
|
137
|
+
const op = firstResult(response);
|
|
138
|
+
let result = null;
|
|
139
|
+
try {
|
|
140
|
+
result = JSON.parse(await readFile(join(dir, "result.json"), "utf-8"));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
result = null;
|
|
144
|
+
}
|
|
145
|
+
if (op.ok === false || response?.ok === false) {
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
result,
|
|
149
|
+
dir,
|
|
150
|
+
failureReason: getFailureReason(op) ?? getFailureReason(response) ?? "preview_failed",
|
|
151
|
+
error: typeof op.error === "string" ? op.error : JSON.stringify(op).slice(0, 400),
|
|
152
|
+
dispose,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const base64 = typeof op.image_base64 === "string" ? op.image_base64 : typeof op.base64 === "string" ? op.base64 : undefined;
|
|
156
|
+
const image = base64
|
|
157
|
+
? {
|
|
158
|
+
base64,
|
|
159
|
+
mime: typeof op.mime === "string" ? op.mime : "image/jpeg",
|
|
160
|
+
...(typeof op.width === "number" ? { width: op.width } : {}),
|
|
161
|
+
...(typeof op.height === "number" ? { height: op.height } : {}),
|
|
162
|
+
}
|
|
163
|
+
: undefined;
|
|
164
|
+
if (!result) {
|
|
165
|
+
return {
|
|
166
|
+
ok: false,
|
|
167
|
+
result: null,
|
|
168
|
+
image,
|
|
169
|
+
dir,
|
|
170
|
+
failureReason: "probe_did_not_run",
|
|
171
|
+
error: "The seeing kernel never wrote its result: the wrapper scene loaded but the built-in @tool script did not run (a script compile error, or the target scene failed to load). Read summer_get_console for the engine's error.",
|
|
172
|
+
dispose,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (result.ok !== true) {
|
|
176
|
+
const errors = Array.isArray(result.errors) ? result.errors.map(String).join("; ") : "";
|
|
177
|
+
return {
|
|
178
|
+
ok: false,
|
|
179
|
+
result,
|
|
180
|
+
image,
|
|
181
|
+
dir,
|
|
182
|
+
failureReason: typeof result.failure_reason === "string" ? result.failure_reason : "probe_failed",
|
|
183
|
+
error: errors || `The seeing kernel stopped at stage "${String(result.stage)}".`,
|
|
184
|
+
dispose,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return { ok: true, result, image, dir, dispose };
|
|
188
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart framing, part 2: score what each candidate pose would see. Pure and
|
|
3
|
+
* engine-free; the inputs are the engine's measurements (thick-sweep
|
|
4
|
+
* visibility codes, near-lens/low-angle adjustments, and a ray grid through
|
|
5
|
+
* the frame with a class and a distance per cell).
|
|
6
|
+
*
|
|
7
|
+
* Terms (each 0..1): visibility, fill, thirds, horizon, sky, void, depth,
|
|
8
|
+
* foreground, clear, balance, detail, contrast, entry, solid (no surfaces
|
|
9
|
+
* seen from behind), light (key-light direction) and edge (no world edge
|
|
10
|
+
* below the horizon). Weights depend on the shot type. Hard rejections
|
|
11
|
+
* (blocked by walls/terrain, camera behind or inside a surface, camera in
|
|
12
|
+
* geometry, subject out of frame, too much clutter, an eye-level or corridor
|
|
13
|
+
* camera off eye height) never rank, but are counted by reason. Establishing
|
|
14
|
+
* shots rank in tiers: a pose that shows more than EMPTY_LIMIT empty ground or
|
|
15
|
+
* world edge ranks below every pose that shows less, whatever the weights.
|
|
16
|
+
*/
|
|
17
|
+
import { type Candidate, type ShotType } from "./candidates.js";
|
|
18
|
+
import { type Aabb, type CameraPose, type Vec3 } from "./math.js";
|
|
19
|
+
export declare const SCORE_TERMS: readonly ["visibility", "fill", "thirds", "horizon", "sky", "void", "depth", "foreground", "clear", "balance", "detail", "contrast", "entry", "solid", "light", "edge"];
|
|
20
|
+
export type ScoreTerm = (typeof SCORE_TERMS)[number];
|
|
21
|
+
export interface ShotProfile {
|
|
22
|
+
fillTarget: number;
|
|
23
|
+
fillTolerance: number;
|
|
24
|
+
sky: [number, number];
|
|
25
|
+
foregroundTarget: number;
|
|
26
|
+
foregroundMax: number;
|
|
27
|
+
weights: Record<ScoreTerm, number>;
|
|
28
|
+
/** Tier rule: a pose whose empty share (world edge + empty ground) is over
|
|
29
|
+
* this ranks below every pose at or under it. */
|
|
30
|
+
emptyLimit?: number;
|
|
31
|
+
}
|
|
32
|
+
/** Establishing: "about 15%" empty ground or world edge is decisive. */
|
|
33
|
+
export declare const EMPTY_LIMIT = 0.15;
|
|
34
|
+
export declare const SHOT_PROFILES: Record<ShotType, ShotProfile>;
|
|
35
|
+
/** What the engine measured for one candidate (seeing_probe.gd _measure_one). */
|
|
36
|
+
export interface Measurement {
|
|
37
|
+
i: number;
|
|
38
|
+
position: Vec3;
|
|
39
|
+
look_at: Vec3;
|
|
40
|
+
fov: number;
|
|
41
|
+
rejected?: string;
|
|
42
|
+
near_lens_hit?: string;
|
|
43
|
+
adjustments?: Array<Record<string, unknown>>;
|
|
44
|
+
/** One code per sample: V visible, T seen through transparent surfaces
|
|
45
|
+
* (partial weight), F soft-occluded, H hard-blocked, B behind a surface
|
|
46
|
+
* (the line crosses a hard or subject surface from its BACK side: culled,
|
|
47
|
+
* so the image would look through it). */
|
|
48
|
+
vis?: string;
|
|
49
|
+
blockers_hard?: string[];
|
|
50
|
+
blockers_soft?: string[];
|
|
51
|
+
/** Surfaces the sight lines crossed from behind ("B" samples). */
|
|
52
|
+
blockers_back?: string[];
|
|
53
|
+
/** Transparent surfaces the sight lines passed through ("T" samples). */
|
|
54
|
+
seen_through?: string[];
|
|
55
|
+
/** Row-major ray grid codes: "." nothing (sky/void), S subject, H hard,
|
|
56
|
+
* F soft, T transparent (seen through), B a hard/subject surface met from
|
|
57
|
+
* behind (not drawn). */
|
|
58
|
+
grid?: string;
|
|
59
|
+
/** Distance per grid cell, -1 for no hit. */
|
|
60
|
+
dist?: number[];
|
|
61
|
+
/** Image check (a small beauty render of the final pose), per grid cell:
|
|
62
|
+
* luminance decile and texture spread, "0" = featureless. */
|
|
63
|
+
lum?: string;
|
|
64
|
+
tex?: string;
|
|
65
|
+
/** Height of the first solid surface straight below the final camera
|
|
66
|
+
* position; null = nothing below it (the world edge). */
|
|
67
|
+
ground_y?: number | null;
|
|
68
|
+
}
|
|
69
|
+
export interface ScoringOptions {
|
|
70
|
+
shot: ShotType;
|
|
71
|
+
aspect: number;
|
|
72
|
+
gridCols: number;
|
|
73
|
+
gridRows: number;
|
|
74
|
+
/** Subject bounds for fill/thirds/in-frame/depth; absent = no subject. */
|
|
75
|
+
subject?: Aabb;
|
|
76
|
+
maxHardFraction: number;
|
|
77
|
+
maxSoftFraction: number;
|
|
78
|
+
/** Direction the key light TRAVELS (a DirectionalLight3D's -Z); absent =
|
|
79
|
+
* no light term. */
|
|
80
|
+
keyLight?: Vec3;
|
|
81
|
+
}
|
|
82
|
+
/** A frame showing more than this share of surfaces from behind is a camera
|
|
83
|
+
* behind (or inside) a wall: the image would look through it. */
|
|
84
|
+
export declare const MAX_BACK_SHARE = 0.25;
|
|
85
|
+
export interface FrameStats {
|
|
86
|
+
sky: number;
|
|
87
|
+
void: number;
|
|
88
|
+
subject: number;
|
|
89
|
+
hard: number;
|
|
90
|
+
soft: number;
|
|
91
|
+
foreground: number;
|
|
92
|
+
/** Fraction of non-subject, non-foreground cells hitting hard geometry no
|
|
93
|
+
* more than 40% beyond the subject: a flat wall right behind it. */
|
|
94
|
+
wallBehind: number;
|
|
95
|
+
/** Cells whose first surface is a hard/subject surface seen from behind
|
|
96
|
+
* (not drawn: the image looks through it). */
|
|
97
|
+
back: number;
|
|
98
|
+
/** Cells whose first surface is transparent (seen through). */
|
|
99
|
+
translucent: number;
|
|
100
|
+
/** Fraction of the frame covered by hard geometry right at the lens
|
|
101
|
+
* (closer than max(2.5 m, 15% of the subject distance)). */
|
|
102
|
+
nearHard: number;
|
|
103
|
+
/** Near-wall share in the left vs right half of the frame. */
|
|
104
|
+
nearLeft: number;
|
|
105
|
+
nearRight: number;
|
|
106
|
+
/** Image check: share of the frame that renders featureless (sky excluded),
|
|
107
|
+
* and mean luminance decile of near vs far cells. */
|
|
108
|
+
flat?: number;
|
|
109
|
+
nearLum?: number;
|
|
110
|
+
farLum?: number;
|
|
111
|
+
/** Image check: share of the frame that is featureless ground or
|
|
112
|
+
* surroundings outside the subject's footprint, below the horizon (a bare
|
|
113
|
+
* plain, a fogged backing plane). */
|
|
114
|
+
emptyGround?: number;
|
|
115
|
+
/** World edge + empty ground: what the establishing tier rule reads. */
|
|
116
|
+
empty?: number;
|
|
117
|
+
}
|
|
118
|
+
export interface ScoredCandidate {
|
|
119
|
+
id: string;
|
|
120
|
+
index: number;
|
|
121
|
+
pose: CameraPose;
|
|
122
|
+
total: number;
|
|
123
|
+
terms: Partial<Record<ScoreTerm, number>>;
|
|
124
|
+
rejected?: string;
|
|
125
|
+
stats?: FrameStats;
|
|
126
|
+
hardFraction?: number;
|
|
127
|
+
softFraction?: number;
|
|
128
|
+
fill?: number;
|
|
129
|
+
inFrame?: number;
|
|
130
|
+
adjustments?: Array<Record<string, unknown>>;
|
|
131
|
+
blockers?: {
|
|
132
|
+
hard?: string[];
|
|
133
|
+
soft?: string[];
|
|
134
|
+
back?: string[];
|
|
135
|
+
through?: string[];
|
|
136
|
+
lens?: string;
|
|
137
|
+
};
|
|
138
|
+
note?: string;
|
|
139
|
+
/** The first solid surface straight below the camera (null: none). */
|
|
140
|
+
groundY?: number | null;
|
|
141
|
+
/** 0 = clean; 1 = over the shot's empty limit (ranks below every tier 0). */
|
|
142
|
+
tier?: number;
|
|
143
|
+
}
|
|
144
|
+
export declare function foregroundScore(share: number, target: number, max: number): number;
|
|
145
|
+
export declare function thirdsScore(pose: CameraPose, aspect: number, box: Aabb): number;
|
|
146
|
+
/**
|
|
147
|
+
* Poses are built with a level up vector, so roll is always zero (a level
|
|
148
|
+
* horizon by construction); what is left to judge is where the horizon cuts
|
|
149
|
+
* the frame. Eye-level and corridor shots are one-point perspective views
|
|
150
|
+
* where a centered horizon is natural; elsewhere a horizon through the dead
|
|
151
|
+
* center splits the frame in two and is marked down.
|
|
152
|
+
*/
|
|
153
|
+
export declare function horizonScore(pose: CameraPose, shot?: ShotType): number;
|
|
154
|
+
/**
|
|
155
|
+
* One featureless grid cell (image check tex "0") is empty ground when its ray
|
|
156
|
+
* points below the horizon and meets non-subject geometry outside the
|
|
157
|
+
* subject's footprint (+ 0.5 m) and below its middle: the bare ground or
|
|
158
|
+
* fogged backing plane around the subject, not the subject's own floor.
|
|
159
|
+
*/
|
|
160
|
+
export declare function isEmptyGround(code: string | undefined, d: number, ray: Vec3, pose: CameraPose, subject: Aabb | undefined): boolean;
|
|
161
|
+
export declare function frameStats(m: Measurement, pose: CameraPose, opts: ScoringOptions): {
|
|
162
|
+
stats: FrameStats;
|
|
163
|
+
depth: number;
|
|
164
|
+
};
|
|
165
|
+
/** Ratio (0..1) of the median wall distance in the frame's left and right
|
|
166
|
+
* quarters; 0 when one side shows no wall at all. */
|
|
167
|
+
export declare function edgeSymmetry(m: Measurement, opts: ScoringOptions): number;
|
|
168
|
+
export interface ViewProblem {
|
|
169
|
+
/** behind_surface | hard_blocked | inside_volume | near_lens_blocked | below_ground */
|
|
170
|
+
reason: string;
|
|
171
|
+
/** One line for a caption. */
|
|
172
|
+
detail: string;
|
|
173
|
+
blockers?: string[];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Is this pose a view a player could have of the subject? The one rule both
|
|
177
|
+
* smart framing (rejection) and frame_nodes (a warning for an explicit pose)
|
|
178
|
+
* use. A sight line that crosses a hard or subject surface from BEHIND is as
|
|
179
|
+
* blocked as one that hits a wall's front: back faces are not drawn, so the
|
|
180
|
+
* image would look through the wall the camera stands behind. A frame that
|
|
181
|
+
* shows more than MAX_BACK_SHARE of surfaces from behind is the same failure
|
|
182
|
+
* seen through the lens; the engine's own lens checks (inside a closed shell,
|
|
183
|
+
* just behind a surface, touching geometry) come through as rejections.
|
|
184
|
+
*/
|
|
185
|
+
export declare function viewProblem(m: Measurement, maxHardFraction?: number): ViewProblem | null;
|
|
186
|
+
/**
|
|
187
|
+
* Eye mode guard (eye_level, corridor): the camera must stand min..max above
|
|
188
|
+
* the solid surface straight below it, and must never have been raised. The
|
|
189
|
+
* engine places eye poses that way; this refuses anything else, so a raised
|
|
190
|
+
* eye can never win. Null when the pose is at eye height.
|
|
191
|
+
*/
|
|
192
|
+
export declare function eyeProblem(m: Measurement, candidate: Candidate): string | null;
|
|
193
|
+
/** Camera height above the solid surface straight below it, or undefined. */
|
|
194
|
+
export declare function heightAboveGround(position: Vec3, groundY: number | null | undefined): number | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Key-light direction relative to the view (0..1). `light` is the direction
|
|
197
|
+
* the light travels. Best: side or front-side light (the faces the camera
|
|
198
|
+
* sees get form and shadow); worst: light from straight behind the camera
|
|
199
|
+
* (a flat-lit face); backlight is in between. A sun near the zenith lights
|
|
200
|
+
* every side alike, so the term flattens toward neutral.
|
|
201
|
+
*/
|
|
202
|
+
export declare function lightScore(pose: CameraPose, light: Vec3): number;
|
|
203
|
+
/** Share of the frame below the horizon that shows sky or void: the world's
|
|
204
|
+
* edge (the ground ends in view). The grid's "." cells with a downward ray. */
|
|
205
|
+
export declare const WORLD_EDGE_LIMIT = 0.04;
|
|
206
|
+
export declare function scoreMeasurement(m: Measurement, candidate: Candidate, opts: ScoringOptions): ScoredCandidate;
|
|
207
|
+
/** Rank order: tier first (a pose over the empty limit loses to every pose
|
|
208
|
+
* under it), then score. */
|
|
209
|
+
export declare function rankOrder(a: ScoredCandidate, b: ScoredCandidate): number;
|
|
210
|
+
export interface PickDiversity {
|
|
211
|
+
/** Ring shots: the yaw of each pick is the camera's azimuth around this
|
|
212
|
+
* point; without it, the yaw of the view direction. */
|
|
213
|
+
around?: Vec3;
|
|
214
|
+
/** Minimum yaw between any two picks, degrees (default 25). */
|
|
215
|
+
minYaw?: number;
|
|
216
|
+
/** Prefer picks from distinct sides (front +Z, right +X, back -Z, left -X)
|
|
217
|
+
* while they score within `sideMargin` of the best (default 0.15). */
|
|
218
|
+
sides?: boolean;
|
|
219
|
+
sideMargin?: number;
|
|
220
|
+
}
|
|
221
|
+
/** Yaw (degrees, 0 = +Z, 90 = +X) of a pose: around `around`, else of its view. */
|
|
222
|
+
export declare function poseYaw(pose: CameraPose, around?: Vec3): number;
|
|
223
|
+
/** Side quadrant of a yaw: 0 front (+Z), 1 right (+X), 2 back (-Z), 3 left (-X). */
|
|
224
|
+
export declare function sideOf(yaw: number): number;
|
|
225
|
+
/**
|
|
226
|
+
* Top `count` non-rejected candidates in score order, skipping near-duplicates
|
|
227
|
+
* (camera within `minSeparation` m AND looking within 12 degrees of a better
|
|
228
|
+
* pick). With `diversity`, the picks also spread out: first one per side
|
|
229
|
+
* (within the score margin), then any pose at least `minYaw` from every pick,
|
|
230
|
+
* and only then the plain near-duplicate rule fills what is left — so the top
|
|
231
|
+
* 3 of an establishing shot are three different views, not one front view
|
|
232
|
+
* three times.
|
|
233
|
+
*/
|
|
234
|
+
export declare function pickTop(scored: readonly ScoredCandidate[], count: number, minSeparation: number, diversity?: PickDiversity): ScoredCandidate[];
|
|
235
|
+
export declare function rejectionCounts(scored: readonly ScoredCandidate[]): Record<string, number>;
|