@jgengine/shell 0.10.0 → 0.11.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 +13 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/GamePhaseStamp.d.ts +1 -0
- package/dist/GamePhaseStamp.js +9 -0
- package/dist/GamePlayerShell.d.ts +0 -12
- package/dist/GamePlayerShell.js +88 -1043
- package/dist/GameUiPreview.js +0 -2
- package/dist/audio/audioEngine.js +30 -8
- package/dist/audio/audioWire.d.ts +22 -0
- package/dist/audio/audioWire.js +19 -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 +2 -2
- 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/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 +94 -24
- package/dist/camera/rigMath.js +100 -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/cartridge/runtime.d.ts +15 -0
- package/dist/cartridge/runtime.js +556 -0
- package/dist/cartridge/spec.d.ts +188 -0
- package/dist/cartridge/spec.js +19 -0
- package/dist/cartridge/validate.d.ts +2 -0
- package/dist/cartridge/validate.js +78 -0
- package/dist/cartridge.d.ts +1 -1
- package/dist/cartridge.js +3 -3
- package/dist/commandSink.d.ts +8 -3
- package/dist/commandSink.js +8 -3
- package/dist/defineGame.js +25 -6
- package/dist/devtools/ColPanel.d.ts +1 -0
- package/dist/devtools/ColPanel.js +14 -0
- package/dist/devtools/DevtoolsOverlay.d.ts +7 -3
- package/dist/devtools/DevtoolsOverlay.js +19 -450
- 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 +262 -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 +29 -0
- package/dist/diagnostics/RuntimeDiagnostics.js +69 -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 +32 -6
- 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/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/materialOverride.d.ts +10 -0
- package/dist/materialOverride.js +15 -3
- package/dist/multiplayer.js +8 -2
- package/dist/postfx/PostProcessing.js +47 -9
- package/dist/postfx/gradeShader.js +9 -1
- package/dist/registry.d.ts +3 -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/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 +73 -0
- package/dist/render/modelRender.d.ts +11 -0
- package/dist/render/modelRender.js +15 -0
- package/dist/render/resolveModel.d.ts +39 -3
- package/dist/render/resolveModel.js +79 -2
- 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 +130 -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 +94 -0
- package/dist/scatter.d.ts +1 -0
- package/dist/scatter.js +1 -0
- package/dist/scene/AuthoredScene.d.ts +82 -0
- package/dist/scene/AuthoredScene.js +173 -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 +25 -0
- package/dist/scene/SoilPatchRenderer.d.ts +2 -0
- package/dist/scene/SoilPatchRenderer.js +21 -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 +37 -0
- package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
- package/dist/scene/builtinSceneKindRenderers.js +22 -0
- package/dist/scene/sceneKindRenderers.d.ts +28 -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 +5 -0
- package/dist/settings/appliedSettings.js +9 -0
- 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 +43 -0
- package/dist/structures/TransformGizmo.js +55 -0
- package/dist/structures/index.d.ts +1 -0
- package/dist/structures/index.js +1 -0
- package/dist/terrain/GrassField.js +1 -1
- 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 +3 -0
- package/dist/terrain/grassGeometry.js +3 -0
- package/dist/terrain/grassMaterial.d.ts +2 -0
- package/dist/terrain/grassMaterial.js +2 -0
- package/dist/terrain/random.d.ts +3 -0
- package/dist/terrain/random.js +3 -0
- package/dist/terrain/soilPatchMaterial.d.ts +10 -0
- package/dist/terrain/soilPatchMaterial.js +109 -0
- package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
- package/dist/terrain/terrainDetailMaterial.js +72 -5
- 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/OceanConfig.d.ts +2 -0
- package/dist/water/OceanConfig.js +2 -0
- 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/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 +159 -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 +5 -0
- package/dist/worldSky.js +11 -0
- package/dist/worldSync.d.ts +2 -1
- package/dist/worldSync.js +2 -1
- package/package.json +6 -6
- package/skills/jgengine/SKILL.md +51 -0
- package/skills/jgengine/api.md +434 -0
- package/skills/jgengine/capabilities.md +29 -0
- package/skills/jgengine/reference-cartridge.md +72 -0
- package/skills/jgengine-ui/SKILL.md +36 -0
- package/skills/jgengine-ui/api.md +1852 -0
- package/skills/jgengine-ui/capabilities.md +142 -0
- package/skills/jgengine-ui/reference.md +500 -0
- package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
- package/skills/jgengine-world/SKILL.md +38 -0
- package/skills/jgengine-world/api.md +2652 -0
- package/skills/jgengine-world/capabilities.md +370 -0
- package/skills/jgengine-world/reference.md +222 -0
- package/llms.txt +0 -2761
|
@@ -22,6 +22,9 @@ export interface ResolvedGrassBladeGeometryOptions {
|
|
|
22
22
|
bend: readonly [min: number, max: number];
|
|
23
23
|
heightAt: TerrainHeightSampler;
|
|
24
24
|
}
|
|
25
|
+
/** @internal */
|
|
25
26
|
export declare function resolveGrassRange(value: GrassRange | undefined, fallback: readonly [number, number]): readonly [number, number];
|
|
27
|
+
/** @internal */
|
|
26
28
|
export declare function resolveGrassBladeGeometryOptions(options?: GrassBladeGeometryOptions): ResolvedGrassBladeGeometryOptions;
|
|
29
|
+
/** @internal */
|
|
27
30
|
export declare function createGrassBladeGeometry(options?: GrassBladeGeometryOptions): THREE.InstancedBufferGeometry;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { createSeededRandom } from "./random.js";
|
|
3
3
|
import { resolveTerrainSize } from "./terrainMath.js";
|
|
4
|
+
/** @internal */
|
|
4
5
|
export function resolveGrassRange(value, fallback) {
|
|
5
6
|
if (value === undefined)
|
|
6
7
|
return fallback;
|
|
7
8
|
return typeof value === "number" ? [value, value] : value;
|
|
8
9
|
}
|
|
10
|
+
/** @internal */
|
|
9
11
|
export function resolveGrassBladeGeometryOptions(options = {}) {
|
|
10
12
|
return {
|
|
11
13
|
count: Math.max(0, Math.floor(options.count ?? 1500)),
|
|
@@ -21,6 +23,7 @@ export function resolveGrassBladeGeometryOptions(options = {}) {
|
|
|
21
23
|
function randomRange(random, range) {
|
|
22
24
|
return THREE.MathUtils.lerp(range[0], range[1], random());
|
|
23
25
|
}
|
|
26
|
+
/** @internal */
|
|
24
27
|
export function createGrassBladeGeometry(options = {}) {
|
|
25
28
|
const resolved = resolveGrassBladeGeometryOptions(options);
|
|
26
29
|
const size = resolveTerrainSize(resolved.area);
|
|
@@ -29,5 +29,7 @@ export interface GrassMaterialHandle {
|
|
|
29
29
|
uniforms: GrassShaderUniforms;
|
|
30
30
|
}
|
|
31
31
|
export declare const DEFAULT_GRASS_WIND: Required<GrassWindOptions>;
|
|
32
|
+
/** @internal */
|
|
32
33
|
export declare function resolveGrassWind(wind: GrassWindOptions | false | undefined): Required<GrassWindOptions>;
|
|
34
|
+
/** @internal */
|
|
33
35
|
export declare function createGrassMaterial(options?: GrassMaterialOptions): GrassMaterialHandle;
|
|
@@ -10,6 +10,7 @@ function normalizeWindDirection(direction) {
|
|
|
10
10
|
const vector = new THREE.Vector2(direction[0], direction[1]);
|
|
11
11
|
return vector.lengthSq() === 0 ? new THREE.Vector2(1, 0) : vector.normalize();
|
|
12
12
|
}
|
|
13
|
+
/** @internal */
|
|
13
14
|
export function resolveGrassWind(wind) {
|
|
14
15
|
if (wind === false)
|
|
15
16
|
return { ...DEFAULT_GRASS_WIND, strength: 0, flutter: 0 };
|
|
@@ -21,6 +22,7 @@ export function resolveGrassWind(wind) {
|
|
|
21
22
|
flutter: wind?.flutter ?? DEFAULT_GRASS_WIND.flutter,
|
|
22
23
|
};
|
|
23
24
|
}
|
|
25
|
+
/** @internal */
|
|
24
26
|
export function createGrassMaterial(options = {}) {
|
|
25
27
|
const wind = resolveGrassWind(options.wind);
|
|
26
28
|
const uniforms = {
|
package/dist/terrain/random.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export type TerrainSeed = number | string;
|
|
2
|
+
/** @internal */
|
|
2
3
|
export declare function seedToUint32(seed?: TerrainSeed): number;
|
|
4
|
+
/** @internal */
|
|
3
5
|
export declare function createSeededRandom(seed?: TerrainSeed): () => number;
|
|
6
|
+
/** @internal */
|
|
4
7
|
export declare function hashNoise2(x: number, z: number, seed?: TerrainSeed): number;
|
package/dist/terrain/random.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @internal */
|
|
1
2
|
export function seedToUint32(seed = 1) {
|
|
2
3
|
if (typeof seed === "number")
|
|
3
4
|
return seed >>> 0;
|
|
@@ -8,6 +9,7 @@ export function seedToUint32(seed = 1) {
|
|
|
8
9
|
}
|
|
9
10
|
return hash >>> 0;
|
|
10
11
|
}
|
|
12
|
+
/** @internal */
|
|
11
13
|
export function createSeededRandom(seed = 1) {
|
|
12
14
|
let state = seedToUint32(seed);
|
|
13
15
|
return () => {
|
|
@@ -18,6 +20,7 @@ export function createSeededRandom(seed = 1) {
|
|
|
18
20
|
return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
|
|
19
21
|
};
|
|
20
22
|
}
|
|
23
|
+
/** @internal */
|
|
21
24
|
export function hashNoise2(x, z, seed = 1) {
|
|
22
25
|
let hash = seedToUint32(seed);
|
|
23
26
|
hash ^= Math.imul(x | 0, 374761393);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { SoilRules } from "@jgengine/core/world/soilKind";
|
|
3
|
+
/**
|
|
4
|
+
* A `MeshStandardMaterial` for one authored `soil` volume: a base dirt tint with a Worley crack-line
|
|
5
|
+
* network and an FBM moss-patch overlay injected via `onBeforeCompile`, seeded from `rules.seed`. Full
|
|
6
|
+
* PBR — lit, shadowed, fogged — like the terrain detail material it borrows its noise machinery from.
|
|
7
|
+
* A game never calls this directly — author a soil patch via the editor's `soil` studio kind.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSoilPatchMaterial(rules: SoilRules): THREE.MeshStandardMaterial;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
/**
|
|
3
|
+
* Worley (F1/F2 cellular) crack mask + FBM moss mask — the same noise-driven-shader technique as
|
|
4
|
+
* `terrainDetailMaterial.ts`'s rock/sand/snow blend, injected here via `onBeforeCompile` into a
|
|
5
|
+
* dedicated soil-patch material instead of the whole-ground detail material. `F2 - F1` (the gap
|
|
6
|
+
* between nearest and second-nearest Worley feature distances) goes to zero right at a cell boundary,
|
|
7
|
+
* which reads as a network of cracked-earth veins once thresholded — the standard "cracked ground"
|
|
8
|
+
* shader trick.
|
|
9
|
+
*/
|
|
10
|
+
const SOIL_NOISE_GLSL = /* glsl */ `
|
|
11
|
+
uint jgSoilHashUint(uvec2 v){
|
|
12
|
+
uint x = v.x * 1664525u + v.y * 1013904223u;
|
|
13
|
+
x = (x ^ (x >> 16u)) * 2246822519u;
|
|
14
|
+
x = (x ^ (x >> 13u)) * 3266489917u;
|
|
15
|
+
x = x ^ (x >> 16u);
|
|
16
|
+
return x;
|
|
17
|
+
}
|
|
18
|
+
float jgSoilHash1(vec2 p){
|
|
19
|
+
return float(jgSoilHashUint(uvec2(floor(p)))) * (1.0 / 4294967296.0);
|
|
20
|
+
}
|
|
21
|
+
vec2 jgSoilHash2(vec2 p){
|
|
22
|
+
uvec2 base = uvec2(floor(p));
|
|
23
|
+
float a = float(jgSoilHashUint(base)) * (1.0 / 4294967296.0);
|
|
24
|
+
float b = float(jgSoilHashUint(base + uvec2(19u, 47u))) * (1.0 / 4294967296.0);
|
|
25
|
+
return vec2(a, b);
|
|
26
|
+
}
|
|
27
|
+
float jgSoilVNoise(vec2 p){
|
|
28
|
+
vec2 i = floor(p); vec2 f = fract(p);
|
|
29
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
30
|
+
float a = jgSoilHash1(i);
|
|
31
|
+
float b = jgSoilHash1(i + vec2(1.0, 0.0));
|
|
32
|
+
float c = jgSoilHash1(i + vec2(0.0, 1.0));
|
|
33
|
+
float d = jgSoilHash1(i + vec2(1.0, 1.0));
|
|
34
|
+
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
|
|
35
|
+
}
|
|
36
|
+
float jgSoilFbm(vec2 p){
|
|
37
|
+
float v = 0.0; float amp = 0.5;
|
|
38
|
+
for (int i = 0; i < 4; i++){ v += amp * jgSoilVNoise(p); p *= 2.0; amp *= 0.5; }
|
|
39
|
+
return v;
|
|
40
|
+
}
|
|
41
|
+
vec2 jgSoilWorleyF1F2(vec2 p){
|
|
42
|
+
vec2 ip = floor(p);
|
|
43
|
+
vec2 fp = fract(p);
|
|
44
|
+
float f1 = 8.0; float f2 = 8.0;
|
|
45
|
+
for (int y = -1; y <= 1; y++){
|
|
46
|
+
for (int x = -1; x <= 1; x++){
|
|
47
|
+
vec2 neighbor = vec2(float(x), float(y));
|
|
48
|
+
vec2 point = jgSoilHash2(ip + neighbor);
|
|
49
|
+
float dist = length(neighbor + point - fp);
|
|
50
|
+
if (dist < f1) { f2 = f1; f1 = dist; }
|
|
51
|
+
else if (dist < f2) { f2 = dist; }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return vec2(f1, f2);
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
function hashSeed(text) {
|
|
58
|
+
let h = 2166136261 >>> 0;
|
|
59
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
60
|
+
h ^= text.charCodeAt(i);
|
|
61
|
+
h = Math.imul(h, 16777619);
|
|
62
|
+
}
|
|
63
|
+
return (h >>> 0) % 100000;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A `MeshStandardMaterial` for one authored `soil` volume: a base dirt tint with a Worley crack-line
|
|
67
|
+
* network and an FBM moss-patch overlay injected via `onBeforeCompile`, seeded from `rules.seed`. Full
|
|
68
|
+
* PBR — lit, shadowed, fogged — like the terrain detail material it borrows its noise machinery from.
|
|
69
|
+
* A game never calls this directly — author a soil patch via the editor's `soil` studio kind.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export function createSoilPatchMaterial(rules) {
|
|
73
|
+
const seedOffset = hashSeed(rules.seed);
|
|
74
|
+
const material = new THREE.MeshStandardMaterial({
|
|
75
|
+
color: rules.baseColor,
|
|
76
|
+
roughness: 0.92,
|
|
77
|
+
metalness: 0,
|
|
78
|
+
});
|
|
79
|
+
material.onBeforeCompile = (shader) => {
|
|
80
|
+
shader.uniforms.uSoilCrackColor = { value: new THREE.Color(rules.crackColor) };
|
|
81
|
+
shader.uniforms.uSoilCrackScale = { value: Math.max(0.1, rules.crackScale) };
|
|
82
|
+
shader.uniforms.uSoilCrackIntensity = { value: rules.crackIntensity };
|
|
83
|
+
shader.uniforms.uSoilMossColor = { value: new THREE.Color(rules.mossColor) };
|
|
84
|
+
shader.uniforms.uSoilMossCoverage = { value: rules.mossCoverage };
|
|
85
|
+
shader.uniforms.uSoilSeed = { value: seedOffset };
|
|
86
|
+
shader.vertexShader = shader.vertexShader.replace("#include <common>", `#include <common>
|
|
87
|
+
varying vec3 vJgSoilWorldPos;`).replace("#include <begin_vertex>", `#include <begin_vertex>
|
|
88
|
+
vJgSoilWorldPos = (modelMatrix * vec4(transformed, 1.0)).xyz;`);
|
|
89
|
+
shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `#include <common>
|
|
90
|
+
varying vec3 vJgSoilWorldPos;
|
|
91
|
+
uniform vec3 uSoilCrackColor;
|
|
92
|
+
uniform float uSoilCrackScale;
|
|
93
|
+
uniform float uSoilCrackIntensity;
|
|
94
|
+
uniform vec3 uSoilMossColor;
|
|
95
|
+
uniform float uSoilMossCoverage;
|
|
96
|
+
uniform float uSoilSeed;
|
|
97
|
+
${SOIL_NOISE_GLSL}`).replace("#include <color_fragment>", `#include <color_fragment>
|
|
98
|
+
vec2 jgSoilP = vJgSoilWorldPos.xz + vec2(uSoilSeed * 0.37, uSoilSeed * 0.71);
|
|
99
|
+
vec2 jgSoilF1F2 = jgSoilWorleyF1F2(jgSoilP / uSoilCrackScale);
|
|
100
|
+
float jgSoilCrack = 1.0 - smoothstep(0.0, 0.1, jgSoilF1F2.y - jgSoilF1F2.x);
|
|
101
|
+
vec3 jgSoilCol = mix(diffuseColor.rgb, uSoilCrackColor, jgSoilCrack * uSoilCrackIntensity);
|
|
102
|
+
float jgSoilMossN = jgSoilFbm(jgSoilP / 2.4);
|
|
103
|
+
float jgSoilMossMask = smoothstep(1.0 - uSoilMossCoverage, 1.0 - uSoilMossCoverage + 0.18, jgSoilMossN);
|
|
104
|
+
jgSoilCol = mix(jgSoilCol, uSoilMossColor, jgSoilMossMask);
|
|
105
|
+
diffuseColor.rgb = jgSoilCol;`);
|
|
106
|
+
};
|
|
107
|
+
material.customProgramCacheKey = () => `jgengine-soil-${rules.crackScale}-${rules.crackIntensity}-${rules.mossCoverage}-${seedOffset}`;
|
|
108
|
+
return material;
|
|
109
|
+
}
|
|
@@ -4,11 +4,28 @@ import type { ResolvedTerrainDetail } from "@jgengine/core/world/terrain";
|
|
|
4
4
|
export interface TerrainDetailMaterialHandle {
|
|
5
5
|
material: THREE.MeshStandardMaterial;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Loaded PBR textures matching a resolved `ResolvedTerrainDetailMaterial.maps`' roles. The caller
|
|
9
|
+
* (a React component, via `useTexture`/`useLoader`) owns loading and disposal; `core` never touches
|
|
10
|
+
* `THREE.Texture` and this shell function never fetches a URL itself.
|
|
11
|
+
*/
|
|
12
|
+
export interface TerrainDetailMaterialTextures {
|
|
13
|
+
color: THREE.Texture;
|
|
14
|
+
normal: THREE.Texture;
|
|
15
|
+
roughness: THREE.Texture;
|
|
16
|
+
ao: THREE.Texture;
|
|
17
|
+
}
|
|
7
18
|
/**
|
|
8
19
|
* A `MeshStandardMaterial` whose fragment shader keeps the biome-tinted vertex
|
|
9
20
|
* colour as the base ground and blends procedural, noise-broken rock (by slope),
|
|
10
21
|
* sand (by waterline), and snow (by height) over it — textured-reading terrain
|
|
11
22
|
* with no image assets. Full PBR: lit, shadowed, and fogged like any standard
|
|
12
23
|
* material, so it composes with the post-processing chain.
|
|
13
|
-
|
|
14
|
-
|
|
24
|
+
*
|
|
25
|
+
* When `detail.material` is set, pass the matching loaded `textures` (color/normal/roughness/ao):
|
|
26
|
+
* they tile by world position at `detail.material.repeat` world units per tile and blend over the
|
|
27
|
+
* procedural result at `detail.material.strength` — the real-texture seam layers onto the existing
|
|
28
|
+
* look instead of replacing it.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export declare function createTerrainDetailMaterial(detail: ResolvedTerrainDetail, textures?: TerrainDetailMaterialTextures): TerrainDetailMaterialHandle;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
const NOISE_GLSL = /* glsl */ `
|
|
3
|
-
|
|
3
|
+
uint jgHashUint(uvec2 v){
|
|
4
|
+
uint x = v.x * 1664525u + v.y * 1013904223u;
|
|
5
|
+
x = (x ^ (x >> 16u)) * 2246822519u;
|
|
6
|
+
x = (x ^ (x >> 13u)) * 3266489917u;
|
|
7
|
+
x = x ^ (x >> 16u);
|
|
8
|
+
return x;
|
|
9
|
+
}
|
|
10
|
+
float jgHash(vec2 p){
|
|
11
|
+
ivec2 i = ivec2(floor(p));
|
|
12
|
+
return float(jgHashUint(uvec2(i))) * (1.0 / 4294967296.0);
|
|
13
|
+
}
|
|
4
14
|
float jgVNoise(vec2 p){
|
|
5
15
|
vec2 i = floor(p); vec2 f = fract(p);
|
|
6
16
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
@@ -22,8 +32,17 @@ float jgFbm(vec2 p){
|
|
|
22
32
|
* sand (by waterline), and snow (by height) over it — textured-reading terrain
|
|
23
33
|
* with no image assets. Full PBR: lit, shadowed, and fogged like any standard
|
|
24
34
|
* material, so it composes with the post-processing chain.
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
*
|
|
36
|
+
* When `detail.material` is set, pass the matching loaded `textures` (color/normal/roughness/ao):
|
|
37
|
+
* they tile by world position at `detail.material.repeat` world units per tile and blend over the
|
|
38
|
+
* procedural result at `detail.material.strength` — the real-texture seam layers onto the existing
|
|
39
|
+
* look instead of replacing it.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export function createTerrainDetailMaterial(detail, textures) {
|
|
43
|
+
const hasTexture = textures !== undefined && detail.material !== undefined;
|
|
44
|
+
const repeat = detail.material?.repeat ?? 4;
|
|
45
|
+
const strength = detail.material?.strength ?? 1;
|
|
27
46
|
const uniforms = {
|
|
28
47
|
uRockColor: { value: new THREE.Color(detail.rockColor) },
|
|
29
48
|
uSandColor: { value: new THREE.Color(detail.sandColor) },
|
|
@@ -34,6 +53,16 @@ export function createTerrainDetailMaterial(detail) {
|
|
|
34
53
|
uDetailScale: { value: Math.max(0.5, detail.detailScale) },
|
|
35
54
|
uMacroScale: { value: Math.max(0.5, detail.macroScale) },
|
|
36
55
|
uStrength: { value: detail.strength },
|
|
56
|
+
...(hasTexture
|
|
57
|
+
? {
|
|
58
|
+
uMatColor: { value: textures.color },
|
|
59
|
+
uMatNormal: { value: textures.normal },
|
|
60
|
+
uMatRoughness: { value: textures.roughness },
|
|
61
|
+
uMatAo: { value: textures.ao },
|
|
62
|
+
uMatRepeat: { value: Math.max(0.01, repeat) },
|
|
63
|
+
uMatStrength: { value: strength },
|
|
64
|
+
}
|
|
65
|
+
: {}),
|
|
37
66
|
};
|
|
38
67
|
const material = new THREE.MeshStandardMaterial({
|
|
39
68
|
color: "#ffffff",
|
|
@@ -51,6 +80,36 @@ varying vec3 vJgWorldNormal;`)
|
|
|
51
80
|
vJgWorldNormal = normalize(mat3(modelMatrix) * objectNormal);`)
|
|
52
81
|
.replace("#include <begin_vertex>", `#include <begin_vertex>
|
|
53
82
|
vJgWorldPos = (modelMatrix * vec4(transformed, 1.0)).xyz;`);
|
|
83
|
+
const materialUniformsGlsl = hasTexture
|
|
84
|
+
? `
|
|
85
|
+
uniform sampler2D uMatColor;
|
|
86
|
+
uniform sampler2D uMatNormal;
|
|
87
|
+
uniform sampler2D uMatRoughness;
|
|
88
|
+
uniform sampler2D uMatAo;
|
|
89
|
+
uniform float uMatRepeat;
|
|
90
|
+
uniform float uMatStrength;`
|
|
91
|
+
: "";
|
|
92
|
+
const materialColorGlsl = hasTexture
|
|
93
|
+
? `
|
|
94
|
+
vec2 jgMatUv = jgWp / uMatRepeat;
|
|
95
|
+
vec3 jgMatColor = texture2D(uMatColor, jgMatUv).rgb;
|
|
96
|
+
jgCol = mix(jgCol, jgMatColor, uMatStrength);`
|
|
97
|
+
: "";
|
|
98
|
+
const materialRoughnessGlsl = hasTexture
|
|
99
|
+
? `
|
|
100
|
+
float jgMatRough = texture2D(uMatRoughness, jgMatUv).g;
|
|
101
|
+
roughnessFactor = mix(roughnessFactor, jgMatRough, uMatStrength);`
|
|
102
|
+
: "";
|
|
103
|
+
const materialNormalGlsl = hasTexture
|
|
104
|
+
? `
|
|
105
|
+
vec2 jgMatNormalXy = texture2D(uMatNormal, jgMatUv).rg * 2.0 - 1.0;
|
|
106
|
+
normal = normalize(normal + vec3(jgMatNormalXy.x, 0.0, jgMatNormalXy.y) * uMatStrength * 0.6);`
|
|
107
|
+
: "";
|
|
108
|
+
const materialAoGlsl = hasTexture
|
|
109
|
+
? `
|
|
110
|
+
float jgMatAo = texture2D(uMatAo, jgMatUv).r;
|
|
111
|
+
reflectedLight.indirectDiffuse *= mix(1.0, jgMatAo, uMatStrength);`
|
|
112
|
+
: "";
|
|
54
113
|
shader.fragmentShader = shader.fragmentShader
|
|
55
114
|
.replace("#include <common>", `#include <common>
|
|
56
115
|
varying vec3 vJgWorldPos;
|
|
@@ -64,6 +123,7 @@ uniform float uWaterLevel;
|
|
|
64
123
|
uniform float uDetailScale;
|
|
65
124
|
uniform float uMacroScale;
|
|
66
125
|
uniform float uStrength;
|
|
126
|
+
${materialUniformsGlsl}
|
|
67
127
|
${NOISE_GLSL}`)
|
|
68
128
|
.replace("#include <color_fragment>", `#include <color_fragment>
|
|
69
129
|
vec2 jgWp = vJgWorldPos.xz;
|
|
@@ -83,8 +143,15 @@ jgCol = mix(jgCol, jgSand, jgSandW);
|
|
|
83
143
|
vec3 jgSnow = uSnowColor * mix(0.94, 1.04, jgFine);
|
|
84
144
|
float jgSnowW = smoothstep(uSnowHeight, uSnowHeight + 8.0, jgH) * (1.0 - jgRockW * 0.6) * uStrength;
|
|
85
145
|
jgCol = mix(jgCol, jgSnow, jgSnowW);
|
|
86
|
-
|
|
146
|
+
${materialColorGlsl}
|
|
147
|
+
diffuseColor.rgb = jgCol;`)
|
|
148
|
+
.replace("#include <roughnessmap_fragment>", `#include <roughnessmap_fragment>
|
|
149
|
+
${materialRoughnessGlsl}`)
|
|
150
|
+
.replace("#include <normal_fragment_maps>", `#include <normal_fragment_maps>
|
|
151
|
+
${materialNormalGlsl}`)
|
|
152
|
+
.replace("#include <aomap_fragment>", `#include <aomap_fragment>
|
|
153
|
+
${materialAoGlsl}`);
|
|
87
154
|
};
|
|
88
|
-
material.customProgramCacheKey = () => `jgengine-terrain-detail-${detail.rockSlopeStart}-${detail.snowHeight}`;
|
|
155
|
+
material.customProgramCacheKey = () => `jgengine-terrain-detail-${detail.rockSlopeStart}-${detail.snowHeight}-${hasTexture ? "tex" : "flat"}`;
|
|
89
156
|
return { material };
|
|
90
157
|
}
|
|
@@ -27,10 +27,15 @@ export interface TerrainVertexColorOptions {
|
|
|
27
27
|
waterline?: THREE.ColorRepresentation;
|
|
28
28
|
waterlineHeight?: number;
|
|
29
29
|
}
|
|
30
|
+
/** @internal */
|
|
30
31
|
export declare function normalizeHeightBlend(height: number, minHeight: number, maxHeight: number): number;
|
|
32
|
+
/** @internal */
|
|
31
33
|
export declare function resolveTerrainSize(size?: TerrainArea): ResolvedTerrainSize;
|
|
34
|
+
/** @internal */
|
|
32
35
|
export declare function resolveTerrainSegments(segments?: ProceduralTerrainConfig["segments"]): ResolvedTerrainSegments;
|
|
36
|
+
/** @internal */
|
|
33
37
|
export declare function toNoiseFieldConfig(config?: ProceduralTerrainConfig): NoiseFieldConfig;
|
|
38
|
+
/** @internal */
|
|
34
39
|
export declare function createProceduralTerrainSampler(config?: ProceduralTerrainConfig): TerrainHeightSampler;
|
|
35
40
|
/** Per-position palette override for multi-biome ground coloring — `createTerrainPaletteSampler` from `@jgengine/core/world/terrain` returns exactly this shape. */
|
|
36
41
|
export type TerrainPaletteSampler = (x: number, z: number) => {
|
|
@@ -51,6 +56,8 @@ export interface FieldGroundOptions {
|
|
|
51
56
|
* Mesh any `TerrainField` — including a `CarvableField` with craters/mounds written into it — into a
|
|
52
57
|
* vertex-coloured ground geometry. `sampleHeight` drives the vertices, so runtime carves show up as
|
|
53
58
|
* real depressions the moment the field is re-sampled (bump the caller's rebuild key after a carve).
|
|
54
|
-
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
55
61
|
export declare function createFieldGroundGeometry(field: TerrainField, options?: FieldGroundOptions): THREE.BufferGeometry;
|
|
62
|
+
/** @internal */
|
|
56
63
|
export declare function createProceduralGroundGeometry(config?: ProceduralTerrainConfig, colors?: TerrainVertexColorOptions): THREE.BufferGeometry;
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import { noiseField } from "@jgengine/core/world/terrain";
|
|
2
2
|
import * as THREE from "three";
|
|
3
3
|
import {} from "./random.js";
|
|
4
|
+
/** @internal */
|
|
4
5
|
export function normalizeHeightBlend(height, minHeight, maxHeight) {
|
|
5
6
|
const range = maxHeight - minHeight;
|
|
6
7
|
if (range <= 1e-6)
|
|
7
8
|
return 0.5;
|
|
8
9
|
return THREE.MathUtils.clamp((height - minHeight) / range, 0, 1);
|
|
9
10
|
}
|
|
11
|
+
/** @internal */
|
|
10
12
|
export function resolveTerrainSize(size = 40) {
|
|
11
13
|
return typeof size === "number" ? { width: size, depth: size } : { width: size[0], depth: size[1] };
|
|
12
14
|
}
|
|
15
|
+
/** @internal */
|
|
13
16
|
export function resolveTerrainSegments(segments = 96) {
|
|
14
17
|
if (typeof segments !== "number")
|
|
15
18
|
return { x: Math.max(1, Math.floor(segments[0])), z: Math.max(1, Math.floor(segments[1])) };
|
|
16
19
|
const resolved = Math.max(1, Math.floor(segments));
|
|
17
20
|
return { x: resolved, z: resolved };
|
|
18
21
|
}
|
|
22
|
+
/** @internal */
|
|
19
23
|
export function toNoiseFieldConfig(config = {}) {
|
|
20
24
|
return {
|
|
21
25
|
seed: config.seed,
|
|
@@ -26,6 +30,7 @@ export function toNoiseFieldConfig(config = {}) {
|
|
|
26
30
|
baseHeight: config.baseOffset ?? 0,
|
|
27
31
|
};
|
|
28
32
|
}
|
|
33
|
+
/** @internal */
|
|
29
34
|
export function createProceduralTerrainSampler(config = {}) {
|
|
30
35
|
return noiseField(toNoiseFieldConfig(config)).sampleHeight;
|
|
31
36
|
}
|
|
@@ -33,7 +38,8 @@ export function createProceduralTerrainSampler(config = {}) {
|
|
|
33
38
|
* Mesh any `TerrainField` — including a `CarvableField` with craters/mounds written into it — into a
|
|
34
39
|
* vertex-coloured ground geometry. `sampleHeight` drives the vertices, so runtime carves show up as
|
|
35
40
|
* real depressions the moment the field is re-sampled (bump the caller's rebuild key after a carve).
|
|
36
|
-
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
37
43
|
export function createFieldGroundGeometry(field, options = {}) {
|
|
38
44
|
const size = resolveTerrainSize(options.size);
|
|
39
45
|
const segments = resolveTerrainSegments(options.segments);
|
|
@@ -118,6 +124,7 @@ function buildGroundGeometry(size, segments, sampler, opts) {
|
|
|
118
124
|
geometry.computeBoundingSphere();
|
|
119
125
|
return geometry;
|
|
120
126
|
}
|
|
127
|
+
/** @internal */
|
|
121
128
|
export function createProceduralGroundGeometry(config = {}, colors = {}) {
|
|
122
129
|
const size = resolveTerrainSize(config.size);
|
|
123
130
|
const segments = resolveTerrainSegments(config.segments);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MutableRefObject } from "react";
|
|
2
|
-
import { type TouchScheme } from "@jgengine/core/input/touchScheme";
|
|
2
|
+
import { type TouchScheme, type TouchStyle } from "@jgengine/core/input/touchScheme";
|
|
3
3
|
export interface TouchCodeSink {
|
|
4
4
|
onCodeDown(code: string): void;
|
|
5
5
|
onCodeUp(code: string): void;
|
|
@@ -14,9 +14,11 @@ export declare function primaryButtonOffsets(count: number, scale?: number): {
|
|
|
14
14
|
bottom: number;
|
|
15
15
|
}[] | null;
|
|
16
16
|
/**
|
|
17
|
-
* Vertical space (px, excluding device safe areas)
|
|
18
|
-
* the bottom edge. The shell publishes it as
|
|
19
|
-
* `HudCanvas` regions never collide with touch
|
|
17
|
+
* Vertical space (px, excluding device safe areas) that *bottom-docked* clusters
|
|
18
|
+
* occupy above the bottom edge. The shell publishes it as
|
|
19
|
+
* `--jg-hud-dock-clearance` so `HudCanvas` regions never collide with touch
|
|
20
|
+
* controls. Side rails and top clusters reserve their own rectangles through the
|
|
21
|
+
* layout registry instead of this scalar.
|
|
20
22
|
*/
|
|
21
23
|
export declare function touchDockClearance(scheme: TouchScheme | null, scale?: number): number;
|
|
22
24
|
export declare function TouchPlaySurface({ scheme, sink, yawRef, pitchRef, maxPitch, onPrimaryTap, }: {
|
|
@@ -27,8 +29,10 @@ export declare function TouchPlaySurface({ scheme, sink, yawRef, pitchRef, maxPi
|
|
|
27
29
|
maxPitch: number;
|
|
28
30
|
onPrimaryTap: () => void;
|
|
29
31
|
}): import("react").JSX.Element;
|
|
30
|
-
export declare function TouchControlsDock({ scheme, sink, scale }: {
|
|
32
|
+
export declare function TouchControlsDock({ scheme, sink, style, scale, }: {
|
|
31
33
|
scheme: TouchScheme;
|
|
32
34
|
sink: TouchCodeSink;
|
|
35
|
+
/** Player-selected skin; falls back to the scheme's game default. */
|
|
36
|
+
style?: TouchStyle;
|
|
33
37
|
scale?: number;
|
|
34
38
|
}): import("react").JSX.Element;
|