<script type="x-shader/x-vertex" id="vertex">
varying vec3 v_position;
varying vec2 vUv;
uniform float time;
uniform float scroll;
uniform float u_factor;
mat3 rotation3dX(float angle) {
float s = sin(angle);
float c = cos(angle);
return mat3(
1.0, 0.0, 0.0,
0.0, c, s,
0.0, -s, c
);
}
mat3 rotation3dY(float angle) {
float s = sin(angle);
float c = cos(angle);
return mat3(
c, 0.0, -s,
0.0, 1.0, 0.0,
s, 0.0, c
);
}
void main () {
vUv = uv;
vec3 new_position = position;
float wave = 0.0;
wave += 0.10 * sin(time + position.x) + 0.05 * sin(1.0 * time + position.x) + 0.05 * sin(0.25 * time + position.x);
wave += 0.15 * sin(time + position.y) + 0.05 * sin(2.0 * time + position.y) + 0.05 * sin(0.25 * time + position.y);
wave += 0.20 * sin(time + position.z) + 0.05 * sin(0.5 * time + position.z) + 0.05 * sin(0.25 * time + position.z);
new_position *= mix(u_factor, 1.0, wave);
new_position *= rotation3dX(scroll * 0.001);
new_position *= rotation3dY(scroll * 0.002);
gl_Position = projectionMatrix * modelViewMatrix * vec4( new_position, 1.0 );
gl_PointSize = 1.5;
v_position = new_position;
}
</script>
<script type="x-shader/x-fragment" id="fragment">
uniform float time;
uniform float u_opacity;
varying vec3 v_position;
varying vec2 vUv;
vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d )
{
return a + b*cos( 6.28318*(c*t+d) );
}
void main () {
vec3 position = v_position;
vec3 col = palette(vUv.y, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(2.0,1.0,0.0),vec3(0.5,0.20,0.25) );
vec3 color = vec3(0.459,0.141,0.141);
gl_FragColor = vec4(color, 0.5);
}
</script>
<div class="overlay"></div>
<div class="left">
<nav>
<h1>Projects</h1>
<ul>
<li>
<div>
<span>Döse</span>
</div>
</li>
<li>
<div>
<span>Architecture</span>
</div>
</li>
<li>
<div>
<span>Out of space</span>
</div>
</li>
<li>
<div>
<span>Relieve</span>
</div>
</li>
</ul>
</nav>
</div>
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/jsm/controls/OrbitControls.js";
class THREEScene {
constructor(container = document.body) {
this.container = container;
this.setup();
this.camera();
this.addObjects();
this.eventListeners();
this.settings();
this.render();
this.animate();
}
settings() {
this.settings = {
blur: 0,
speed: 0.5,
noiseFreq: 1.0
};
}
setup() {
this.clock = new THREE.Clock();
this.mouse = new THREE.Vector2();
this.scene = new THREE.Scene();
this.renderer = new THREE.WebGLRenderer({
antialias: true
});
this.renderer.setSize(this.viewport.width, this.viewport.height);
this.renderer.setPixelRatio = window.devicePixelRatio;
this.renderer.setClearColor(0xeadcc8, 1);
this.container.appendChild(this.renderer.domElement);
}
camera() {
const FOV = 50;
const NEAR = 0.001;
const FAR = 100;
const ASPECT_RATIO = this.viewport.aspectRatio;
this.camera = new THREE.PerspectiveCamera(FOV, ASPECT_RATIO, NEAR, FAR);
this.camera.position.set(0, 0, 20);
this.camera.aspect = this.viewport.width / this.viewport.height;
this.camera.updateProjectionMatrix();
}
lights() {
}
addObjects() {
this.geometry = new THREE.IcosahedronGeometry(4, 32);
this.material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
u_factor: { value: 0.5 },
u_opacity: { value: 0 }
},
vertexShader: document.getElementById("vertex").textContent,
fragmentShader: document.getElementById("fragment").textContent
});
this.cube = new THREE.Points(this.geometry, this.material);
this.cube.scale.set(0.5, 0.5, 0.5);
this.scene.add(this.cube);
}
render() {
this.camera.lookAt(this.scene.position);
this.renderer.render(this.scene, this.camera);
this.material.uniforms.time.value = this.clock.getElapsedTime();
this.cube.rotation.y += 0.005;
this.cube.rotation.x += 0.003;
requestAnimationFrame(() => {
this.render();
});
}
animate() {
gsap.set(".overlay", { scaleX: 0, transformOrigin: "center right" });
gsap.set("h1", { x: -24 });
const tl = gsap.timeline({
delay: 1
});
tl.to("h1", {
x: 0,
opacity: 1
})
.fromTo(
"li",
{
opacity: 0,
y: 32
},
{
opacity: 1,
y: 0,
stagger: 0.15,
ease: "power2.out"
},
0
)
.to(
".overlay",
{
scaleX: 1,
duration: 2.5,
ease: "expo.inOut"
},
0
)
.set("canvas", {
opacity: 1
})
.to(
this.camera.position,
{
duration: 4,
ease: "power3.inOut",
z: 7,
y: 0,
x: 0
},
1
)
.to(
".overlay",
{
opacity: 0,
duration: 4
},
"-=2.5"
);
const nav = document.querySelector("ul");
nav.addEventListener("mouseenter", () => {
gsap.to(this.material.uniforms.u_factor, {
value: 1.0
});
});
nav.addEventListener("mouseleave", () => {
gsap.to(this.material.uniforms.u_factor, {
value: 0.5
});
});
}
eventListeners() {
window.addEventListener("resize", this.onWindowResize.bind(this));
}
onWindowResize() {
this.camera.aspect = this.viewport.aspectRatio;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.viewport.width, this.viewport.height);
}
get viewport() {
const width = this.container.clientWidth / 2;
const height = this.container.clientHeight;
const aspectRatio = width / height;
this.aspectRatio = aspectRatio;
return {
width,
height,
aspectRatio
};
}
}
const scene = new THREEScene();
View Compiled