diff --git a/app/assets/images/logop42-intro_three.png b/app/assets/images/logop42-intro_three.png new file mode 100644 index 0000000..add4ed8 Binary files /dev/null and b/app/assets/images/logop42-intro_three.png differ diff --git a/app/assets/images/rogland_clear_night_4k.hdr b/app/assets/images/rogland_clear_night_4k.hdr new file mode 100644 index 0000000..baf4cd5 Binary files /dev/null and b/app/assets/images/rogland_clear_night_4k.hdr differ diff --git a/app/assets/images/satara_night_no_lamps_2k.hdr b/app/assets/images/satara_night_no_lamps_2k.hdr new file mode 100644 index 0000000..8593b28 Binary files /dev/null and b/app/assets/images/satara_night_no_lamps_2k.hdr differ diff --git a/app/assets/sfx/intro.js b/app/assets/sfx/intro.js new file mode 100644 index 0000000..73fb6f1 --- /dev/null +++ b/app/assets/sfx/intro.js @@ -0,0 +1,209 @@ +import * as THREE from 'three' +import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js' +import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js' +import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js' + +// === Scene & Camera === +const scene = new THREE.Scene() + +const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 100) +camera.position.set(0.1, 0.02, 4) +//camera.position.z = 4 + +// === Renderer (transparent) === +const renderer = new THREE.WebGLRenderer({ + antialias: true, + alpha: true, + canvas: document.querySelector('.intro3d') +}) +renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) +renderer.setSize(window.innerWidth, window.innerHeight) +renderer.setClearColor(0x000000, 0) +renderer.outputColorSpace = THREE.SRGBColorSpace + + + +const rgbeLoader = new RGBELoader() +rgbeLoader.load('/app/assets/images/satara_night_no_lamps_2k.hdr', hdrTexture => { + hdrTexture.mapping = THREE.EquirectangularReflectionMapping + scene.environment = hdrTexture + scene.background = hdrTexture +}) + + +// === Load background as a plane that fits the viewport === +const loader = new THREE.TextureLoader() +let plane +let planeDistance = 4.4 + +loader.load('/app/assets/images/logop42-intro_three.png', texture => { + + texture.colorSpace = THREE.SRGBColorSpace + texture.wrapS = THREE.ClampToEdgeWrapping + texture.wrapT = THREE.ClampToEdgeWrapping + texture.minFilter = THREE.LinearFilter + texture.magFilter = THREE.LinearFilter + const imageAspect = texture.image.width / texture.image.height + + // Create plane sized to exactly fill the camera frustum at Z = -planeDistance + function makeOrResizePlane() { + const fovRad = THREE.MathUtils.degToRad(camera.fov) + const viewHeight = 2 * Math.tan(fovRad / 2) * planeDistance + const viewWidth = viewHeight * camera.aspect + + let planeWidth, planeHeight + if (viewWidth / viewHeight > imageAspect) { + planeHeight = viewHeight + planeWidth = planeHeight * imageAspect + } else { + planeWidth = viewWidth + planeHeight = planeWidth / imageAspect + } + + if (!plane) { + const geo = new THREE.PlaneGeometry(planeWidth, planeHeight) + const mat = new THREE.MeshBasicMaterial({ map: texture }) + plane = new THREE.Mesh(geo, mat) + plane.scale.set(1.44, 1.5, 1) + plane.position.z = 0 + plane.renderOrder = 0 + scene.add(plane) + } else { + plane.geometry.dispose() + plane.geometry = new THREE.PlaneGeometry(planeWidth, planeHeight) + } + } + makeOrResizePlane() + onResizeCallbacks.push(makeOrResizePlane) +}) + +const glassMat = new THREE.MeshPhysicalMaterial({ + color: 0xffffff, + metalness: .05, + roughness: 0.05, //0.02, + transmission: 1, //1, // true glass + thickness: 1,//0.6, + ior: 1.45, //1.5, + envMapIntensity: 1.2, + attenuationColor: new THREE.Color(0x88ffcc), + attenuationDistance: 2, +}) + + +// === Lights === +const l1 = new THREE.DirectionalLight(0xffbb33, 1) +l1.position.set(-1, 1.5, 6) +scene.add(l1) + +const l2 = new THREE.DirectionalLight(0xffbb33, 1) +l2.position.set(2, -1.5, 6) +scene.add(l2) + + +const lettersPosScale =[ + { position: { x: -0.98, y: 0.02, z: -1 }, scale: { x: 1, y: 1.12, z: 1 } }, + { position: { x: -0.63, y: -0.04, z: -1.05 }, scale: { x: 1, y: 1.05, z: 1 } }, + { position: { x: -0.28, y: -0.05, z: -1.1 }, scale: { x: 0.9, y: 1.15, z: 1, X: 0.8 } }, + { position: { x: -0.1, y: -0.04, z: -1.15 }, scale: { x: 1, y: 1, z: 1 } }, + { position: { x: 0.12, y: -0.06, z: -1.2 }, scale: { x: 0.65, y: 1, z: 1 } }, + { position: { x: 0.355, y: -0.055, z: -1.25 }, scale: { x: 0.5, y: 0.9, z: 1, Y: 0.9 } }, + { position: { x: 0.53, y: -0.01, z: -1.3 }, scale: { x: 1, y: 0.94, z: 1 } }, + { position: { x: 0.84, y: -0.05, z: -1.35 }, scale: { x: 0.95, y: 1.04, z: 1 } }, + { position: { x: 1.17, y: -0.05, z: -1.4 }, scale: { x: 0.7, y: 1.02, z: 1 } }, +] + + +const glassLetters = [] +const text = 'Project42' + +const fontLoader = new FontLoader() +fontLoader.load('/app/thirdparty/Three/fonts/helvetiker_regular.typeface.json', font => { + const mat = new THREE.MeshPhysicalMaterial({ + metalness: 0.2, + roughness: 0.04, + transmission: 1, + thickness: 0.8, + ior: 1.45, + envMapIntensity: 1.2, + attenuationColor: new THREE.Color(0x88ffcc), + attenuationDistance: 2, + color: 0x88ffcc, + emissive: 0x00CCFF, + emissiveIntensity: 0.05, + }) + + for (let i = 0; i < text.length; i++) { + const char = text[i] + const geo = new TextGeometry(char, { + font, + size: .5, + height: 0.15, + curveSegments: 32, + bevelEnabled: true, + bevelThickness: 0.03, + bevelSize: 0.03, + bevelSegments: 32 + }) + + geo.center() + const mesh = new THREE.Mesh(geo, mat) + mesh.position.set(lettersPosScale[i].position.x, lettersPosScale[i].position.y, lettersPosScale[i].position.z) + mesh.scale.set(lettersPosScale[i].scale.x, lettersPosScale[i].scale.y, lettersPosScale[i].scale.z) + scene.add(mesh) + glassLetters.push(mesh) + } + +}) + + +// Helper: update envMap (hide cube → capture → show cube) +function updateEnvMap() { + const wasVisible = cube.visible + cube.visible = false + cubeCam.update(renderer, scene) + cube.visible = wasVisible + glassMat.envMap = cubeRT.texture + glassMat.needsUpdate = true +} + + + +let t = 0 +let lettersZ=-1 +function animate() { + requestAnimationFrame(animate) + lettersZ += .005 + for(const letter of glassLetters){ + letter.position.z += 0.005 //= lettersZ + } + if(lettersZ>1.5) { + for(const [i, letter] of glassLetters.entries()){ + letter.rotation.y += (i-4)/2000 + letter.position.x += (i-4)/4000 + } + } + if(lettersZ>4.5) { + lettersZ = -1 + for(const [i, letter] of glassLetters.entries()){ + letter.rotation.y = 0 + letter.position.x = lettersPosScale[i].position.x + letter.position.z = lettersPosScale[i].position.z + } + } + + + // refresh envmap if anything moves around glass to update reflections + //if ((t++ % 2) === 0) updateEnvMap() + + renderer.render(scene, camera) +} +animate() + +// === Resize handling === +const onResizeCallbacks = [] +window.addEventListener('resize', () => { + camera.aspect = window.innerWidth / window.innerHeight + camera.updateProjectionMatrix() + renderer.setSize(window.innerWidth, window.innerHeight) + onResizeCallbacks.forEach(fn => fn()) +}) diff --git a/app/assets/styles/intro-old.css b/app/assets/styles/intro-old.css new file mode 100644 index 0000000..cb4b446 --- /dev/null +++ b/app/assets/styles/intro-old.css @@ -0,0 +1,228 @@ +body { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + min-height: 100vh; + background: #161616; + overflow: hidden; + font-family: sans; +} + + +canvas.intro3d{ + position:absolute; + top:0; + left:0; + width:100%; + height:100%; + background:transparent; + pointer-events: none; + z-index:99; +} +.glowing { + position: absolute; + width: 60vw; + height: 100vh; + transform-origin: right; + animation: colorChange 5s linear infinite; + animation: fadeaway 30s forwards; + transform: translateX(-50%); +} +.glowing.lt { + left: 0%; + transform: rotate(-15deg); + top: -15%; +} +.glowing.ct { + left: 50%; +} +.glowing.rt { + left: 50%; + transform: rotate(15deg) +} + + +.glowing:nth-child(even) { + transform-origin: left; +} + +@keyframes colorChange { + 0% { filter: hue-rotate(0deg); } + 100% { filter: hue-rotate(360deg); } +} + +.glowing span { + position: absolute; + top: calc(80px * var(--i)); + left: calc(80px * var(--i)); + bottom: calc(80px * var(--i)); + right: calc(80px * var(--i)); + filter: blur(2px); +} + +.glowing span::before { + content: ""; + position: absolute; + top: 50%; + left: -8px; + width: 10px; + height: 10px; + background: #f00; + border-radius: 50%; +} + +.glowing span:nth-child(3n + 1)::before { + background: rgba(134,255,0,1); + box-shadow: 0 0 20px rgba(134,255,0,1), + 0 0 40px rgba(134,255,0,1), + 0 0 60px rgba(134,255,0,1), + 0 0 80px rgba(134,255,0,1), + 0 0 0 8px rgba(134,255,0,.1); +} + +.glowing span:nth-child(3n + 2)::before { + background: rgba(0,255,183,1); + box-shadow: 0 0 20px rgba(0,255,183,1), + 0 0 40px rgba(0,255,183,1), + 0 0 60px rgba(0,255,183,1), + 0 0 80px rgba(0,255,183,1), + 0 0 0 8px rgba(0,255,183,.1); +} + +.glowing span:nth-child(3n + 3)::before { + background: rgba(0,226,255,1); + box-shadow: 0 0 20px rgba(0,226,255,1), + 0 0 40px rgba(0,226,255,1), + 0 0 60px rgba(0,226,255,1), + 0 0 80px rgba(0,226,255,1), + 0 0 0 8px rgba(0,226,255,.1); +} + +.glowing span:nth-child(3n + 1) { + animation: rotatedots1 15s alternate infinite; +} + +.glowing span:nth-child(3n + 2) { + animation: rotatedots-reverse 9s alternate infinite; +} + +.glowing span:nth-child(3n + 3) { + animation: rotatedots1 15s alternate infinite; +} + +@keyframes fadeaway { + 0% { opacity: 1; } + 15% { opacity: 1; } + 100% { opacity: 0; } +} + +@keyframes rotatedots1 { + 0% { transform: rotate(calc(180deg * var(--i))); scale:20%;} + 25% { transform: rotate(calc(90deg * var(--i))); scale:100%;} + 50% { transform: rotate(calc(0deg * var(--i))); scale:80%;} + 100% { transform: rotate(calc(360deg * var(--i))); scale:10%;} +} + + +@keyframes rotatedots-reverse { + 0% { transform: rotate(calc(135deg * var(--i))); scale:20%;} + 25% { transform: rotate(calc(45deg * var(--i))); scale:100%;} + 50% { transform: rotate(calc(-45deg * var(--i))); scale:80%;} + 100% { transform: rotate(calc(315deg * var(--i))); scale:10%;} +} + + + + +.logointro{ + filter: blur(14px); + opacity: 0; + animation: logoanim 5s ease-out forwards; /* runs once */ + will-change: filter, opacity; + color: #FFF; + position: absolute; + text-shadow: 3px -3px 5px #C5F7FF; +} + +@keyframes logoanim{ + 0% { filter: blur(14px); opacity: 0; transform: scale(0.1) } + 100% { filter: blur(0); opacity: 1; transform: scale(0.7) } +} + +@keyframes startbtnanim{ + 0% { opacity: 0; } + 40% { opacity: 0.8; } + 100% { opacity: 1; } +} + +#startbtn{ + cursor: default; + position: absolute; + bottom: 15vh; + color: aliceblue; + font-style: italic; + font-size: 1.5rem; + border-radius: 100px; + padding: 5px 40px; + background: radial-gradient(#82cc50, #0a8200); + box-shadow: 2px 2px 10px #BAFFEF, -2px -2px 10px #BAFFEF, -2px 0 10px #BAFFEF, 0 -2px 10px #BAFFEF; + animation: startbtnanim 5s ease-out forwards; + z-index: 99; +} + +#startbtn[disabled]{ + filter: brightness(.3); +} + +#login-dialog{ + width: 22rem; + z-index: 99; + border-radius: 1rem; + box-shadow: 2px 2px 10px #BAFFEF, -2px -2px 10px #BAFFEF, -2px 0 10px #BAFFEF, 0 -2px 10px #BAFFEF; + background: radial-gradient(#82cc50, #0a8200); + padding: 2rem 3rem 1rem 3rem; + margin-top: -68vh; + opacity: 0; + visibility: hidden; + transition: opacity 0.5s ease; + font-size: 1.3rem; + transform: perspective(200px) rotateY(0deg) rotateX(6deg) rotateZ(0deg); + transform-style: preserve-3d; +} +#login-dialog.show { + opacity: 1; + visibility: visible; +} +#login-dialog > div.cols2{ + display: grid !important; + grid-gap: 10px; + grid-template-columns: 7rem 15rem; +} +#login-dialog > div{ + margin-bottom: 1rem; +} +#login-dialog input{ + line-height: 2rem; + width: 15rem; + border-radius: 5px; + border: none; + font-size: 1rem; +} +#login-dialog button{ + justify-self: end; + font-size: 1rem; + float: right; +} +#login-dialog div.loginerr{ + background-color: #326A1E; + font-size: 1rem; + color: #FFF; + padding: .1rem .5rem; + border-radius: 5px; + text-align: center; + display:none; +} +#login-dialog div.loginerr.show{ + display:block!important; +} \ No newline at end of file diff --git a/app/assets/styles/intro.css b/app/assets/styles/intro.css index 046bf69..20d1d3f 100644 --- a/app/assets/styles/intro.css +++ b/app/assets/styles/intro.css @@ -4,140 +4,23 @@ body { align-items: center; width: 100%; min-height: 100vh; - background: #000; + background: #161616; overflow: hidden; font-family: sans; } -.glowing { - position: absolute; - width: 60vw; - height: 100vh; - transform-origin: right; - animation: colorChange 5s linear infinite; - animation: fadeaway 30s forwards; - transform: translateX(-50%); -} -.glowing.lt { - left: 0%; - transform: rotate(-15deg); - top: -15%; -} -.glowing.ct { - left: 50%; -} -.glowing.rt { - left: 50%; - transform: rotate(15deg) + +canvas.intro3d{ + position:absolute; + top:0; + left:0; + width:100%; + height:100%; + background:transparent; + pointer-events: none; + z-index:99; } - -.glowing:nth-child(even) { - transform-origin: left; -} - -@keyframes colorChange { - 0% { filter: hue-rotate(0deg); } - 100% { filter: hue-rotate(360deg); } -} - -.glowing span { - position: absolute; - top: calc(80px * var(--i)); - left: calc(80px * var(--i)); - bottom: calc(80px * var(--i)); - right: calc(80px * var(--i)); - filter: blur(2px); -} - -.glowing span::before { - content: ""; - position: absolute; - top: 50%; - left: -8px; - width: 10px; - height: 10px; - background: #f00; - border-radius: 50%; -} - -.glowing span:nth-child(3n + 1)::before { - background: rgba(134,255,0,1); - box-shadow: 0 0 20px rgba(134,255,0,1), - 0 0 40px rgba(134,255,0,1), - 0 0 60px rgba(134,255,0,1), - 0 0 80px rgba(134,255,0,1), - 0 0 0 8px rgba(134,255,0,.1); -} - -.glowing span:nth-child(3n + 2)::before { - background: rgba(0,255,183,1); - box-shadow: 0 0 20px rgba(0,255,183,1), - 0 0 40px rgba(0,255,183,1), - 0 0 60px rgba(0,255,183,1), - 0 0 80px rgba(0,255,183,1), - 0 0 0 8px rgba(0,255,183,.1); -} - -.glowing span:nth-child(3n + 3)::before { - background: rgba(0,226,255,1); - box-shadow: 0 0 20px rgba(0,226,255,1), - 0 0 40px rgba(0,226,255,1), - 0 0 60px rgba(0,226,255,1), - 0 0 80px rgba(0,226,255,1), - 0 0 0 8px rgba(0,226,255,.1); -} - -.glowing span:nth-child(3n + 1) { - animation: rotatedots1 15s alternate infinite; -} - -.glowing span:nth-child(3n + 2) { - animation: rotatedots-reverse 9s alternate infinite; -} - -.glowing span:nth-child(3n + 3) { - animation: rotatedots1 15s alternate infinite; -} - -@keyframes fadeaway { - 0% { opacity: 1; } - 15% { opacity: 1; } - 100% { opacity: 0; } -} - -@keyframes rotatedots1 { - 0% { transform: rotate(calc(180deg * var(--i))); scale:20%;} - 25% { transform: rotate(calc(90deg * var(--i))); scale:100%;} - 50% { transform: rotate(calc(0deg * var(--i))); scale:80%;} - 100% { transform: rotate(calc(360deg * var(--i))); scale:10%;} -} - - -@keyframes rotatedots-reverse { - 0% { transform: rotate(calc(135deg * var(--i))); scale:20%;} - 25% { transform: rotate(calc(45deg * var(--i))); scale:100%;} - 50% { transform: rotate(calc(-45deg * var(--i))); scale:80%;} - 100% { transform: rotate(calc(315deg * var(--i))); scale:10%;} -} - - - - -.logointro{ - filter: blur(14px); - opacity: 0; - animation: logoanim 5s ease-out forwards; /* runs once */ - will-change: filter, opacity; - color: #FFF; - position: absolute; - text-shadow: 3px -3px 5px #C5F7FF; -} - -@keyframes logoanim{ - 0% { filter: blur(14px); opacity: 0; transform: scale(0.1) } - 100% { filter: blur(0); opacity: 1; transform: scale(0.7) } -} @keyframes startbtnanim{ 0% { opacity: 0; } @@ -157,6 +40,7 @@ body { background: radial-gradient(#82cc50, #0a8200); box-shadow: 2px 2px 10px #BAFFEF, -2px -2px 10px #BAFFEF, -2px 0 10px #BAFFEF, 0 -2px 10px #BAFFEF; animation: startbtnanim 5s ease-out forwards; + z-index: 99; } #startbtn[disabled]{ diff --git a/index copy.html b/index copy.html new file mode 100644 index 0000000..ac33201 --- /dev/null +++ b/index copy.html @@ -0,0 +1,48 @@ + + + + + + Project 42 + + + + + + +
+ + + +
+
+ + + +
+
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ +
+ + \ No newline at end of file diff --git a/index.html b/index.html index e308243..85eb8ad 100644 --- a/index.html +++ b/index.html @@ -5,26 +5,21 @@ Project 42 + + - -
- - - -
-
- - - -
-
- - - -
- +