@jgengine/shell 0.10.0 → 0.12.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/CHANGELOG.md +39 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/CombatPresentation.d.ts +5 -0
- package/dist/CombatPresentation.js +8 -0
- package/dist/GameHost.d.ts +25 -1
- package/dist/GameHost.js +60 -4
- package/dist/GamePhaseStamp.d.ts +1 -0
- package/dist/GamePhaseStamp.js +9 -0
- package/dist/GamePlayer.d.ts +5 -0
- package/dist/GamePlayer.js +5 -0
- package/dist/GamePlayerShell.d.ts +5 -12
- package/dist/GamePlayerShell.js +67 -1332
- package/dist/GameUiPreview.js +3 -2
- package/dist/Shell3dPresentation.d.ts +63 -0
- package/dist/Shell3dPresentation.js +302 -0
- package/dist/ShellChrome.d.ts +51 -0
- package/dist/ShellChrome.js +51 -0
- package/dist/ShellHudPresentation.d.ts +41 -0
- package/dist/ShellHudPresentation.js +22 -0
- package/dist/audio/audioEngine.d.ts +4 -0
- package/dist/audio/audioEngine.js +128 -21
- package/dist/audio/audioWire.d.ts +40 -0
- package/dist/audio/audioWire.js +62 -0
- package/dist/audio/loopParams.d.ts +20 -0
- package/dist/audio/loopParams.js +28 -0
- package/dist/behaviour.d.ts +2 -1
- package/dist/behaviour.js +2 -1
- package/dist/behaviourAttach.d.ts +1 -0
- package/dist/behaviourAttach.js +1 -0
- package/dist/behaviourDriver.d.ts +1 -0
- package/dist/behaviourDriver.js +1 -0
- package/dist/boundActionDispatch.d.ts +13 -0
- package/dist/boundActionDispatch.js +37 -0
- package/dist/camera/GameCameraRig.d.ts +5 -2
- package/dist/camera/GameCameraRig.js +8 -3
- package/dist/camera/GameFirstPersonCamera.d.ts +9 -2
- package/dist/camera/GameFirstPersonCamera.js +8 -3
- package/dist/camera/GameInspectionCamera.d.ts +1 -1
- package/dist/camera/GameInspectionCamera.js +2 -2
- package/dist/camera/GameOrbitCamera.js +24 -9
- package/dist/camera/cameraBlendMath.d.ts +3 -0
- package/dist/camera/cameraBlendMath.js +3 -0
- package/dist/camera/cameraRigs.d.ts +3 -1
- package/dist/camera/cameraRigs.js +21 -3
- package/dist/camera/fovPreference.d.ts +6 -1
- package/dist/camera/fovPreference.js +6 -1
- package/dist/camera/index.d.ts +4 -7
- package/dist/camera/index.js +4 -7
- package/dist/camera/inspectionCameraMath.d.ts +7 -2
- package/dist/camera/inspectionCameraMath.js +7 -2
- package/dist/camera/orbitCameraMath.d.ts +36 -6
- package/dist/camera/orbitCameraMath.js +56 -6
- package/dist/camera/rigMath.d.ts +114 -24
- package/dist/camera/rigMath.js +129 -24
- package/dist/camera/rigResolve.d.ts +4 -2
- package/dist/camera/rigResolve.js +4 -2
- package/dist/camera/shakeChannel.d.ts +6 -2
- package/dist/camera/shakeChannel.js +6 -2
- package/dist/camera/shakeChannelMath.d.ts +1 -0
- package/dist/camera/shakeChannelMath.js +1 -0
- package/dist/commandSink.d.ts +8 -3
- package/dist/commandSink.js +8 -3
- package/dist/defineGame.d.ts +15 -1
- package/dist/defineGame.js +50 -9
- package/dist/devtools/ColPanel.d.ts +1 -0
- package/dist/devtools/ColPanel.js +14 -0
- package/dist/devtools/DevtoolsOverlay.d.ts +11 -7
- package/dist/devtools/DevtoolsOverlay.js +47 -462
- package/dist/devtools/KeysPanel.d.ts +4 -0
- package/dist/devtools/KeysPanel.js +31 -0
- package/dist/devtools/LogsPanel.d.ts +1 -0
- package/dist/devtools/LogsPanel.js +12 -0
- package/dist/devtools/NetPanel.d.ts +4 -0
- package/dist/devtools/NetPanel.js +10 -0
- package/dist/devtools/PerfPanel.d.ts +4 -0
- package/dist/devtools/PerfPanel.js +53 -0
- package/dist/devtools/TunePanel.d.ts +3 -0
- package/dist/devtools/TunePanel.js +309 -0
- package/dist/devtools/agentBridge.d.ts +41 -0
- package/dist/devtools/agentBridge.js +266 -0
- package/dist/devtools/collisionDebug.d.ts +6 -0
- package/dist/devtools/collisionDebug.js +6 -0
- package/dist/devtools/collisionDebugMath.d.ts +8 -2
- package/dist/devtools/collisionDebugMath.js +24 -5
- package/dist/devtools/devtoolsOverrides.d.ts +6 -0
- package/dist/devtools/devtoolsOverrides.js +48 -0
- package/dist/devtools/panelAtoms.d.ts +9 -0
- package/dist/devtools/panelAtoms.js +10 -0
- package/dist/devtools/perfDiagnose.d.ts +2 -0
- package/dist/devtools/perfDiagnose.js +43 -0
- package/dist/diagnostics/RuntimeDiagnostics.d.ts +36 -0
- package/dist/diagnostics/RuntimeDiagnostics.js +80 -0
- package/dist/drivers/FrameDriver.d.ts +37 -0
- package/dist/drivers/FrameDriver.js +232 -0
- package/dist/drivers/HudOnlyDriver.d.ts +16 -0
- package/dist/drivers/HudOnlyDriver.js +60 -0
- package/dist/environment/Daylight.d.ts +23 -7
- package/dist/environment/Daylight.js +106 -13
- package/dist/environment/EnvironmentScene.js +44 -9
- package/dist/environment/VolumetricClouds.d.ts +17 -0
- package/dist/environment/VolumetricClouds.js +202 -0
- package/dist/environment/daylightCycle.d.ts +3 -1
- package/dist/environment/daylightCycle.js +3 -1
- package/dist/environment/groundPadMath.d.ts +3 -0
- package/dist/environment/groundPadMath.js +3 -0
- package/dist/environment/index.d.ts +1 -0
- package/dist/environment/index.js +1 -0
- package/dist/environment/skyLightingPolicy.d.ts +2 -0
- package/dist/environment/skyLightingPolicy.js +2 -0
- package/dist/environment/terrainGroundColor.d.ts +9 -0
- package/dist/environment/terrainGroundColor.js +22 -0
- package/dist/gameKit.d.ts +27 -0
- package/dist/gameKit.js +29 -0
- package/dist/hotbarActions.d.ts +26 -0
- package/dist/hotbarActions.js +27 -0
- package/dist/inputSink.d.ts +16 -4
- package/dist/inputSink.js +57 -7
- package/dist/map/MapMarkerBeacons.d.ts +3 -2
- package/dist/materialOverride.d.ts +10 -0
- package/dist/materialOverride.js +15 -3
- package/dist/multiplayer.js +8 -2
- package/dist/postfx/PostProcessing.d.ts +9 -1
- package/dist/postfx/PostProcessing.js +56 -11
- package/dist/postfx/gradeShader.js +9 -1
- package/dist/presentationResolve.d.ts +35 -0
- package/dist/presentationResolve.js +51 -0
- package/dist/registry.d.ts +4 -2
- package/dist/render/EnvironmentLighting.d.ts +10 -0
- package/dist/render/EnvironmentLighting.js +34 -0
- package/dist/render/SceneLighting.d.ts +7 -0
- package/dist/render/SceneLighting.js +18 -0
- package/dist/render/SceneModels.d.ts +14 -0
- package/dist/render/SceneModels.js +337 -0
- package/dist/render/assetBase.d.ts +17 -0
- package/dist/render/assetBase.js +35 -0
- package/dist/render/defaultSurface.d.ts +29 -0
- package/dist/render/defaultSurface.js +101 -0
- package/dist/render/modelLoad.d.ts +24 -0
- package/dist/render/modelLoad.js +76 -0
- package/dist/render/modelRender.d.ts +11 -0
- package/dist/render/modelRender.js +15 -0
- package/dist/render/resolveModel.d.ts +54 -3
- package/dist/render/resolveModel.js +116 -4
- package/dist/render/useEntityRenderCues.d.ts +13 -0
- package/dist/render/useEntityRenderCues.js +62 -0
- package/dist/scatter/InstancedScatter.d.ts +24 -0
- package/dist/scatter/InstancedScatter.js +135 -0
- package/dist/scatter/scatterModels.d.ts +25 -0
- package/dist/scatter/scatterModels.js +61 -0
- package/dist/scatter/scatterProxies.d.ts +6 -0
- package/dist/scatter/scatterProxies.js +118 -0
- package/dist/scatter.d.ts +1 -0
- package/dist/scatter.js +1 -0
- package/dist/scene/AuthoredScene.d.ts +84 -0
- package/dist/scene/AuthoredScene.js +178 -0
- package/dist/scene/CityRenderer.d.ts +2 -0
- package/dist/scene/CityRenderer.js +1031 -0
- package/dist/scene/GeneratedAssetRenderer.d.ts +14 -0
- package/dist/scene/GeneratedAssetRenderer.js +59 -0
- package/dist/scene/GrassFieldRenderer.d.ts +2 -0
- package/dist/scene/GrassFieldRenderer.js +73 -0
- package/dist/scene/PoleLineRenderer.d.ts +2 -0
- package/dist/scene/PoleLineRenderer.js +287 -0
- package/dist/scene/SoilPatchRenderer.d.ts +2 -0
- package/dist/scene/SoilPatchRenderer.js +84 -0
- package/dist/scene/StudioStage.d.ts +37 -0
- package/dist/scene/StudioStage.js +42 -0
- package/dist/scene/WaterRenderer.d.ts +2 -0
- package/dist/scene/WaterRenderer.js +61 -0
- package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
- package/dist/scene/builtinSceneKindRenderers.js +26 -0
- package/dist/scene/cityWindowMaterial.d.ts +16 -0
- package/dist/scene/cityWindowMaterial.js +81 -0
- package/dist/scene/sceneKindRenderers.d.ts +30 -0
- package/dist/scene/sceneKindRenderers.js +17 -0
- package/dist/scene.d.ts +1 -0
- package/dist/scene.js +1 -0
- package/dist/settings/appliedSettings.d.ts +7 -1
- package/dist/settings/appliedSettings.js +13 -2
- package/dist/settings/settingsController.d.ts +2 -0
- package/dist/settings/settingsController.js +22 -1
- package/dist/shellConstants.d.ts +4 -0
- package/dist/shellConstants.js +4 -0
- package/dist/shellMovement.d.ts +8 -0
- package/dist/shellMovement.js +11 -0
- package/dist/shellPointer.d.ts +20 -0
- package/dist/shellPointer.js +28 -0
- package/dist/structures/PlacementGhost.d.ts +4 -0
- package/dist/structures/PlacementGhost.js +4 -0
- package/dist/structures/TransformGizmo.d.ts +53 -0
- package/dist/structures/TransformGizmo.js +59 -0
- package/dist/structures/index.d.ts +1 -0
- package/dist/structures/index.js +1 -0
- package/dist/terrain/GrassField.d.ts +11 -3
- package/dist/terrain/GrassField.js +16 -6
- package/dist/terrain/TerraformBrushCursor.js +3 -0
- package/dist/terrain/grassBudget.d.ts +11 -2
- package/dist/terrain/grassBudget.js +20 -4
- package/dist/terrain/grassGeometry.d.ts +35 -0
- package/dist/terrain/grassGeometry.js +85 -20
- package/dist/terrain/grassMaterial.d.ts +20 -0
- package/dist/terrain/grassMaterial.js +68 -13
- package/dist/terrain/heightfieldGeometry.d.ts +34 -0
- package/dist/terrain/heightfieldGeometry.js +109 -0
- package/dist/terrain/index.d.ts +1 -0
- package/dist/terrain/index.js +1 -0
- package/dist/terrain/random.d.ts +3 -0
- package/dist/terrain/random.js +3 -0
- package/dist/terrain/soilPatchMaterial.d.ts +23 -0
- package/dist/terrain/soilPatchMaterial.js +147 -0
- package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
- package/dist/terrain/terrainDetailMaterial.js +87 -7
- package/dist/terrain/terrainMath.d.ts +8 -1
- package/dist/terrain/terrainMath.js +8 -1
- package/dist/touch/TouchControlsOverlay.d.ts +9 -5
- package/dist/touch/TouchControlsOverlay.js +201 -22
- package/dist/useShellMultiplayerSync.d.ts +9 -0
- package/dist/useShellMultiplayerSync.js +98 -0
- package/dist/visibility/CullingProvider.js +1 -1
- package/dist/water/Ocean.d.ts +7 -1
- package/dist/water/Ocean.js +16 -3
- package/dist/water/OceanConfig.d.ts +11 -0
- package/dist/water/OceanConfig.js +8 -0
- package/dist/water/OceanMaterial.d.ts +12 -0
- package/dist/water/OceanMaterial.js +9 -0
- package/dist/water/OceanShader.d.ts +2 -2
- package/dist/water/OceanShader.js +78 -10
- package/dist/weather/fireSpreadPose.d.ts +1 -0
- package/dist/weather/fireSpreadPose.js +1 -0
- package/dist/weather/weatherGeometry.d.ts +1 -0
- package/dist/weather/weatherGeometry.js +1 -0
- package/dist/weather/weatherMath.d.ts +3 -0
- package/dist/weather/weatherMath.js +3 -0
- package/dist/weather/weatherUniforms.d.ts +3 -0
- package/dist/weather/weatherUniforms.js +3 -0
- package/dist/world/PlaceScene.d.ts +11 -0
- package/dist/world/PlaceScene.js +27 -0
- package/dist/world/RetainedVfx.d.ts +10 -0
- package/dist/world/RetainedVfx.js +136 -0
- package/dist/world/WorldHud.d.ts +49 -2
- package/dist/world/WorldHud.js +87 -2
- package/dist/world/WorldScene.d.ts +21 -0
- package/dist/world/WorldScene.js +186 -0
- package/dist/world/WorldVfx.d.ts +9 -0
- package/dist/world/WorldVfx.js +184 -0
- package/dist/world/entityPose.d.ts +2 -0
- package/dist/world/entityPose.js +2 -0
- package/dist/world/floatTextStyle.d.ts +1 -0
- package/dist/world/floatTextStyle.js +1 -0
- package/dist/world/telegraphPulse.d.ts +1 -0
- package/dist/world/telegraphPulse.js +1 -0
- package/dist/world/worldBarSamples.d.ts +25 -0
- package/dist/world/worldBarSamples.js +38 -0
- package/dist/worldSky.d.ts +11 -0
- package/dist/worldSky.js +21 -0
- package/dist/worldSync.d.ts +2 -1
- package/dist/worldSync.js +2 -1
- package/package.json +6 -6
- package/skills/game-design/SKILL.md +28 -0
- package/skills/game-design/agents/openai.yaml +4 -0
- package/skills/game-design/references/application-playbook.md +170 -0
- package/skills/game-design/references/field-guide.md +288 -0
- package/skills/jgengine/SKILL.md +54 -0
- package/skills/jgengine/api.md +527 -0
- package/skills/jgengine/capabilities.md +131 -0
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-ui/SKILL.md +41 -0
- package/skills/jgengine-ui/api.md +2007 -0
- package/skills/jgengine-ui/capabilities.md +211 -0
- package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
- package/skills/jgengine-ui/reference.md +513 -0
- package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
- package/skills/jgengine-world/SKILL.md +51 -0
- package/skills/jgengine-world/api.md +3056 -0
- package/skills/jgengine-world/capabilities.md +476 -0
- package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
- package/skills/jgengine-world/reference.md +261 -0
- package/skills/level-design/SKILL.md +54 -0
- package/skills/level-design/agents/openai.yaml +4 -0
- package/skills/level-design/references/application-playbook.md +192 -0
- package/skills/level-design/references/field-guide.md +337 -0
- package/skills/level-design/references/live-editor-loop.md +179 -0
- package/dist/cartridge.d.ts +0 -145
- package/dist/cartridge.js +0 -246
- package/llms.txt +0 -2761
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component, useState } from "react";
|
|
3
|
+
import { VERSION } from "@jgengine/core/meta/changelog";
|
|
4
|
+
function errorToDiagnostic(error, phase, componentStack) {
|
|
5
|
+
const capturedAt = new Date().toISOString();
|
|
6
|
+
if (error instanceof Error) {
|
|
7
|
+
return { phase, message: error.message, stack: error.stack, componentStack, capturedAt };
|
|
8
|
+
}
|
|
9
|
+
return { phase, message: typeof error === "string" ? error : JSON.stringify(error), componentStack, capturedAt };
|
|
10
|
+
}
|
|
11
|
+
export function logRuntimeError(error, phase, componentStack) {
|
|
12
|
+
const diagnostic = errorToDiagnostic(error, phase, componentStack);
|
|
13
|
+
console.error(`[jgengine:${phase}] ${diagnostic.message}`, error);
|
|
14
|
+
return diagnostic;
|
|
15
|
+
}
|
|
16
|
+
export class GameUiErrorBoundary extends Component {
|
|
17
|
+
state = { failed: false };
|
|
18
|
+
static getDerivedStateFromError() {
|
|
19
|
+
return { failed: true };
|
|
20
|
+
}
|
|
21
|
+
componentDidCatch(error, info) {
|
|
22
|
+
this.props.onRuntimeError(error, "ui-render", info.componentStack ?? undefined);
|
|
23
|
+
}
|
|
24
|
+
render() {
|
|
25
|
+
if (this.state.failed)
|
|
26
|
+
return null;
|
|
27
|
+
return this.props.children;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function expandedReactError(message) {
|
|
31
|
+
return /Minified React error #185\b/.test(message)
|
|
32
|
+
? "Maximum update depth exceeded. A component is repeatedly updating state during render or after every update."
|
|
33
|
+
: null;
|
|
34
|
+
}
|
|
35
|
+
const ISSUES_NEW_URL = "https://github.com/Noisemaker111/jgengine/issues/new";
|
|
36
|
+
/** Standalone error footer text (page, browser, engine) shared by every error surface. */
|
|
37
|
+
export function errorReportContext() {
|
|
38
|
+
return [
|
|
39
|
+
`Engine: ${VERSION}`,
|
|
40
|
+
`Page: ${window.location.origin}${window.location.pathname}`,
|
|
41
|
+
`Browser: ${navigator.userAgent}`,
|
|
42
|
+
].join("\n");
|
|
43
|
+
}
|
|
44
|
+
/** "Copy error" + "File issue" buttons for any error surface. `report` is the full text to copy / prefill. */
|
|
45
|
+
export function ErrorReportActions({ report, issueTitle }) {
|
|
46
|
+
const [copied, setCopied] = useState(false);
|
|
47
|
+
const issueBody = report.length > 8000 ? `${report.slice(0, 8000)}\n\n[Report truncated; use Copy error for the full report.]` : report;
|
|
48
|
+
const issueUrl = `${ISSUES_NEW_URL}?title=${encodeURIComponent(`[BUG] ${issueTitle.slice(0, 120)}`)}&body=${encodeURIComponent(issueBody)}`;
|
|
49
|
+
return (_jsxs("div", { className: "flex gap-2", children: [_jsx("button", { className: "rounded border border-red-300/50 bg-red-900 px-2 py-1 text-xs font-semibold text-red-50 hover:bg-red-800", type: "button", onClick: () => {
|
|
50
|
+
void navigator.clipboard.writeText(report).then(() => {
|
|
51
|
+
setCopied(true);
|
|
52
|
+
window.setTimeout(() => setCopied(false), 2000);
|
|
53
|
+
});
|
|
54
|
+
}, children: copied ? "Copied" : "Copy error" }), _jsx("a", { className: "rounded border border-red-300/50 bg-red-900 px-2 py-1 text-xs font-semibold text-red-50 hover:bg-red-800", href: issueUrl, rel: "noreferrer", target: "_blank", children: "File issue" })] }));
|
|
55
|
+
}
|
|
56
|
+
function diagnosticReport(diagnostic, gameName) {
|
|
57
|
+
const explanation = expandedReactError(diagnostic.message);
|
|
58
|
+
return [
|
|
59
|
+
"JGengine runtime error",
|
|
60
|
+
`Game: ${gameName}`,
|
|
61
|
+
`Phase: ${diagnostic.phase}`,
|
|
62
|
+
`Time: ${diagnostic.capturedAt}`,
|
|
63
|
+
errorReportContext(),
|
|
64
|
+
explanation === null ? null : `Explanation: ${explanation}`,
|
|
65
|
+
"",
|
|
66
|
+
`Message: ${diagnostic.message}`,
|
|
67
|
+
diagnostic.stack === undefined ? null : `JavaScript stack:\n${diagnostic.stack}`,
|
|
68
|
+
diagnostic.componentStack === undefined ? null : `React component stack:\n${diagnostic.componentStack}`,
|
|
69
|
+
]
|
|
70
|
+
.filter((line) => line !== null)
|
|
71
|
+
.join("\n");
|
|
72
|
+
}
|
|
73
|
+
export function DiagnosticOverlay({ diagnostics, gameName }) {
|
|
74
|
+
if (diagnostics.length === 0)
|
|
75
|
+
return null;
|
|
76
|
+
const latest = diagnostics[diagnostics.length - 1];
|
|
77
|
+
const explanation = expandedReactError(latest.message);
|
|
78
|
+
const report = diagnosticReport(latest, gameName);
|
|
79
|
+
return (_jsxs("div", { className: "pointer-events-auto absolute right-4 top-4 z-50 max-w-lg select-text rounded border border-red-400/60 bg-red-950/95 p-3 text-xs text-red-50 shadow-2xl", children: [_jsx("div", { className: "mb-1 font-semibold uppercase tracking-wide text-red-200", children: "JG engine error" }), _jsxs("div", { className: "font-mono text-[11px] text-red-100", children: ["[", latest.phase, "] ", latest.message] }), explanation !== null ? _jsx("div", { className: "mt-2 text-red-100", children: explanation }) : null, latest.stack !== undefined ? (_jsx("pre", { className: "mt-2 max-h-36 overflow-auto whitespace-pre-wrap text-[10px] text-red-200/80", children: latest.stack })) : null, latest.componentStack !== undefined ? (_jsx("pre", { className: "mt-2 max-h-36 overflow-auto whitespace-pre-wrap text-[10px] text-red-200/80", children: latest.componentStack })) : null, _jsx("div", { className: "mt-3", children: _jsx(ErrorReportActions, { report: report, issueTitle: `${latest.phase}: ${latest.message.slice(0, 100)}` }) })] }));
|
|
80
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { GameContext } from "@jgengine/core/runtime/gameContext";
|
|
2
|
+
import type { PointerAxisState } from "@jgengine/core/input/pointerAxis";
|
|
3
|
+
import type { ActionStateTracker } from "@jgengine/core/input/actionBindings";
|
|
4
|
+
import type { PointerService } from "../pointer/pointerService.js";
|
|
5
|
+
import type { ShellMultiplayer } from "../multiplayer.js";
|
|
6
|
+
import type { PlayableGame } from "../registry.js";
|
|
7
|
+
export declare const POSTER_SETTLE_SECONDS = 1.6;
|
|
8
|
+
export declare function FrameDriver({ ctx, playable, tracker, yawRef, pitchRef, primaryClickRef, pointerAxisRef, gateRef, onRuntimeError, multiplayer, serverIdRef, pointerService, pointerAim, pingCommand, poster, onPosterSettled, }: {
|
|
9
|
+
ctx: GameContext;
|
|
10
|
+
playable: PlayableGame;
|
|
11
|
+
tracker: ActionStateTracker<string>;
|
|
12
|
+
yawRef: {
|
|
13
|
+
current: number;
|
|
14
|
+
};
|
|
15
|
+
pitchRef: {
|
|
16
|
+
current: number;
|
|
17
|
+
};
|
|
18
|
+
primaryClickRef: {
|
|
19
|
+
current: boolean;
|
|
20
|
+
};
|
|
21
|
+
pointerAxisRef: {
|
|
22
|
+
current: PointerAxisState | null;
|
|
23
|
+
};
|
|
24
|
+
gateRef: {
|
|
25
|
+
current: boolean;
|
|
26
|
+
};
|
|
27
|
+
onRuntimeError: (error: unknown, phase: string) => void;
|
|
28
|
+
multiplayer: ShellMultiplayer | null;
|
|
29
|
+
serverIdRef: {
|
|
30
|
+
current: string | null;
|
|
31
|
+
};
|
|
32
|
+
pointerService: PointerService;
|
|
33
|
+
pointerAim: boolean;
|
|
34
|
+
pingCommand: string | undefined;
|
|
35
|
+
poster: boolean;
|
|
36
|
+
onPosterSettled: () => void;
|
|
37
|
+
}): null;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { useFrame } from "@react-three/fiber";
|
|
2
|
+
import { useMemo, useRef } from "react";
|
|
3
|
+
import { RESERVED_INPUT_ACTIONS, dispatchBoundAction, heldActionsFor, shouldFireBoundAction } from "../boundActionDispatch.js";
|
|
4
|
+
import { executeHotbarSlot, findHotbarSlotActions, hotbarIdFor } from "../hotbarActions.js";
|
|
5
|
+
import { pointerAimFor } from "../shellPointer.js";
|
|
6
|
+
import { shellDrivesPlayerPose } from "../shellMovement.js";
|
|
7
|
+
import { steerYaw } from "@jgengine/core/movement/steering";
|
|
8
|
+
import { stepPlayerMovement, resolvePlayerMovementTuning } from "@jgengine/core/movement/playerMovement";
|
|
9
|
+
import { isServerAuthoritative } from "@jgengine/core/runtime/adapter";
|
|
10
|
+
import { resolveCommandSink } from "../commandSink.js";
|
|
11
|
+
import { inputFramesEqual, resolveInputSink } from "../inputSink.js";
|
|
12
|
+
import { advanceBehaviors } from "@jgengine/core/scene/behaviorRuntime";
|
|
13
|
+
import { resolveActivePrompt } from "@jgengine/core/interaction/proximityPrompt";
|
|
14
|
+
import { DEFAULT_PICKUP_RADIUS } from "@jgengine/core/game/worldItem";
|
|
15
|
+
import { playControlsActive } from "@jgengine/core/game/controlGate";
|
|
16
|
+
import { devtools } from "@jgengine/core/devtools/devtools";
|
|
17
|
+
import { collisionDebug } from "../devtools/collisionDebug.js";
|
|
18
|
+
import { GAME_SIM_FRAME_PRIORITY } from "../camera/index.js";
|
|
19
|
+
import { NO_ACTIONS } from "../shellConstants.js";
|
|
20
|
+
const TURN_SPEED = 2.4;
|
|
21
|
+
export const POSTER_SETTLE_SECONDS = 1.6;
|
|
22
|
+
export function FrameDriver({ ctx, playable, tracker, yawRef, pitchRef, primaryClickRef, pointerAxisRef, gateRef, onRuntimeError, multiplayer, serverIdRef, pointerService, pointerAim, pingCommand, poster, onPosterSettled, }) {
|
|
23
|
+
const posterElapsedRef = useRef(0);
|
|
24
|
+
const posterDoneRef = useRef(false);
|
|
25
|
+
const hasReportedTickError = useRef(false);
|
|
26
|
+
const repeatFiredAtRef = useRef(new Map());
|
|
27
|
+
const slotActions = useMemo(() => findHotbarSlotActions(playable.game.input), [playable]);
|
|
28
|
+
const hotbarId = useMemo(() => hotbarIdFor(playable), [playable]);
|
|
29
|
+
const movementTuning = useMemo(() => resolvePlayerMovementTuning({
|
|
30
|
+
collision: playable.collision,
|
|
31
|
+
movement: playable.movement,
|
|
32
|
+
physics: playable.game.physics,
|
|
33
|
+
world: playable.game.world,
|
|
34
|
+
}), [playable]);
|
|
35
|
+
const autoPickupRadius = useMemo(() => {
|
|
36
|
+
const cfg = playable.worldItem?.autoPickup;
|
|
37
|
+
if (cfg === undefined || cfg === false)
|
|
38
|
+
return null;
|
|
39
|
+
const fallback = playable.worldItem?.pickupRadius ?? DEFAULT_PICKUP_RADIUS;
|
|
40
|
+
return cfg === true ? fallback : cfg.radius ?? fallback;
|
|
41
|
+
}, [playable]);
|
|
42
|
+
const drivesPose = useMemo(() => shellDrivesPlayerPose(playable.game.input), [playable]);
|
|
43
|
+
const serverAuthoritative = useMemo(() => isServerAuthoritative(playable.game.multiplayer) && multiplayer !== null, [playable, multiplayer]);
|
|
44
|
+
const commandSink = useMemo(() => ({
|
|
45
|
+
run: (name, input) => resolveCommandSink(ctx, {
|
|
46
|
+
serverAuthoritative,
|
|
47
|
+
backend: multiplayer?.backend ?? null,
|
|
48
|
+
serverId: serverIdRef.current,
|
|
49
|
+
}).run(name, input),
|
|
50
|
+
}), [ctx, multiplayer, serverAuthoritative, serverIdRef]);
|
|
51
|
+
const inputSink = useMemo(() => ({
|
|
52
|
+
send: (frame) => resolveInputSink({
|
|
53
|
+
serverAuthoritative,
|
|
54
|
+
backend: multiplayer?.backend ?? null,
|
|
55
|
+
serverId: serverIdRef.current,
|
|
56
|
+
}).send(frame),
|
|
57
|
+
}), [multiplayer, serverAuthoritative, serverIdRef]);
|
|
58
|
+
const lastSentInputRef = useRef(null);
|
|
59
|
+
const inputActions = useMemo(() => Object.keys(playable.game.input ?? {}), [playable]);
|
|
60
|
+
useFrame((_state, rawDt) => {
|
|
61
|
+
if (poster) {
|
|
62
|
+
if (posterDoneRef.current)
|
|
63
|
+
return;
|
|
64
|
+
posterElapsedRef.current += Math.min(rawDt, 0.05);
|
|
65
|
+
if (posterElapsedRef.current >= POSTER_SETTLE_SECONDS) {
|
|
66
|
+
posterDoneRef.current = true;
|
|
67
|
+
onPosterSettled();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const sendInput = () => {
|
|
72
|
+
if (!serverAuthoritative)
|
|
73
|
+
return;
|
|
74
|
+
const frame = { held: ctx.input.held(), pointer: ctx.input.pointer() };
|
|
75
|
+
const last = lastSentInputRef.current;
|
|
76
|
+
if (last !== null && inputFramesEqual(last, frame))
|
|
77
|
+
return;
|
|
78
|
+
lastSentInputRef.current = frame;
|
|
79
|
+
inputSink.send(frame);
|
|
80
|
+
};
|
|
81
|
+
if (gateRef.current || !playControlsActive(ctx)) {
|
|
82
|
+
ctx.input.publish(heldActionsFor(tracker, NO_ACTIONS));
|
|
83
|
+
sendInput();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const simStart = performance.now();
|
|
87
|
+
try {
|
|
88
|
+
let endPhase = devtools.profile.begin("time+input");
|
|
89
|
+
const dt = Math.min(rawDt, 0.05);
|
|
90
|
+
const gameDt = ctx.time.advance(dt);
|
|
91
|
+
ctx.input.publish(heldActionsFor(tracker, inputActions));
|
|
92
|
+
ctx.input.publishPointer(pointerAxisRef.current);
|
|
93
|
+
sendInput();
|
|
94
|
+
const turnInput = (tracker.isDown("turnRight") ? 1 : 0) - (tracker.isDown("turnLeft") ? 1 : 0);
|
|
95
|
+
if (turnInput !== 0)
|
|
96
|
+
yawRef.current = steerYaw(yawRef.current, turnInput, TURN_SPEED, dt);
|
|
97
|
+
endPhase();
|
|
98
|
+
const playerId = ctx.player.possession.active(ctx.player.userId);
|
|
99
|
+
const player = ctx.scene.entity.get(playerId);
|
|
100
|
+
if (player !== null && drivesPose && !serverAuthoritative) {
|
|
101
|
+
endPhase = devtools.profile.begin("pose");
|
|
102
|
+
stepPlayerMovement(ctx, ctx.player.userId, { held: ctx.input.held(), pointer: ctx.input.pointer() }, rawDt, movementTuning, yawRef.current);
|
|
103
|
+
endPhase();
|
|
104
|
+
}
|
|
105
|
+
if (autoPickupRadius !== null && !serverAuthoritative) {
|
|
106
|
+
endPhase = devtools.profile.begin("pickup");
|
|
107
|
+
const self = ctx.scene.entity.get(playerId);
|
|
108
|
+
if (self !== null) {
|
|
109
|
+
const nearest = ctx.scene.worldItem.nearestInRadius(self.position, autoPickupRadius);
|
|
110
|
+
if (nearest !== null)
|
|
111
|
+
ctx.scene.worldItem.pickup(nearest, ctx.player.userId);
|
|
112
|
+
}
|
|
113
|
+
endPhase();
|
|
114
|
+
}
|
|
115
|
+
if (!serverAuthoritative) {
|
|
116
|
+
devtools.profile.measure("onTick", () => {
|
|
117
|
+
playable.loop.onTick(ctx, gameDt);
|
|
118
|
+
});
|
|
119
|
+
advanceBehaviors(ctx, gameDt);
|
|
120
|
+
}
|
|
121
|
+
endPhase = devtools.profile.begin("actions");
|
|
122
|
+
if (tracker.wasPressed("tabTarget")) {
|
|
123
|
+
if (ctx.game.commands.has("target.cycle"))
|
|
124
|
+
ctx.game.commands.run("target.cycle", {});
|
|
125
|
+
else
|
|
126
|
+
ctx.scene.entity.cycleTarget(playerId, { filter: "hostile" });
|
|
127
|
+
}
|
|
128
|
+
if (tracker.wasPressed("clearTarget")) {
|
|
129
|
+
if (ctx.game.commands.has("target.clear"))
|
|
130
|
+
ctx.game.commands.run("target.clear", {});
|
|
131
|
+
else
|
|
132
|
+
ctx.scene.entity.setTarget(playerId, null);
|
|
133
|
+
}
|
|
134
|
+
if (pingCommand !== undefined && tracker.wasPressed("ping")) {
|
|
135
|
+
const hit = pointerService.worldHit();
|
|
136
|
+
if (hit !== null && ctx.game.commands.has(pingCommand)) {
|
|
137
|
+
commandSink.run(pingCommand, {
|
|
138
|
+
point: hit.point,
|
|
139
|
+
entity: hit.entity,
|
|
140
|
+
object: hit.object,
|
|
141
|
+
normal: hit.normal,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const aimOverride = pointerAim ? pointerAimFor(ctx, pointerService) : undefined;
|
|
146
|
+
const commandAim = aimOverride ?? { yaw: yawRef.current, pitch: pitchRef.current };
|
|
147
|
+
if (collisionDebug.getState().layers.aimLaser) {
|
|
148
|
+
const aimFrom = ctx.player.possession.active(playerId) ?? playerId;
|
|
149
|
+
collisionDebug.setAimProbe({
|
|
150
|
+
from: aimFrom,
|
|
151
|
+
aim: commandAim,
|
|
152
|
+
originPolicy: { kind: "converge" },
|
|
153
|
+
maxDistance: 100,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else if (collisionDebug.getAimProbe() !== null) {
|
|
157
|
+
collisionDebug.setAimProbe(null);
|
|
158
|
+
}
|
|
159
|
+
const nowMs = performance.now();
|
|
160
|
+
for (const action of Object.keys(playable.game.input ?? {})) {
|
|
161
|
+
const pressed = tracker.wasPressed(action);
|
|
162
|
+
if (action === "ping" && pingCommand !== undefined)
|
|
163
|
+
continue;
|
|
164
|
+
if (action === "interact") {
|
|
165
|
+
if (!pressed)
|
|
166
|
+
continue;
|
|
167
|
+
const prompts = playable.prompts?.(ctx);
|
|
168
|
+
const focus = prompts === undefined ? null : ctx.scene.entity.get(playerId);
|
|
169
|
+
if (prompts !== undefined && focus !== null) {
|
|
170
|
+
const active = resolveActivePrompt({ x: focus.position[0], z: focus.position[2] }, prompts);
|
|
171
|
+
if (active !== null && active.prompt.invoke !== null) {
|
|
172
|
+
commandSink.run(active.prompt.invoke.name, active.prompt.invoke.input);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (!shouldFireBoundAction(tracker, action, playable.game.input, repeatFiredAtRef.current, nowMs))
|
|
178
|
+
continue;
|
|
179
|
+
repeatFiredAtRef.current.set(action, nowMs);
|
|
180
|
+
dispatchBoundAction(ctx, action, yawRef.current, pitchRef.current, commandAim, RESERVED_INPUT_ACTIONS, commandSink);
|
|
181
|
+
}
|
|
182
|
+
if (hotbarId !== null) {
|
|
183
|
+
for (const { action, slot } of slotActions) {
|
|
184
|
+
if (!tracker.wasPressed(action))
|
|
185
|
+
continue;
|
|
186
|
+
const result = executeHotbarSlot(ctx, playerId, hotbarId, slot, yawRef.current, pitchRef.current, aimOverride);
|
|
187
|
+
if (!result.ok)
|
|
188
|
+
console.warn(`[jgengine:item-use] ${result.error}`);
|
|
189
|
+
}
|
|
190
|
+
const usePrimary = tracker.wasPressed("useAbility") || (primaryClickRef.current && hotbarId !== null);
|
|
191
|
+
if (usePrimary) {
|
|
192
|
+
primaryClickRef.current = false;
|
|
193
|
+
const slots = ctx.player.inventory.state(hotbarId).slots;
|
|
194
|
+
const preferred = playable.hotbarSelection?.() ?? -1;
|
|
195
|
+
const slot = preferred >= 0 && slots[preferred] !== null && slots[preferred] !== undefined
|
|
196
|
+
? preferred
|
|
197
|
+
: slots.findIndex((stack) => stack !== null);
|
|
198
|
+
if (slot >= 0) {
|
|
199
|
+
const result = executeHotbarSlot(ctx, playerId, hotbarId, slot, yawRef.current, pitchRef.current, aimOverride);
|
|
200
|
+
if (!result.ok)
|
|
201
|
+
console.warn(`[jgengine:item-use] ${result.error}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
tracker.endFrame();
|
|
206
|
+
endPhase();
|
|
207
|
+
const serverId = serverIdRef.current;
|
|
208
|
+
if (multiplayer !== null && serverId !== null) {
|
|
209
|
+
endPhase = devtools.profile.begin("presence");
|
|
210
|
+
const focus = ctx.scene.entity.get(playerId);
|
|
211
|
+
if (focus !== null) {
|
|
212
|
+
multiplayer.backend.presenceSync.syncPose(serverId, {
|
|
213
|
+
x: focus.position[0],
|
|
214
|
+
y: focus.position[1],
|
|
215
|
+
z: focus.position[2],
|
|
216
|
+
rotationY: focus.rotationY,
|
|
217
|
+
rotationPitch: pitchRef.current,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
endPhase();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (!hasReportedTickError.current) {
|
|
225
|
+
hasReportedTickError.current = true;
|
|
226
|
+
onRuntimeError(error, "tick");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
devtools.frame.record({ frameMs: rawDt * 1000, simMs: performance.now() - simStart });
|
|
230
|
+
}, GAME_SIM_FRAME_PRIORITY);
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { GameContext } from "@jgengine/core/runtime/gameContext";
|
|
2
|
+
import type { PointerAxisState } from "@jgengine/core/input/pointerAxis";
|
|
3
|
+
import type { ActionStateTracker } from "@jgengine/core/input/actionBindings";
|
|
4
|
+
import type { PlayableGame } from "../registry.js";
|
|
5
|
+
export declare function HudOnlyDriver({ ctx, playable, tracker, pointerAxisRef, gateRef, onRuntimeError, }: {
|
|
6
|
+
ctx: GameContext;
|
|
7
|
+
playable: PlayableGame;
|
|
8
|
+
tracker: ActionStateTracker<string>;
|
|
9
|
+
pointerAxisRef: {
|
|
10
|
+
current: PointerAxisState | null;
|
|
11
|
+
};
|
|
12
|
+
gateRef: {
|
|
13
|
+
current: boolean;
|
|
14
|
+
};
|
|
15
|
+
onRuntimeError: (error: unknown, phase: string) => void;
|
|
16
|
+
}): null;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { dispatchBoundAction, heldActionsFor, shouldFireBoundAction } from "../boundActionDispatch.js";
|
|
3
|
+
import { advanceBehaviors } from "@jgengine/core/scene/behaviorRuntime";
|
|
4
|
+
import { playControlsActive } from "@jgengine/core/game/controlGate";
|
|
5
|
+
import { devtools } from "@jgengine/core/devtools/devtools";
|
|
6
|
+
import { EMPTY_RESERVED, NO_ACTIONS } from "../shellConstants.js";
|
|
7
|
+
export function HudOnlyDriver({ ctx, playable, tracker, pointerAxisRef, gateRef, onRuntimeError, }) {
|
|
8
|
+
const hasReportedTickError = useRef(false);
|
|
9
|
+
const repeatFiredAtRef = useRef(new Map());
|
|
10
|
+
const lastFrameRef = useRef(null);
|
|
11
|
+
const inputActions = useMemo(() => Object.keys(playable.game.input ?? {}), [playable]);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
let frameId;
|
|
14
|
+
const tick = (now) => {
|
|
15
|
+
frameId = requestAnimationFrame(tick);
|
|
16
|
+
const last = lastFrameRef.current;
|
|
17
|
+
lastFrameRef.current = now;
|
|
18
|
+
if (last === null)
|
|
19
|
+
return;
|
|
20
|
+
if (gateRef.current || !playControlsActive(ctx)) {
|
|
21
|
+
ctx.input.publish(heldActionsFor(tracker, NO_ACTIONS));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const rawDt = (now - last) / 1000;
|
|
25
|
+
const simStart = performance.now();
|
|
26
|
+
try {
|
|
27
|
+
let endPhase = devtools.profile.begin("time+input");
|
|
28
|
+
const dt = Math.min(rawDt, 0.05);
|
|
29
|
+
const gameDt = ctx.time.advance(dt);
|
|
30
|
+
ctx.input.publish(heldActionsFor(tracker, inputActions));
|
|
31
|
+
ctx.input.publishPointer(pointerAxisRef.current);
|
|
32
|
+
endPhase();
|
|
33
|
+
devtools.profile.measure("onTick", () => {
|
|
34
|
+
playable.loop.onTick(ctx, gameDt);
|
|
35
|
+
});
|
|
36
|
+
advanceBehaviors(ctx, gameDt);
|
|
37
|
+
endPhase = devtools.profile.begin("actions");
|
|
38
|
+
const nowMs = performance.now();
|
|
39
|
+
for (const action of inputActions) {
|
|
40
|
+
if (!shouldFireBoundAction(tracker, action, playable.game.input, repeatFiredAtRef.current, nowMs))
|
|
41
|
+
continue;
|
|
42
|
+
repeatFiredAtRef.current.set(action, nowMs);
|
|
43
|
+
dispatchBoundAction(ctx, action, 0, 0, { yaw: 0, pitch: 0 }, EMPTY_RESERVED);
|
|
44
|
+
}
|
|
45
|
+
tracker.endFrame();
|
|
46
|
+
endPhase();
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (!hasReportedTickError.current) {
|
|
50
|
+
hasReportedTickError.current = true;
|
|
51
|
+
onRuntimeError(error, "tick");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
devtools.frame.record({ frameMs: rawDt * 1000, simMs: performance.now() - simStart });
|
|
55
|
+
};
|
|
56
|
+
frameId = requestAnimationFrame(tick);
|
|
57
|
+
return () => cancelAnimationFrame(frameId);
|
|
58
|
+
}, [ctx, playable, tracker, pointerAxisRef, gateRef, onRuntimeError, inputActions]);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type MutableRefObject } from "react";
|
|
2
2
|
import * as THREE from "three";
|
|
3
|
-
import type { SkyEnvironmentDescriptor } from "@jgengine/core/world/features";
|
|
3
|
+
import type { BiomeBand, SkyEnvironmentDescriptor } from "@jgengine/core/world/features";
|
|
4
|
+
import { type VolumetricCloudsConfig } from "@jgengine/core/world/volumetricClouds";
|
|
4
5
|
export interface SkyDomeProps {
|
|
5
6
|
topColor?: string;
|
|
6
7
|
horizonColor?: string;
|
|
@@ -13,10 +14,15 @@ export interface SkyDomeProps {
|
|
|
13
14
|
sunColor?: string;
|
|
14
15
|
/** Sun disc/glow intensity multiplier. Default 1. */
|
|
15
16
|
sunIntensity?: number;
|
|
17
|
+
/** Horizon haze-band strength: 0 removes the dusty band, ~1 makes it heavy. Default 0.5. */
|
|
18
|
+
hazeStrength?: number;
|
|
19
|
+
/** Sun-glow brightness multiplier around the sun disc. Default 1. */
|
|
20
|
+
sunGlowStrength?: number;
|
|
16
21
|
/** Exposes the created shader material so a time-of-day driver can mutate its uniforms per frame without recreating it. */
|
|
17
22
|
materialRef?: MutableRefObject<THREE.ShaderMaterial | null>;
|
|
18
23
|
}
|
|
19
|
-
|
|
24
|
+
/** @internal */
|
|
25
|
+
export declare function SkyDome({ topColor, horizonColor, radius, offset, exponent, sunDirection, sunColor, sunIntensity, hazeStrength, sunGlowStrength, materialRef, }?: SkyDomeProps): import("react").JSX.Element;
|
|
20
26
|
export interface DaylightProps {
|
|
21
27
|
sky?: SkyDomeProps | false;
|
|
22
28
|
fog?: {
|
|
@@ -36,14 +42,21 @@ export interface DaylightProps {
|
|
|
36
42
|
};
|
|
37
43
|
/** When false, only the sky dome and fog mount — use with authored `PlayableGame.lighting`. Default true. */
|
|
38
44
|
lights?: boolean;
|
|
45
|
+
/** Raymarched volumetric cloud layer over the sky dome. Omit for no clouds — off by default. */
|
|
46
|
+
clouds?: VolumetricCloudsConfig;
|
|
39
47
|
}
|
|
40
|
-
|
|
48
|
+
/** @internal */
|
|
49
|
+
export declare function Daylight({ sky, fog, sun, ambient, lights, clouds }?: DaylightProps): import("react").JSX.Element;
|
|
41
50
|
export interface SkyDaylightProps {
|
|
42
51
|
sky: SkyEnvironmentDescriptor;
|
|
43
52
|
lights?: boolean;
|
|
53
|
+
/** Terrain `biomeBands`; when any carries `fog`/`sky`, fog and dome cross-fade per camera z. */
|
|
54
|
+
bands?: readonly BiomeBand[];
|
|
44
55
|
}
|
|
45
|
-
/** Renders a fixed sky/sun/fog look sampled from `sky`'s preset (or, when `timeOfDay` is on but no clock drives it, its noon look). No per-frame updates.
|
|
46
|
-
|
|
56
|
+
/** Renders a fixed sky/sun/fog look sampled from `sky`'s preset (or, when `timeOfDay` is on but no clock drives it, its noon look). No per-frame updates.
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export declare function SkyDaylight({ sky, lights, bands }: SkyDaylightProps): import("react").JSX.Element;
|
|
47
60
|
export interface TimeOfDayDaylightProps {
|
|
48
61
|
sky: SkyEnvironmentDescriptor;
|
|
49
62
|
/** The world's `SimClock` (or a stub exposing `calendar().dayFraction`). Absent means static rendering. */
|
|
@@ -53,10 +66,13 @@ export interface TimeOfDayDaylightProps {
|
|
|
53
66
|
};
|
|
54
67
|
};
|
|
55
68
|
lights?: boolean;
|
|
69
|
+
/** Terrain `biomeBands`; when any carries `fog`/`sky`, fog and dome cross-fade per camera z. */
|
|
70
|
+
bands?: readonly BiomeBand[];
|
|
56
71
|
}
|
|
57
72
|
/**
|
|
58
73
|
* Drives sky/fog (and optional default lights) from the world clock when `sky.timeOfDay` and `clock`
|
|
59
74
|
* are both present. Authored `PlayableGame.lighting` is never rewritten — pass `lights={false}` so
|
|
60
75
|
* only dome colors and fog track the day fraction.
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
export declare function TimeOfDayDaylight({ sky, clock, lights, bands }: TimeOfDayDaylightProps): import("react").JSX.Element;
|