diff --git a/src/App.tsx b/src/App.tsx index 9ee57a4..fb9df72 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,9 +1,22 @@ +import { useEffect, useRef } from "react"; import Background from "./components/Background"; import "./main.css"; +import { init } from "./scripts/lang"; export function App() { + const canvasRef = useRef(null); + + useEffect(() => { + init(canvasRef.current); + }, []); + return ( - + <> +
+ +
+ + ); } diff --git a/src/components/Background.tsx b/src/components/Background.tsx index f7938a0..954c137 100644 --- a/src/components/Background.tsx +++ b/src/components/Background.tsx @@ -9,9 +9,11 @@ export default function Background() { }, []); return ( - <> -
- - +
+
+
+
+ +
); } \ No newline at end of file diff --git a/src/main.css b/src/main.css index 71c6a8d..0576e88 100644 --- a/src/main.css +++ b/src/main.css @@ -83,7 +83,7 @@ body { rotate: 90deg; } #language-div { - position: absolute; padding: 10px; padding-right: 20px; z-index: 3; + position: absolute; padding: 10px; z-index: 3; right: 20px; } #language-renderer { width: 100%; height: 100vh; display: block; margin: 0; padding: 0; cursor: grab; @@ -94,6 +94,10 @@ body { #projects { position: absolute; top: 50vh; left: 20%; transform: translateX(-50%); z-index: 11; width: 900px; height: auto; display: grid; grid-template-columns: 50% 50%; left: 50%; width: 90%; } +#background { + position: fixed; + z-index: -10; +} #footer { background: linear-gradient(to bottom left, rgb(41, 11, 41), rgb(44, 18, 44)); margin-bottom: 0px; @@ -128,7 +132,9 @@ body { background: linear-gradient(to bottom right, rgba(0, 0, 0, 0.5), rgba(107, 29, 107, 0.3)); background: -webkit-linear-gradient(to bottom right, rgba(0, 0, 0, 0.5), rgba(107, 29, 107, 0.3) 100%); background: -moz-linear-gradient(to bottom right, rgba(0, 0, 0, 0.5), rgba(107, 29, 107, 0.3) 100%); - position: fixed; width: 100%; height: 100%; + position: fixed; + width: 100%; height: 100%; + top: 0px; z-index: 1000000; } .devider { @@ -287,6 +293,8 @@ a.icon:hover { width: fit-content; height: fit-content; animation: float 5s ease-in-out infinite; } .gradient-overlay img { + position: absolute; + z-index: 100000000; width: 7vh; height: 7vh; transform-origin: 50% 50%; animation: float-rotate 6s ease-in-out infinite; filter: blur(0.5svh); transition-duration: 0.5s; @@ -294,6 +302,7 @@ a.icon:hover { .gradient-overlay img:hover { filter: none; scale: 1.4; + cursor: pointer; } .rotate-away { transform-origin: 50% 0px 50vh; diff --git a/src/scripts/background.js b/src/scripts/background.js index 28d9371..6fd2744 100644 --- a/src/scripts/background.js +++ b/src/scripts/background.js @@ -11,7 +11,7 @@ export async function init(canvas) { const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(0, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({antialias: false, canvas: canvas}); - renderer.setSize(window.innerWidth/2, window.innerHeight); + renderer.setSize(window.innerWidth, window.innerHeight); const composer = new EffectComposer( renderer ); const uniforms = { diff --git a/src/scripts/lang.js b/src/scripts/lang.js index ee2e0d5..773e1cd 100644 --- a/src/scripts/lang.js +++ b/src/scripts/lang.js @@ -4,192 +4,192 @@ import engPath from '../images/english.png' import nldPath from '../images/dutch.jpg' import rusPath from '../images/russian.jpg' -let language = "en"; +export async function init(canvas) { + let language = "en"; -function determineLanguage(){ - const userLang = localStorage.getItem("preferredLanguage") || navigator.language || navigator.userLanguage; - switch (userLang) { - case "ru": { - language = "ru"; - cube.rotation.y = 1.5707963267948966; - break; - } - case "nl": { - language = "nl"; - cube.rotation.y = 4.71238898038469; - } - } - if (language != "en") setLanguage(language); -} - -var elements = document.querySelectorAll('[ts]'); - -function setLanguage(l) { - language = l; - const arr = translations[language]; - elements.forEach(function(element) { - var key = element.getAttribute('ts'); - - if (arr.hasOwnProperty(key)) { - element.innerHTML = arr[key]; - } - }); -} - - -const fov = 75; -const aspect = 1; -const near = 0.1; -const far = 5; - -const canvas = document.querySelector('#language-renderer'); -const renderer = new THREE.WebGLRenderer({antialias: false, canvas}); -renderer.setSize( 90,90 ); -renderer.setClearColor( 0xffffff, 0); -const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); -camera.position.z = 1.4; - -const scene = new THREE.Scene(); - -const discardMaterial = new THREE.ShaderMaterial({ - vertexShader:` - void main() { - gl_Position = vec4(1.0); - }`, - fragmentShader: ` - void main() { - gl_FragColor = vec4(1.0); - discard; - } - ` -}); - -var geometry = new THREE.BoxGeometry(1, 1, 1); -var texture = new THREE.TextureLoader(); -var materials = []; -const dutch = texture.load(nldPath); -dutch.magFilter = THREE.NearestFilter; -dutch.minFilter = THREE.NearestFilter; -const english = texture.load(engPath); -english.magFilter = THREE.NearestFilter; -english.minFilter = THREE.NearestFilter; -const russian = texture.load(rusPath); -russian.magFilter = THREE.NearestFilter; -russian.minFilter = THREE.NearestFilter; -materials.push(new THREE.MeshPhongMaterial({map: dutch})); -materials.push(new THREE.MeshPhongMaterial({map: russian})); -materials.push(discardMaterial); -materials.push(discardMaterial); -materials.push(new THREE.MeshPhongMaterial({map: english})); -materials.push(new THREE.MeshPhongMaterial({map: english})); - -var cube = new THREE.Mesh(geometry, materials); - -determineLanguage(); - -scene.add(cube); - - -const ambientLight = new THREE.AmbientLight(0xffffff, 2.8); -scene.add(ambientLight); - -let isDragging = false; -let previousX; -let velocity = 0; -const friction = 0.4; -// Define the possible rotation positions -const snapPositions = [0, Math.PI / 2, Math.PI, Math.PI * 3 / 2]; - -// Store the current snapped position -let currentSnapPosition = 0; - -function startDrag(event) { - isDragging = true; - previousX = event.clientX || event.touches[0].clientX; - canvas.style.cursor = "grabbing"; -} - -function drag(event) { - if (isDragging) { - const currentX = event.clientX || event.touches[0].clientX; - velocity += (currentX - previousX) * 0.05; - previousX = currentX; - } -} - -function endDrag() { - isDragging = false; - canvas.style.cursor = "grab"; - snapCube(); -} - -function snapCube() { - // Normalize the cube's rotation to be within the range [0, 2 * PI) - let rotation = cube.rotation.y % (2 * Math.PI); - if (rotation < -Math.PI/4) { - rotation += 2 * Math.PI; - } else if (rotation > 5.49778718038469) { - rotation -= 2 * Math.PI; - } - - // Calculate the closest snap position - const closestSnapPosition = snapPositions.reduce((prev, curr) => { - return Math.abs(curr - rotation) < Math.abs(prev - rotation) ? curr : prev; - }, snapPositions[0]); - - // Interpolate to the closest snap position - const snapTime = 0.5; // seconds - const snapStart = rotation; - const snapEnd = closestSnapPosition; - const snapStartTime = performance.now(); - - function snapRender(time) { - const t = (time - snapStartTime) / (snapTime * 1000); - cube.rotation.y = snapStart + (snapEnd - snapStart) * t; - if (t < 1) { - requestAnimationFrame(snapRender); - } else { - cube.rotation.y = snapEnd; - currentSnapPosition = snapEnd; - let lang; - switch (snapEnd){ - case 1.5707963267948966: - lang = "ru"; - break; - case 0: - lang = "en"; - break; - case 3.141592653589793: - lang = "en"; - break; - case 4.71238898038469: - lang = "nl"; - break; + function determineLanguage(){ + const userLang = localStorage.getItem("preferredLanguage") || navigator.language || navigator.userLanguage; + switch (userLang) { + case "ru": { + language = "ru"; + cube.rotation.y = 1.5707963267948966; + break; } - if (lang != language) { - setLanguage(lang); - localStorage.setItem("preferredLanguage",language); + case "nl": { + language = "nl"; + cube.rotation.y = 4.71238898038469; } } + if (language != "en") setLanguage(language); } - requestAnimationFrame(snapRender); -} -canvas.addEventListener('mousedown', startDrag); -canvas.addEventListener('touchstart', startDrag); -canvas.addEventListener('mousemove', drag); -canvas.addEventListener('touchmove', drag); -canvas.addEventListener("mouseleave", endDrag); -canvas.addEventListener('mouseup', endDrag); -canvas.addEventListener('touchend', endDrag); + var elements = document.querySelectorAll('[ts]'); -//cube.rotation.x = 0.5; -function render(time) { - renderer.render(scene, camera); + function setLanguage(l) { + language = l; + const arr = translations[language]; + elements.forEach(function(element) { + var key = element.getAttribute('ts'); + + if (arr.hasOwnProperty(key)) { + element.innerHTML = arr[key]; + } + }); + } - velocity *= friction; - cube.rotation.y += velocity; + const fov = 75; + const aspect = 1; + const near = 0.1; + const far = 5; + + const renderer = new THREE.WebGLRenderer({antialias: false, canvas}); + renderer.setSize( 90,90 ); + renderer.setClearColor( 0xffffff, 0); + const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); + camera.position.z = 1.4; + + const scene = new THREE.Scene(); + + const discardMaterial = new THREE.ShaderMaterial({ + vertexShader:` + void main() { + gl_Position = vec4(1.0); + }`, + fragmentShader: ` + void main() { + gl_FragColor = vec4(1.0); + discard; + } + ` + }); + + var geometry = new THREE.BoxGeometry(1, 1, 1); + var texture = new THREE.TextureLoader(); + var materials = []; + const dutch = texture.load(nldPath); + dutch.magFilter = THREE.NearestFilter; + dutch.minFilter = THREE.NearestFilter; + const english = texture.load(engPath); + english.magFilter = THREE.NearestFilter; + english.minFilter = THREE.NearestFilter; + const russian = texture.load(rusPath); + russian.magFilter = THREE.NearestFilter; + russian.minFilter = THREE.NearestFilter; + materials.push(new THREE.MeshPhongMaterial({map: dutch})); + materials.push(new THREE.MeshPhongMaterial({map: russian})); + materials.push(discardMaterial); + materials.push(discardMaterial); + materials.push(new THREE.MeshPhongMaterial({map: english})); + materials.push(new THREE.MeshPhongMaterial({map: english})); + + var cube = new THREE.Mesh(geometry, materials); + + determineLanguage(); + + scene.add(cube); + + + const ambientLight = new THREE.AmbientLight(0xffffff, 2.8); + scene.add(ambientLight); + + let isDragging = false; + let previousX; + let velocity = 0; + const friction = 0.4; + // Define the possible rotation positions + const snapPositions = [0, Math.PI / 2, Math.PI, Math.PI * 3 / 2]; + + // Store the current snapped position + let currentSnapPosition = 0; + + function startDrag(event) { + isDragging = true; + previousX = event.clientX || event.touches[0].clientX; + canvas.style.cursor = "grabbing"; + } + + function drag(event) { + if (isDragging) { + const currentX = event.clientX || event.touches[0].clientX; + velocity += (currentX - previousX) * 0.05; + previousX = currentX; + } + } + + function endDrag() { + isDragging = false; + canvas.style.cursor = "grab"; + snapCube(); + } + + function snapCube() { + // Normalize the cube's rotation to be within the range [0, 2 * PI) + let rotation = cube.rotation.y % (2 * Math.PI); + if (rotation < -Math.PI/4) { + rotation += 2 * Math.PI; + } else if (rotation > 5.49778718038469) { + rotation -= 2 * Math.PI; + } + + // Calculate the closest snap position + const closestSnapPosition = snapPositions.reduce((prev, curr) => { + return Math.abs(curr - rotation) < Math.abs(prev - rotation) ? curr : prev; + }, snapPositions[0]); + + // Interpolate to the closest snap position + const snapTime = 0.5; // seconds + const snapStart = rotation; + const snapEnd = closestSnapPosition; + const snapStartTime = performance.now(); + + function snapRender(time) { + const t = (time - snapStartTime) / (snapTime * 1000); + cube.rotation.y = snapStart + (snapEnd - snapStart) * t; + if (t < 1) { + requestAnimationFrame(snapRender); + } else { + cube.rotation.y = snapEnd; + currentSnapPosition = snapEnd; + let lang; + switch (snapEnd){ + case 1.5707963267948966: + lang = "ru"; + break; + case 0: + lang = "en"; + break; + case 3.141592653589793: + lang = "en"; + break; + case 4.71238898038469: + lang = "nl"; + break; + } + if (lang != language) { + setLanguage(lang); + localStorage.setItem("preferredLanguage",language); + } + } + } + requestAnimationFrame(snapRender); + } + + canvas.addEventListener('mousedown', startDrag); + canvas.addEventListener('touchstart', startDrag); + canvas.addEventListener('mousemove', drag); + canvas.addEventListener('touchmove', drag); + canvas.addEventListener("mouseleave", endDrag); + canvas.addEventListener('mouseup', endDrag); + canvas.addEventListener('touchend', endDrag); + + function render(time) { + renderer.render(scene, camera); + + velocity *= friction; + cube.rotation.y += velocity; + + requestAnimationFrame(render); + } requestAnimationFrame(render); -} -requestAnimationFrame(render); +} \ No newline at end of file