@plasius/renderer 1.0.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/CODE_OF_CONDUCT.md +79 -0
  3. package/CONTRIBUTORS.md +27 -0
  4. package/LICENSE +203 -0
  5. package/README.md +70 -0
  6. package/SECURITY.md +17 -0
  7. package/dist/adaptivedpr.d.ts +2 -0
  8. package/dist/adaptivedpr.d.ts.map +1 -0
  9. package/dist/adaptivedpr.js +65 -0
  10. package/dist/camera/cameraRigProfile.d.ts +12 -0
  11. package/dist/camera/cameraRigProfile.d.ts.map +1 -0
  12. package/dist/camera/cameraRigProfile.js +18 -0
  13. package/dist/camera/managedCameraController.d.ts +49 -0
  14. package/dist/camera/managedCameraController.d.ts.map +1 -0
  15. package/dist/camera/managedCameraController.js +271 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +3 -0
  19. package/dist/landscape.d.ts +2 -0
  20. package/dist/landscape.d.ts.map +1 -0
  21. package/dist/landscape.js +120 -0
  22. package/dist/player/player.d.ts +8 -0
  23. package/dist/player/player.d.ts.map +1 -0
  24. package/dist/player/player.js +203 -0
  25. package/dist/player/playerstore.d.ts +205 -0
  26. package/dist/player/playerstore.d.ts.map +1 -0
  27. package/dist/player/playerstore.js +500 -0
  28. package/dist/renderStateProvider.d.ts +57 -0
  29. package/dist/renderStateProvider.d.ts.map +1 -0
  30. package/dist/renderStateProvider.js +50 -0
  31. package/dist/renderer.d.ts +9 -0
  32. package/dist/renderer.d.ts.map +1 -0
  33. package/dist/renderer.js +165 -0
  34. package/dist/scene.d.ts +7 -0
  35. package/dist/scene.d.ts.map +1 -0
  36. package/dist/scene.js +10 -0
  37. package/dist/shaders/fragment/landscapeFragmentShader.js +141 -0
  38. package/dist/shaders/landscapeShader.d.ts +13 -0
  39. package/dist/shaders/landscapeShader.d.ts.map +1 -0
  40. package/dist/shaders/landscapeShader.js +25 -0
  41. package/dist/shaders/vertex/landscapeVertexShader.js +67 -0
  42. package/dist/styles/renderer.module.css +90 -0
  43. package/dist/worldSpaceCompositor.d.ts +50 -0
  44. package/dist/worldSpaceCompositor.d.ts.map +1 -0
  45. package/dist/worldSpaceCompositor.js +159 -0
  46. package/dist/xr/rendererXrBridge.d.ts +12 -0
  47. package/dist/xr/rendererXrBridge.d.ts.map +1 -0
  48. package/dist/xr/rendererXrBridge.js +17 -0
  49. package/docs/adrs/adr-0001-renderer-package-scope.md +21 -0
  50. package/docs/adrs/adr-0002-public-repo-governance.md +24 -0
  51. package/docs/adrs/adr-0003-world-space-compositor-contracts.md +34 -0
  52. package/docs/adrs/adr-template.md +35 -0
  53. package/docs/design/0001-public-package-scope.md +18 -0
  54. package/docs/tdrs/index.md +3 -0
  55. package/docs/tdrs/tdr-0001-renderer-public-package-standards-alignment.md +19 -0
  56. package/legal/CLA-REGISTRY.csv +1 -0
  57. package/legal/CLA.md +22 -0
  58. package/legal/CORPORATE_CLA.md +57 -0
  59. package/legal/INDIVIDUAL_CLA.md +91 -0
  60. package/package.json +117 -0
  61. package/src/adaptivedpr.tsx +74 -0
  62. package/src/camera/cameraRigProfile.ts +29 -0
  63. package/src/camera/managedCameraController.tsx +401 -0
  64. package/src/global.d.ts +10 -0
  65. package/src/index.ts +3 -0
  66. package/src/landscape.tsx +321 -0
  67. package/src/player/player.tsx +257 -0
  68. package/src/player/playerstore.tsx +733 -0
  69. package/src/renderStateProvider.tsx +121 -0
  70. package/src/renderer.tsx +294 -0
  71. package/src/scene.tsx +42 -0
  72. package/src/shaders/fragment/landscapeFragmentShader.d.ts +4 -0
  73. package/src/shaders/fragment/landscapeFragmentShader.js +141 -0
  74. package/src/shaders/landscapeShader.tsx +39 -0
  75. package/src/shaders/vertex/landscapeVertexShader.d.ts +4 -0
  76. package/src/shaders/vertex/landscapeVertexShader.js +67 -0
  77. package/src/styles/renderer.module.css +90 -0
  78. package/src/worldSpaceCompositor.ts +265 -0
  79. package/src/xr/rendererXrBridge.ts +44 -0
@@ -0,0 +1,165 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import * as THREE from "three/webgpu";
3
+ import { Canvas, } from "@react-three/fiber";
4
+ import { useRef, useEffect, Suspense } from "react";
5
+ import { Html, useProgress } from "@react-three/drei";
6
+ import { createXrManager } from "@plasius/gpu-xr";
7
+ import { BsHeadsetVr } from "react-icons/bs";
8
+ import { CgWebsite } from "react-icons/cg";
9
+ import { RenderStore } from "./renderStateProvider.js";
10
+ import styles from "./styles/renderer.module.css";
11
+ import { Scene } from "./scene.js";
12
+ import { Player } from "./player/player.js";
13
+ import { AdaptiveDPR } from "./adaptivedpr.js";
14
+ import { bindSessionToRenderer, rendererVrSessionInit, } from "./xr/rendererXrBridge.js";
15
+ import { createRendererCameraManager, ManagedCameraController, } from "./camera/managedCameraController.js";
16
+ function Loader() {
17
+ const { progress } = useProgress();
18
+ return _jsxs(Html, { center: true, children: [progress, " % loaded"] });
19
+ }
20
+ var Perf;
21
+ (function (Perf) {
22
+ Perf[Perf["Low"] = 0] = "Low";
23
+ Perf[Perf["Medium"] = 1] = "Medium";
24
+ Perf[Perf["High"] = 2] = "High";
25
+ Perf[Perf["Ultra"] = 3] = "Ultra";
26
+ })(Perf || (Perf = {}));
27
+ function Renderer({ cameraPosition, cameraRotation, multiview = true, children, }) {
28
+ const canvasRef = useRef(null);
29
+ const sceneRef = useRef(null);
30
+ const rendererRef = useRef(null);
31
+ const xrManagerRef = useRef(null);
32
+ const cameraManagerRef = useRef(null);
33
+ const { useVR, cameraRigProfile } = RenderStore.useStore();
34
+ const dispatch = RenderStore.useDispatch();
35
+ if (!cameraManagerRef.current) {
36
+ cameraManagerRef.current = createRendererCameraManager({
37
+ maxParallelViews: multiview ? 2 : 1,
38
+ maxHotCameras: 3,
39
+ });
40
+ }
41
+ const cameraManager = cameraManagerRef.current;
42
+ useEffect(() => {
43
+ return () => {
44
+ cameraManager.clear();
45
+ };
46
+ }, [cameraManager]);
47
+ useEffect(() => {
48
+ const xrManager = createXrManager({
49
+ onSessionStart: (session) => {
50
+ void bindSessionToRenderer(rendererRef.current, session).catch(() => {
51
+ dispatch({ type: "set_vr_mode", payload: false });
52
+ });
53
+ },
54
+ onSessionEnd: () => {
55
+ dispatch({ type: "set_vr_mode", payload: false });
56
+ },
57
+ });
58
+ xrManagerRef.current = xrManager;
59
+ void xrManager.probeSupport(["immersive-vr"]).catch(() => {
60
+ // Ignore probe failures; entering VR will surface actionable errors.
61
+ });
62
+ return () => {
63
+ const current = xrManagerRef.current;
64
+ xrManagerRef.current = null;
65
+ if (current) {
66
+ void current.dispose();
67
+ }
68
+ };
69
+ }, [dispatch]);
70
+ useEffect(() => {
71
+ const canvas = canvasRef.current;
72
+ const xrManager = xrManagerRef.current;
73
+ if (!canvas || !xrManager) {
74
+ return;
75
+ }
76
+ const fullscreenChangeHandler = () => {
77
+ if (!document.fullscreenElement) {
78
+ dispatch({ type: "set_vr_mode", payload: false });
79
+ }
80
+ };
81
+ const enterVRHandler = async () => {
82
+ try {
83
+ if (!document.fullscreenElement) {
84
+ await canvas.requestFullscreen();
85
+ }
86
+ canvas.addEventListener("fullscreenchange", fullscreenChangeHandler);
87
+ await xrManager.enterVr(rendererVrSessionInit);
88
+ }
89
+ catch {
90
+ dispatch({ type: "set_vr_mode", payload: false });
91
+ }
92
+ };
93
+ const exitVRHandler = async () => {
94
+ await xrManager.exitSession();
95
+ if (document.fullscreenElement === canvas) {
96
+ await document.exitFullscreen().catch(() => { });
97
+ }
98
+ };
99
+ if (!useVR) {
100
+ void exitVRHandler();
101
+ return () => {
102
+ canvas.removeEventListener("fullscreenchange", fullscreenChangeHandler);
103
+ };
104
+ }
105
+ void enterVRHandler();
106
+ return () => {
107
+ canvas.removeEventListener("fullscreenchange", fullscreenChangeHandler);
108
+ };
109
+ }, [useVR, dispatch]);
110
+ return (_jsxs(_Fragment, { children: [_jsx("button", { title: useVR ? "Exit VR" : "Enter VR", onClick: () => dispatch({ type: "set_vr_mode", payload: !useVR }), className: styles.vrButton, children: useVR ? _jsx(CgWebsite, { size: 24 }) : _jsx(BsHeadsetVr, { size: 24 }) }), _jsx(Suspense, { fallback: _jsx("div", { style: { height: "100%" } }), children: _jsxs(Canvas, { shadows: "soft", tabIndex: 0, ref: canvasRef, className: `${styles.canvas} ${!useVR ? styles.fixed : styles.absolute}`, style: { width: "100%", height: "100%" }, camera: {
111
+ position: cameraPosition.toArray(),
112
+ rotation: cameraRotation.toArray(),
113
+ near: 0.1,
114
+ far: 1000,
115
+ fov: 50,
116
+ }, dpr: useVR ? 1 : [1, 4], gl: async (props) => {
117
+ const params = {
118
+ ...props,
119
+ multiview,
120
+ };
121
+ const renderer = new THREE.WebGPURenderer(params);
122
+ await renderer.init();
123
+ if (useVR && "setPixelRatio" in renderer) {
124
+ renderer.setPixelRatio(1);
125
+ }
126
+ if ("setClearColor" in renderer) {
127
+ renderer.setClearColor("lightblue");
128
+ }
129
+ if ("outputColorSpace" in renderer) {
130
+ renderer.outputColorSpace = THREE.SRGBColorSpace;
131
+ }
132
+ if ("xr" in renderer) {
133
+ renderer.xr.enabled = true;
134
+ }
135
+ renderer.getContextAttributes = () => ({
136
+ antialias: props.antialias ?? true,
137
+ alpha: props.alpha ?? true,
138
+ stencil: props.stencil ?? true,
139
+ depth: props.depth ?? true,
140
+ powerPreference: props.powerPreference ?? "high-performance",
141
+ xrCompatible: true,
142
+ });
143
+ return renderer;
144
+ }, onCreated: (state) => {
145
+ // In XR, keep DPR stable to avoid stereo stitching issues
146
+ if (useVR && "setPixelRatio" in state.gl) {
147
+ // Cap DPR to a reasonable value for HMDs; many runtimes manage internal resolution
148
+ state.gl.setPixelRatio(1);
149
+ }
150
+ if ("setClearColor" in state.gl) {
151
+ state.gl.setClearColor("lightblue");
152
+ }
153
+ if ("setSize" in state.gl) {
154
+ state.gl.setSize(state.size.width, state.size.height);
155
+ }
156
+ if ("outputColorSpace" in state.gl) {
157
+ state.gl.outputColorSpace = THREE.SRGBColorSpace;
158
+ }
159
+ rendererRef.current = state.gl;
160
+ }, children: [!useVR && _jsx(AdaptiveDPR, {}), _jsxs(Suspense, { fallback: Loader(), children: [!useVR && (_jsx(ManagedCameraController, { manager: cameraManager, profile: cameraRigProfile, cameraId: "main" })), _jsxs(Scene, { ref: sceneRef, children: [_jsx(Player, { cameraManager: cameraManager, cameraId: "main" }), children] })] })] }) })] }));
161
+ }
162
+ function WrappedRenderer(props) {
163
+ return (_jsx(RenderStore.Provider, { children: _jsx(Renderer, { ...props }) }));
164
+ }
165
+ export { WrappedRenderer as Renderer };
@@ -0,0 +1,7 @@
1
+ import { type ReactNode } from "react";
2
+ import { Group } from "three";
3
+ export interface SceneProps {
4
+ children?: ReactNode[];
5
+ }
6
+ export declare const Scene: import("react").ForwardRefExoticComponent<SceneProps & import("react").RefAttributes<Group<import("three").Object3DEventMap>>>;
7
+ //# sourceMappingURL=scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAInD,OAAO,EAAW,KAAK,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;CACxB;AAGD,eAAO,MAAM,KAAK,gIA8BhB,CAAC"}
package/dist/scene.js ADDED
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { Physics } from "@react-three/rapier";
4
+ import { Environment } from "@react-three/drei";
5
+ import { Landscape } from "./landscape.js";
6
+ import { Vector3 } from "three";
7
+ // Use forwardRef to make ref work
8
+ export const Scene = forwardRef(function Scene(props, ref) {
9
+ return (_jsxs("group", { ref: ref, children: [_jsx(Environment, { preset: "dawn", background: false, environmentIntensity: 0.5 }), _jsx("ambientLight", { color: 0xe1e1e1, intensity: 0.3 }), _jsx("directionalLight", { color: 0xf0f0f0, intensity: 1.0, position: new Vector3(5, 10, -10), castShadow: true, "shadow-mapSize-width": 2048, "shadow-mapSize-height": 2048, "shadow-bias": -0.0005, "shadow-camera-left": -20, "shadow-camera-right": 20, "shadow-camera-top": 20, "shadow-camera-bottom": -20, "shadow-camera-near": 0.5, "shadow-camera-far": 100 }), _jsxs(Physics, { gravity: [0, -9.81, 0], children: [_jsx(Landscape, {}), props.children] })] }));
10
+ });
@@ -0,0 +1,141 @@
1
+ import * as TSL from "three/tsl";
2
+
3
+ // Fragment shader
4
+ export const landscapeFragmentShader = TSL.Fn((shader) => {
5
+ const vHeight = shader.input.float("vHeight");
6
+ const fragColor = shader.uniforms.vec4("fragColor");
7
+
8
+ const lowColor = TSL.vec3(0.5, 0.8, 0.3); // Grass
9
+ const highColor = TSL.vec3(1.0, 1.0, 1.0); // Snow
10
+
11
+ const mixFactor = TSL.smoothstep(0.0, 2.0, vHeight);
12
+ const baseColor = TSL.mix(lowColor, highColor, mixFactor);
13
+
14
+ TSL.assign(fragColor, TSL.vec4(baseColor, 1.0));
15
+ });
16
+
17
+ /*import * as TSL from "three/tsl";
18
+
19
+ // Fragment shader
20
+ export const landscapeFragmentShader = TSL.Fn((shader) => {
21
+ const vUv = shader.input.vec2("vUv");
22
+ const vHeight = shader.input.float("vHeight");
23
+ const vPos = shader.input.vec3("vPos");
24
+
25
+ const time = shader.uniforms.float("time");
26
+ const fragColor = shader.uniforms.vec4("fragColor");
27
+
28
+ const applyWind = (normal, pos) => {
29
+ const windDir = TSL.vec2(
30
+ TSL.sin(TSL.add(TSL.mul(pos.x, 0.1), TSL.mul(time, 0.3))),
31
+ TSL.cos(TSL.add(TSL.mul(pos.y, 0.1), TSL.mul(time, 0.3)))
32
+ );
33
+ const strength = TSL.add(
34
+ 0.2,
35
+ TSL.mul(
36
+ 0.1,
37
+ TSL.sin(TSL.add(TSL.dot(pos, TSL.vec2(0.3, 0.7)), TSL.mul(time, 0.5)))
38
+ )
39
+ );
40
+ const wind = TSL.mul(
41
+ TSL.normalize(TSL.vec3(windDir.x, windDir.y, 0.0)),
42
+ strength
43
+ );
44
+ return TSL.normalize(TSL.add(normal, TSL.mul(wind, 0.4)));
45
+ };
46
+
47
+ const calculateNormal = (height, uv, pos) => {
48
+ const eps = 0.01;
49
+ const hL = TSL.smoothstep(-2.0, 4.5, TSL.sub(height, eps));
50
+ const hR = TSL.smoothstep(-2.0, 4.5, TSL.add(height, eps));
51
+ const hD = TSL.smoothstep(-2.0, 4.5, TSL.sub(height, eps));
52
+ const hU = TSL.smoothstep(-2.0, 4.5, TSL.add(height, eps));
53
+ const normal = TSL.normalize(
54
+ TSL.vec3(TSL.sub(hL, hR), TSL.sub(hD, hU), 2.0)
55
+ );
56
+ return applyWind(normal, pos.xz);
57
+ };
58
+
59
+ const grassWave = (uv, height) => {
60
+ const baseFreq = 40.0;
61
+ const speed = 0.5;
62
+ const wave1 = TSL.sin(
63
+ TSL.mul(TSL.add(TSL.add(uv.x, uv.y), TSL.mul(time, speed)), baseFreq)
64
+ );
65
+ const wave2 = TSL.cos(
66
+ TSL.mul(
67
+ TSL.add(TSL.sub(uv.x, uv.y), TSL.mul(time, TSL.mul(speed, 1.2))),
68
+ TSL.mul(baseFreq, 0.8)
69
+ )
70
+ );
71
+ const pattern = TSL.mul(TSL.add(wave1, wave2), 0.03);
72
+ const density = TSL.smoothstep(0.3, 0.7, height);
73
+ return TSL.mul(pattern, density);
74
+ };
75
+
76
+ const grassDensityFactor = (coords) =>
77
+ TSL.smoothstep(
78
+ 0.4,
79
+ 0.9,
80
+ TSL.fract(
81
+ TSL.mul(
82
+ TSL.sin(TSL.dot(TSL.mul(coords, 0.2), TSL.vec2(12.9898, 78.233))),
83
+ 43758.5453
84
+ )
85
+ )
86
+ );
87
+
88
+ const sand = TSL.vec3(0.76, 0.7, 0.5);
89
+ const grass = TSL.vec3(0.4, 0.8, 0.2);
90
+ const stone = TSL.vec3(0.5, 0.5, 0.5);
91
+ const snow = TSL.vec3(0.95, 0.95, 0.95);
92
+
93
+ const low = TSL.smoothstep(-2.0, 0.0, vHeight);
94
+ const high = TSL.smoothstep(1.0, 3.0, vHeight);
95
+
96
+ let base = TSL.mix(sand, grass, low);
97
+ base = TSL.mix(base, stone, high);
98
+ base = TSL.mix(base, snow, TSL.smoothstep(2.5, 4.5, vHeight));
99
+
100
+ const normal = calculateNormal(vHeight, vUv, vPos);
101
+ const slope = TSL.dot(TSL.vec3(0.0, 0.0, 1.0), normal);
102
+ const snowBlend = TSL.smoothstep(0.8, 1.0, slope);
103
+ base = TSL.mix(
104
+ base,
105
+ snow,
106
+ TSL.mul(snowBlend, TSL.smoothstep(1.5, 4.5, vHeight))
107
+ );
108
+
109
+ const tintNoise = TSL.fract(
110
+ TSL.mul(TSL.sin(TSL.dot(vPos.xz, TSL.vec2(91.91, 47.47))), 43758.5453)
111
+ );
112
+ const tint = TSL.mix(
113
+ TSL.vec3(-0.05, 0.05, -0.02),
114
+ TSL.vec3(0.05, -0.03, 0.02),
115
+ tintNoise
116
+ );
117
+ base = TSL.add(base, tint);
118
+
119
+ const density = grassDensityFactor(vPos.xz);
120
+ base = TSL.mix(base, TSL.vec3(0.25, 0.4, 0.15), TSL.sub(1.0, density));
121
+
122
+ const lightDir = TSL.normalize(TSL.vec3(0.3, 0.5, 1.0));
123
+ let lighting = TSL.clamp(TSL.dot(lightDir, normal), 0.3, 1.0);
124
+ lighting = TSL.mul(lighting, TSL.add(0.8, TSL.mul(0.4, density)));
125
+
126
+ const grassMotion = TSL.mul(grassWave(vUv, vHeight), density);
127
+ const animatedGrass = TSL.vec3(0.0, TSL.mul(grassMotion, 0.4), 0.0);
128
+
129
+ const fresnel = TSL.pow(
130
+ TSL.sub(1.0, TSL.dot(TSL.normalize(TSL.vec3(0.0, 0.0, 1.0)), normal)),
131
+ 3.0
132
+ );
133
+ const fresnelColor = TSL.mul(TSL.vec3(0.2, 0.5, 0.1), fresnel);
134
+
135
+ const finalColor = TSL.mul(
136
+ TSL.add(TSL.add(base, animatedGrass), fresnelColor),
137
+ lighting
138
+ );
139
+ TSL.assign(fragColor, TSL.vec4(finalColor, 1.0));
140
+ });
141
+ */
@@ -0,0 +1,13 @@
1
+ import * as THREE from "three/webgpu";
2
+ declare class LandscapeShaderMaterial extends THREE.MeshStandardNodeMaterial {
3
+ constructor();
4
+ }
5
+ export { LandscapeShaderMaterial };
6
+ declare module "@react-three/fiber" {
7
+ interface ThreeElements {
8
+ landscapeShaderMaterial: ThreeElements["meshStandardMaterial"] & {
9
+ ref?: React.Ref<THREE.MeshStandardNodeMaterial>;
10
+ };
11
+ }
12
+ }
13
+ //# sourceMappingURL=landscapeShader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landscapeShader.d.ts","sourceRoot":"","sources":["../../src/shaders/landscapeShader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAOtC,cAAM,uBAAwB,SAAQ,KAAK,CAAC,wBAAwB;;CAkBnE;AAKD,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,OAAO,QAAQ,oBAAoB,CAAC;IAClC,UAAU,aAAa;QACrB,uBAAuB,EAAE,aAAa,CAAC,sBAAsB,CAAC,GAAG;YAC/D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;SACjD,CAAC;KACH;CACF"}
@@ -0,0 +1,25 @@
1
+ import * as THREE from "three/webgpu";
2
+ import { extend } from "@react-three/fiber";
3
+ // ✅ Define a class that extends the material
4
+ class LandscapeShaderMaterial extends THREE.MeshStandardNodeMaterial {
5
+ constructor() {
6
+ super({ color: new THREE.Color(0.4, 0.7, 0.2) });
7
+ /*
8
+ // Append your vertex shader to the existing position pipeline
9
+ if (this.positionNode)
10
+ this.positionNode = shader(() =>
11
+ add(this.positionNode!, landscapeVertexShader)
12
+ );
13
+ else this.positionNode = landscapeVertexShader;
14
+ // Append your fragment shader to the existing color pipeline
15
+ if (this.colorNode)
16
+ this.colorNode = shader(() =>
17
+ add(this.colorNode!, landscapeFragmentShader)
18
+ );
19
+ else this.colorNode = landscapeFragmentShader;
20
+ */
21
+ }
22
+ }
23
+ // ✅ Register the class with R3F so you can use it as a JSX tag
24
+ extend({ LandscapeShaderMaterial });
25
+ export { LandscapeShaderMaterial };
@@ -0,0 +1,67 @@
1
+ import * as TSL from "three/tsl";
2
+
3
+ // Vertex shader
4
+ export const landscapeVertexShader = TSL.Fn((shader) => {
5
+ const position = shader.input.vec3("position");
6
+ const uv = shader.input.vec2("uv");
7
+ const time = shader.uniforms.float("time");
8
+
9
+ let vHeight = shader.output.float("vHeight");
10
+ const clipPosition = output.vec4("gl_Position");
11
+
12
+ const waveZ = TSL.mul(
13
+ TSL.sin(TSL.add(TSL.mul(position.x, 0.5), TSL.mul(time, 1.0))),
14
+ 1.0
15
+ );
16
+
17
+ const newPos = TSL.vec3(position.x, position.y, TSL.add(position.z, waveZ));
18
+
19
+ TSL.assign(vHeight, newPos.z);
20
+ TSL.assign(clipPosition, TSL.vec4(newPos, 1.0));
21
+ });
22
+ /*
23
+
24
+
25
+ // Vertex shader
26
+ export const landscapeVertexShader = TSL.Fn((shader) => {
27
+ const position = shader.input.vec3("position");
28
+ const uv = shader.input.vec2("uv");
29
+
30
+ const time = shader.uniforms.float("time");
31
+ const seed = shader.uniforms.float("seed");
32
+
33
+ let vUv = shader.output.vec2("vUv");
34
+ let vHeight = shader.output.float("vHeight");
35
+ let vPos = shader.output.vec3("vPos");
36
+
37
+ const clipPosition = output.vec4("gl_Position");
38
+
39
+ const random = (st) =>
40
+ fract(
41
+ mul(
42
+ sin(dot(st, vec2(add(12.9898, seed), add(78.233, seed)))),
43
+ 43758.5453123
44
+ )
45
+ );
46
+
47
+ assign(vUv, uv);
48
+ assign(vPos, position);
49
+
50
+ const rnd = random(position.xy);
51
+ const waveZ = add(
52
+ mul(
53
+ add(
54
+ sin(add(mul(position.x, 0.2), time)),
55
+ cos(add(mul(position.y, 0.2), time))
56
+ ),
57
+ 0.75
58
+ ),
59
+ sub(mul(rnd, 2.0), 1.0)
60
+ );
61
+
62
+ const newPos = vec3(position.x, position.y, add(position.z, waveZ));
63
+
64
+ assign(vHeight, newPos.z);
65
+ assign(clipPosition, vec4(newPos, 1.0));
66
+ });
67
+ */
@@ -0,0 +1,90 @@
1
+ .canvas {
2
+ width: 100%;
3
+ height: 100%;
4
+ min-width: 640px;
5
+ min-height: 480px;
6
+ top: 0px;
7
+ left: 0px;
8
+ display: block;
9
+ z-index: 0;
10
+ }
11
+
12
+ .vrButton {
13
+ top: 67px;
14
+ position: absolute;
15
+ right: 15px;
16
+ z-index: 1000;
17
+ background-color: rgba(225, 18, 222, 0.8);
18
+ border: none;
19
+ border-radius: 5px;
20
+ padding: 10px;
21
+ cursor: pointer;
22
+ transition: background-color 0.3s;
23
+ }
24
+
25
+ .vrButton .fullscreen {
26
+ top: 15px;
27
+ }
28
+
29
+ .vrButton:hover {
30
+ background-color: rgba(200, 10, 200, 0.8);
31
+ border: 2px solid #fff;
32
+ box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
33
+ }
34
+ .vrButton:active {
35
+ background-color: rgba(175, 5, 175, 0.8);
36
+ }
37
+ .vrButton:disabled {
38
+ background-color: rgba(150, 0, 150, 0.8);
39
+ cursor: not-allowed;
40
+ }
41
+ .vrButton:disabled:hover {
42
+ background-color: rgba(150, 0, 150, 0.8);
43
+ }
44
+ .vrButton:focus {
45
+ outline: none;
46
+ box-shadow: 0 0 0 2px rgba(225, 18, 222, 0.8);
47
+ }
48
+ .vrButton:focus-visible {
49
+ outline: none;
50
+ box-shadow: 0 0 0 2px rgba(225, 18, 222, 0.8);
51
+ }
52
+ .vrButton:focus:not(:focus-visible) {
53
+ box-shadow: none;
54
+ }
55
+
56
+ .performanceContainer {
57
+ position: absolute;
58
+ bottom: 15px;
59
+ left: 15px;
60
+ width: 80px;
61
+ height: 48px;
62
+ z-index: 1000;
63
+ background-color: rgba(220, 220, 220, 0.5);
64
+ padding: 10px;
65
+ border-radius: 5px;
66
+ }
67
+
68
+ .performanceContainer p {
69
+ margin: 0;
70
+ font-size: 14px;
71
+ }
72
+ .performanceContainer span {
73
+ font-weight: bold;
74
+ }
75
+ .performanceContainer .performanceText {
76
+ font-size: 16px;
77
+ color: #202020;
78
+ }
79
+ .performanceContainer .frameRateText {
80
+ font-size: 16px;
81
+ color: #202020;
82
+ }
83
+ /* Custom canvas classes for VR/AR mode switching */
84
+ .fixed {
85
+ position: fixed;
86
+ }
87
+
88
+ .absolute {
89
+ position: absolute;
90
+ }
@@ -0,0 +1,50 @@
1
+ export declare const WORLD_SPACE_SURFACE_LAYERS: readonly ["screen", "overlay", "alert"];
2
+ export type WorldSpaceSurfaceLayer = (typeof WORLD_SPACE_SURFACE_LAYERS)[number];
3
+ export declare const WORLD_SPACE_OCCLUSION_MODES: readonly ["world", "overlay", "always-visible"];
4
+ export type WorldSpaceOcclusionMode = (typeof WORLD_SPACE_OCCLUSION_MODES)[number];
5
+ export interface WorldSpaceOcclusionPolicy {
6
+ mode: WorldSpaceOcclusionMode;
7
+ depthTest: boolean;
8
+ depthWrite: boolean;
9
+ polygonOffset: boolean;
10
+ polygonOffsetFactor: number;
11
+ polygonOffsetUnits: number;
12
+ renderOrderOffset: number;
13
+ fadeWhenOccluded: boolean;
14
+ }
15
+ export interface WorldSpaceSurfaceInput {
16
+ id: string;
17
+ slot: string;
18
+ layer: WorldSpaceSurfaceLayer;
19
+ priority?: number;
20
+ occlusionMode?: WorldSpaceOcclusionMode;
21
+ exclusiveSlot?: boolean;
22
+ }
23
+ export interface ComposedWorldSpaceSurface extends WorldSpaceSurfaceInput {
24
+ exclusiveSlot: boolean;
25
+ occlusionMode: WorldSpaceOcclusionMode;
26
+ occlusionPolicy: WorldSpaceOcclusionPolicy;
27
+ renderOrder: number;
28
+ slotIndex: number;
29
+ }
30
+ export interface WorldSpaceCompositionCollision {
31
+ slot: string;
32
+ surfaceIds: string[];
33
+ reason: "exclusive-slot-conflict";
34
+ }
35
+ export interface WorldSpaceCompositionResult {
36
+ surfaces: ComposedWorldSpaceSurface[];
37
+ collisions: WorldSpaceCompositionCollision[];
38
+ }
39
+ export interface WorldSpaceCompositionOptions {
40
+ slotOrder?: string[];
41
+ startingRenderOrder?: number;
42
+ slotStep?: number;
43
+ priorityStep?: number;
44
+ }
45
+ export declare function resolveWorldSpaceOcclusionPolicy(mode: WorldSpaceOcclusionMode): WorldSpaceOcclusionPolicy;
46
+ export declare function resolveWorldSpaceRenderOrder(surface: WorldSpaceSurfaceInput, options?: WorldSpaceCompositionOptions & {
47
+ slotIndex?: number;
48
+ }): number;
49
+ export declare function composeWorldSpaceSurfaces(surfaces: readonly WorldSpaceSurfaceInput[], options?: WorldSpaceCompositionOptions): WorldSpaceCompositionResult;
50
+ //# sourceMappingURL=worldSpaceCompositor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worldSpaceCompositor.d.ts","sourceRoot":"","sources":["../src/worldSpaceCompositor.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B,yCAI7B,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,eAAO,MAAM,2BAA2B,iDAI9B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,sBAAsB,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,uBAAuB,CAAC;IACvC,eAAe,EAAE,yBAAyB,CAAC;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,yBAAyB,CAAC;CACnC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,UAAU,EAAE,8BAA8B,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAiHD,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,uBAAuB,GAC5B,yBAAyB,CAE3B;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,sBAAsB,EAC/B,OAAO,GAAE,4BAA4B,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClE,MAAM,CAiBR;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,EAC3C,OAAO,GAAE,4BAAiC,GACzC,2BAA2B,CA0D7B"}