Compare commits
6 Commits
8daec5666e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4978670fc4 | ||
|
|
0c91356320 | ||
|
|
c3075328a3 | ||
|
|
6e69ae9cfe | ||
|
|
c861603b06 | ||
|
|
c032578bc6 |
3
.vscode/extensions.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>th</title>
|
||||
|
||||
BIN
public/models/room-draco.glb
Normal file
BIN
public/vids/Aus_dem_wasser.mp4
Normal file
BIN
public/vids/TH-Video_Abgabe.mp4
Executable file
BIN
public/vids/googleOR.mp4
Normal file
|
Before Width: | Height: | Size: 8.4 MiB After Width: | Height: | Size: 7.9 MiB |
BIN
public/vids/skitom.mp4
Executable file
|
Before Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 14 MiB |
|
Before Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 380 KiB |
BIN
src/assets/fonts/IBMPlexMono-Medium.woff2
Normal file
@@ -101,78 +101,59 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="text">
|
||||
<h2>Here is some content</h2>
|
||||
<h2>Was ist Kunst?</h2>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
Nach Schelling ist die Kunst das Erzeugnis oder die Folge jener
|
||||
Weltanschauung, nach der das Subjekt sich in sein Objekt verwandelt oder
|
||||
das Objekt selbst 45 zum Subjekt wird. Die Schönheit ist die Darstellung
|
||||
des Unendli- chen im Endlichen. Und der Grundcharakter eines Kunstwerkes
|
||||
ist die bewußtlose Unendlichkeit. Die Kunst ist die Vereinigung des
|
||||
Subjektiven mit dem Objektiven, – der Natur mit der Vernunft, der
|
||||
Bewußtlosigkeit mit dem Bewußten. Und deshalb ist die Kunst das höchste
|
||||
Mittel der Erkenntnis. Die Schönheit ist die Betrachtung der Dinge an
|
||||
sich, wie sie in Urbildern sind. Das Schöne erzeugt nicht der Künstler
|
||||
vermöge seines Wissens oder seines Willens, sondern die Idee der
|
||||
Schönheit selbst schafft in ihm. (Schaßler)
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
In der Welt erblicken wir nur die Entartung der Grundidee, die Kunst
|
||||
jedoch kann ver- möge der Phantasie sich bis zur Höhe der Grundidee
|
||||
erheben. Und deshalb ist die Kunst das Ebenbild der Schöpfung
|
||||
(Schaßler).
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
Nach einem anderen Anhänger Schellings, Krause (1781–1832), ist die
|
||||
wahre reale Schönheit die Erzeugung der Idee in der indivi- duellen
|
||||
Form; die Kunst ist aber die Verwirklichung der Schönheit in der Sphäre
|
||||
des freien menschlichen Geistes. Die höchste Stufe der Kunst ist die
|
||||
Kunst des Lebens, die ihre Thätigkeit auf die Verschö- nerung des Lebens
|
||||
richtet, damit dies ein schön belebter Wohnort für die selber in
|
||||
Schönheit vollendete Menschheit sei. (Ebd.)
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
Nach Hegel (1770–1831) offenbart sich Gott in Natur und Kunst unter der
|
||||
Form der Schönheit. Gott äußert sich auf zweierlei Weise: in dem Objekt
|
||||
und in dem Subjekt, – in der Natur und im Geiste. Die Schönheit ist
|
||||
jedoch das Durch- scheinen der Idee durch den Stoff. Das wahrhaft Schöne
|
||||
ist nur der Geist und alles das, was dem Geiste teilhaftig ist. Deshalb
|
||||
ist die Schönheit der Natur nur der Schein der dem Geiste eigenen Schön-
|
||||
heit: das Schöne hat nur als Geistiges wahrhaften Gehalt. Aber das
|
||||
Geistige muß in der sinnlichen Form erscheinen. Die sinnliche Äu- ßerung
|
||||
des Geistes jedoch ist nur der Schein. Und dieser Schein ist die
|
||||
eigentliche Wirklichkeit des Schönen. Sodaß die Kunst die 46
|
||||
Verwirklichung dieses Scheines der Idee und zugleich mit der Reli- gion
|
||||
und Philosophie das Mittel ist, die tiefsten Interessen der Men- schen
|
||||
und die umfassendsten Wahrheiten des Geistes zum Bewußt- sein zu bringen
|
||||
und auszusprechen. Wahrheit und Schönheit sind nach Hegel ein und
|
||||
dasselbe: der Unterschied besteht nur darin, daß die Wahrheit die Idee
|
||||
ist, wie diese an sich und dem allgemeinen Prinzip nach ist und als
|
||||
solches gedacht wird. Die Idee jedoch, die äußerlich existiert, wird für
|
||||
das Bewußtsein nicht blos wahr, son- dern auch schön. Das Schöne ist das
|
||||
Scheinen der Idee
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
--- Was ist Kunst?, Leo N. Tolstoi, Aus dem Russischen von Michail
|
||||
Feofanov (1902) ---
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -261,6 +242,7 @@ p {
|
||||
}
|
||||
|
||||
.text {
|
||||
font-family: Courier New;
|
||||
padding: 2rem 5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
196
src/components/sections/IntroductionSection.vue
Normal file
@@ -0,0 +1,196 @@
|
||||
<script setup lang="js">
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import SplitText from "gsap/SplitText";
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger, SplitText);
|
||||
|
||||
const section = ref(null);
|
||||
|
||||
let ctx;
|
||||
let split;
|
||||
let animation;
|
||||
const date = ref("--:--");
|
||||
const time = ref("");
|
||||
let interval;
|
||||
|
||||
function createTween() {
|
||||
animation?.kill();
|
||||
split = SplitText.create(".text", {
|
||||
type: "words",
|
||||
});
|
||||
|
||||
animation = gsap.from(split.words, {
|
||||
y: 30,
|
||||
opacity: 0,
|
||||
duration: 0.9,
|
||||
ease: "power2.out",
|
||||
stagger: 0.05,
|
||||
|
||||
scrollTrigger: {
|
||||
trigger: section.value,
|
||||
start: "top 10%",
|
||||
toggleActions: "play none none none",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
ctx = gsap.context(() => {
|
||||
createTween();
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
}, section.value);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
ScrollTrigger.refresh();
|
||||
});
|
||||
getTimeDate();
|
||||
interval = setInterval(() => {
|
||||
getTimeDate();
|
||||
}, 1000);
|
||||
console.log(date.value);
|
||||
});
|
||||
|
||||
function handleResize() {
|
||||
split && split.revert();
|
||||
split = SplitText.create(".text", {
|
||||
type: "words",
|
||||
});
|
||||
ScrollTrigger.refresh();
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
ctx?.revert();
|
||||
clearInterval(interval);
|
||||
});
|
||||
|
||||
function getTimeDate() {
|
||||
const now = new Date();
|
||||
|
||||
time.value = now.toLocaleTimeString("de-DE", {
|
||||
timeZone: "Europe/Berlin",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
|
||||
date.value = now.toLocaleDateString("de-DE", {
|
||||
timeZone: "Europe/Berlin",
|
||||
weekday: "long",
|
||||
day: "2-digit",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="poster">
|
||||
<div class="b-one"></div>
|
||||
<div class="b-two"></div>
|
||||
<div class="b-three"></div>
|
||||
<div class="b-four"></div>
|
||||
<div class="b-five"></div>
|
||||
|
||||
<div class="textblock text">
|
||||
<h4 class="textblock__subheader text">Tom Alexander Herpel</h4>
|
||||
|
||||
<h1 class="textblock__header text">
|
||||
Welcome to my page. <br />
|
||||
This space is currently under construction.
|
||||
</h1>
|
||||
|
||||
<h4 class="textblock__subheader text">
|
||||
Here you’ll find creative projects and ideas that inspire me at the
|
||||
moment.
|
||||
</h4>
|
||||
|
||||
<p class="textblock__caption">Oldenburg, Germany <br /></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.poster {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(33, 1fr);
|
||||
grid-template-rows: repeat(16, 1fr);
|
||||
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
|
||||
background: var(--bg-clr);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
/* Schwarze Blöcke */
|
||||
.b-one,
|
||||
.b-two,
|
||||
.b-three,
|
||||
.b-four,
|
||||
.b-five {
|
||||
background: var(--black-clr);
|
||||
}
|
||||
|
||||
.b-one {
|
||||
grid-column: 1 / 4;
|
||||
grid-row: 11 / 15;
|
||||
}
|
||||
|
||||
.b-two {
|
||||
grid-column: 4 / 12;
|
||||
grid-row: 6 / 8;
|
||||
}
|
||||
|
||||
.b-three {
|
||||
grid-column: 16 / 18;
|
||||
grid-row: 8 / 11;
|
||||
}
|
||||
|
||||
.b-four {
|
||||
grid-column: 11 / 30;
|
||||
grid-row: 15 / 17;
|
||||
}
|
||||
|
||||
.b-five {
|
||||
grid-column: 30 / 34;
|
||||
grid-row: 1 / 11;
|
||||
}
|
||||
|
||||
/* Textbereich */
|
||||
.textblock {
|
||||
grid-column: 6 / 28;
|
||||
grid-row-end: 14;
|
||||
|
||||
align-self: center;
|
||||
color: var(--black-clr);
|
||||
}
|
||||
|
||||
.textblock__subheader {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 1rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.textblock__header {
|
||||
font-size: 4rem;
|
||||
line-height: 1;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2rem;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.textblock__caption {
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.7;
|
||||
max-width: 600px;
|
||||
}
|
||||
.text {
|
||||
font-family: Courier New;
|
||||
font-size: clamp(1.5rem, 3vw, 5rem);
|
||||
}
|
||||
</style>
|
||||
252
src/components/sections/MonitorModel.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<script setup lang="js">
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import * as THREE from "three";
|
||||
import gsap from "gsap";
|
||||
import ScrollTrigger from "gsap/ScrollTrigger";
|
||||
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||
|
||||
import surf_video from "/vids/Aus_dem_wasser.mp4";
|
||||
import ski_video from "/vids/ski.mp4";
|
||||
|
||||
const canvasRef = ref(null);
|
||||
let renderer, scene, camera, model, controls, gsapCtx;
|
||||
let screen1, screen3, screen4;
|
||||
|
||||
const video_surf = document.createElement("video");
|
||||
const video_ski = document.createElement("video");
|
||||
|
||||
video_surf.src = surf_video;
|
||||
video_surf.loop = true;
|
||||
video_surf.muted = true;
|
||||
|
||||
video_ski.src = ski_video;
|
||||
video_ski.loop = true;
|
||||
video_ski.muted = true;
|
||||
|
||||
function initThree(canvas) {
|
||||
renderer = new THREE.WebGLRenderer({
|
||||
canvas,
|
||||
antialias: true,
|
||||
alpha: true,
|
||||
});
|
||||
|
||||
renderer.setPixelRatio(1); //TODO
|
||||
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
scene = new THREE.Scene();
|
||||
camera = new THREE.PerspectiveCamera(45, 2, 0.1, 100);
|
||||
|
||||
const light = new THREE.DirectionalLight(0xffe0b0, 0.9);
|
||||
light.position.set(-1, 4, 5);
|
||||
scene.add(light);
|
||||
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
controls.enabled = false;
|
||||
|
||||
// controls.minDistance = 5;
|
||||
// controls.maxDistance = 5;
|
||||
controls.maxPolarAngle = Math.PI / 2;
|
||||
controls.minAzimuthAngle = -Math.PI / 2;
|
||||
controls.maxAzimuthAngle = Math.PI / 2;
|
||||
|
||||
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
|
||||
|
||||
loadModel();
|
||||
|
||||
gsap.ticker.add(render);
|
||||
}
|
||||
|
||||
function loadModel() {
|
||||
if (model) {
|
||||
scene.remove(model);
|
||||
}
|
||||
let modelUrl = "/models/room-draco.glb";
|
||||
let dracoPath = "/draco/";
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(dracoPath);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
modelUrl,
|
||||
(gltf) => {
|
||||
model = gltf.scene;
|
||||
|
||||
const box = new THREE.Box3().setFromObject(model);
|
||||
const center = box.getCenter(new THREE.Vector3());
|
||||
const size = box.getSize(new THREE.Vector3());
|
||||
const texture_surf_video = new THREE.VideoTexture(video_surf);
|
||||
const texure_ski = new THREE.VideoTexture(video_ski);
|
||||
screen1 = model.getObjectByName("fernseher1Bild");
|
||||
screen4 = model.getObjectByName("fernseher4Bild");
|
||||
screen3 = model.getObjectByName("fernseher3Bild");
|
||||
|
||||
texture_surf_video.flipY = false;
|
||||
texure_ski.flipY = false;
|
||||
texure_ski.offset.set(-0.3, -0.2);
|
||||
|
||||
screen1.material = new THREE.MeshBasicMaterial({
|
||||
map: texture_surf_video,
|
||||
});
|
||||
screen4.material = new THREE.MeshBasicMaterial({
|
||||
map: texure_ski,
|
||||
});
|
||||
screen3.material = new THREE.MeshBasicMaterial({
|
||||
map: texure_ski,
|
||||
});
|
||||
const maxSize = Math.max(size.x, size.y, size.z);
|
||||
const distance = maxSize * 2;
|
||||
|
||||
camera.position.set(center.x, center.y, center.z + distance);
|
||||
controls.target.copy(center);
|
||||
controls.update();
|
||||
|
||||
console.log(scene);
|
||||
model.position.set(0, 0, 0);
|
||||
scene.add(model);
|
||||
gsapCtx = scrollCamreaGsap(center);
|
||||
|
||||
document.title = "Model geladen";
|
||||
},
|
||||
(progress) => {
|
||||
const percent = ((progress.loaded / progress.total) * 100).toFixed(1);
|
||||
console.log(`Loading: ${percent}%`);
|
||||
document.title = `${percent}%`;
|
||||
},
|
||||
(error) => {
|
||||
console.error("Fehler beim Laden des Modells:", error);
|
||||
document.title = "Fehler beim Laden!";
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function render() {
|
||||
if (!renderer) return;
|
||||
|
||||
controls.update();
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
function onResize() {
|
||||
if (!renderer || !canvasRef.value) return;
|
||||
const r = canvasRef.value.getBoundingClientRect();
|
||||
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||
|
||||
const width = canvasRef.value.clientWidth;
|
||||
const height = canvasRef.value.clientHeight;
|
||||
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
renderer.setSize(width, height, false);
|
||||
|
||||
camera.aspect = (r.width || 1) / (r.height || 1);
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
function scrollCamreaGsap(center) {
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
gsap.to(camera.position, {
|
||||
z: center.z + 5,
|
||||
ease: "none",
|
||||
scrollTrigger: {
|
||||
trigger: canvasRef.value,
|
||||
start: "top top",
|
||||
end: "+=2000",
|
||||
scrub: 1,
|
||||
pin: true,
|
||||
anticipatePin: 1,
|
||||
onUpdate: (self) => {
|
||||
if (self.progress >= 0.8) {
|
||||
controls.enabled = true;
|
||||
|
||||
controls.enableRotate = true;
|
||||
controls.enableZoom = false;
|
||||
controls.enablePan = false;
|
||||
|
||||
screen1.visible = true;
|
||||
screen3.visible = true;
|
||||
screen4.visible = true;
|
||||
setVideoActive(true);
|
||||
} else {
|
||||
controls.enabled = false;
|
||||
screen1.visible = false;
|
||||
screen3.visible = false;
|
||||
screen4.visible = false;
|
||||
setVideoActive(false);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
}, canvasRef.value);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
function setVideoActive(active) {
|
||||
if (active) {
|
||||
video_surf.play();
|
||||
video_ski.play();
|
||||
} else {
|
||||
video_surf.pause();
|
||||
video_ski.pause();
|
||||
}
|
||||
}
|
||||
|
||||
const resizeObserver = new ResizeObserver(onResize);
|
||||
|
||||
onMounted(() => {
|
||||
initThree(canvasRef.value);
|
||||
onResize();
|
||||
|
||||
resizeObserver.observe(canvasRef.value);
|
||||
window.addEventListener("resize", onResize);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
gsap.ticker.remove(render);
|
||||
window.removeEventListener("resize", onResize);
|
||||
resizeObserver.disconnect();
|
||||
renderer?.dispose();
|
||||
gsapCtx?.revert();
|
||||
ScrollTrigger.getAll().forEach((t) => t.kill());
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<!-- <div class="spacer"></div> -->
|
||||
|
||||
<canvas class="canvas" ref="canvasRef"></canvas>
|
||||
</div>
|
||||
<div class="scroll-buffer"></div>
|
||||
<div class="spacer"></div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.spacer {
|
||||
width: 100%;
|
||||
height: 200vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.scroll-buffer {
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
@@ -48,45 +48,54 @@ const createTimeline = () => {
|
||||
|
||||
onMounted(() => {
|
||||
createTimeline();
|
||||
|
||||
window.addEventListener("resize", createTween);
|
||||
window.addEventListener("resize", createTimeline);
|
||||
ScrollTrigger.refresh();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
flipCtx?.revert();
|
||||
window.removeEventListener("resize", createTween);
|
||||
gsap.ticker.remove(updateMorph);
|
||||
window.removeEventListener("resize", createTimeline);
|
||||
});
|
||||
|
||||
window.addEventListener("resize", createTimeline);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<div class="container initial">
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
|
||||
<div class="container second">
|
||||
<div class="experience-text">
|
||||
<h2>Do you want to see where I used to study?</h2>
|
||||
<section class="text-section">
|
||||
<div class="main">
|
||||
<div class="container initial">
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
<div class="marker"></div>
|
||||
<router-link to="/experience">
|
||||
<button class="btn second-btn">Zur Experience</button>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="container third">
|
||||
<div class="experience-text">
|
||||
<h2>Here is the final step!</h2>
|
||||
<div class="container second">
|
||||
<div class="experience-text">
|
||||
<h2>Do you want to see where I used to study?</h2>
|
||||
</div>
|
||||
<div class="marker"></div>
|
||||
<router-link to="/experience">
|
||||
<button class="btn second-btn">Zur Experience</button>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="container third">
|
||||
<div class="experience-text">
|
||||
<h2>Spotify recommendation project</h2>
|
||||
</div>
|
||||
<div class="marker"></div>
|
||||
<router-link to="/recommSpotify">
|
||||
<button class="btn third-btn">Zur recommSpotify</button>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="container fourth">
|
||||
<div class="experience-text">
|
||||
<h2>Here is the final step!</h2>
|
||||
</div>
|
||||
<div class="marker"></div>
|
||||
<button class="btn fourth-btn">Next</button>
|
||||
</div>
|
||||
<div class="marker"></div>
|
||||
<button class="btn third-btn">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spacer final"></div>
|
||||
<div class="spacer final"></div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -228,4 +237,14 @@ body {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.fourth {
|
||||
left: 10%;
|
||||
top: 750%;
|
||||
}
|
||||
|
||||
.fourth .marker {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script setup>
|
||||
import { onMounted, onUnmounted } from "vue";
|
||||
import { onMounted, onUnmounted, ref, nextTick } from "vue";
|
||||
|
||||
import MonitorModel from "/src/components/sections/MonitorModel.vue";
|
||||
|
||||
import gsap from "gsap";
|
||||
import ScrollTrigger from "gsap/ScrollTrigger";
|
||||
|
||||
@@ -9,9 +12,11 @@ import Lenis from "lenis";
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
let ctx;
|
||||
let ctx, lenis;
|
||||
const childRef = ref(null);
|
||||
const parallaxRef = ref(null);
|
||||
|
||||
function initParallax() {
|
||||
function initParallax(triggerElement) {
|
||||
const layers = [
|
||||
{ layer: "1", yPercent: 70 },
|
||||
{ layer: "2", yPercent: 50 },
|
||||
@@ -19,8 +24,6 @@ function initParallax() {
|
||||
{ layer: "4", yPercent: 10 },
|
||||
];
|
||||
|
||||
const triggerElement = document.querySelector(".parallax");
|
||||
|
||||
const tl = gsap.timeline({
|
||||
scrollTrigger: {
|
||||
trigger: triggerElement,
|
||||
@@ -43,6 +46,17 @@ function initParallax() {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function initChild() {
|
||||
gsap.to(childRef.value, {
|
||||
scrollTrigger: {
|
||||
trigger: childRef.value,
|
||||
start: "top center",
|
||||
},
|
||||
scale,
|
||||
});
|
||||
}
|
||||
|
||||
function initLenis() {
|
||||
lenis = new Lenis({
|
||||
duration: 1.1,
|
||||
@@ -58,20 +72,23 @@ function initLenis() {
|
||||
|
||||
gsap.ticker.lagSmoothing(0);
|
||||
}
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
|
||||
ctx = gsap.context(() => {
|
||||
initParallax();
|
||||
initParallax(parallaxRef.value);
|
||||
// initChild();
|
||||
initLenis();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
ctx?.revert();
|
||||
|
||||
lenis?.destroy();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="parallax">
|
||||
<div ref="parallaxRef" class="parallax">
|
||||
<section class="parallax__header">
|
||||
<div class="parallax__visuals">
|
||||
<div class="parallax__layers">
|
||||
@@ -88,7 +105,7 @@ onUnmounted(() => {
|
||||
/>
|
||||
|
||||
<div data-parallax-layer="3" class="parallax__layer-title">
|
||||
<h2 class="parallax__title">WELCOM</h2>
|
||||
<h2 class="parallax__title">TOM HERPEL</h2>
|
||||
</div>
|
||||
|
||||
<img data-parallax-layer="4" class="parallax__layer-img" />
|
||||
@@ -98,7 +115,11 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="parallax__content"></section>
|
||||
<section class="parallax__content">
|
||||
<!-- <div ref="childRef" class="model__wrapper">
|
||||
<MonitorModel />
|
||||
</div> -->
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
@@ -146,7 +167,7 @@ onUnmounted(() => {
|
||||
.parallax__content {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100svh;
|
||||
min-height: 50svh;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
@@ -208,6 +229,7 @@ onUnmounted(() => {
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
/* color: #e84b3d; 633a34 */
|
||||
}
|
||||
|
||||
.parallax__radial-gradient {
|
||||
@@ -244,6 +266,7 @@ onUnmounted(() => {
|
||||
top: -17.5%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "ArtDystopia";
|
||||
src: url("/src/assets/fonts/Art_Dystopia.woff2") format("opentype");
|
||||
|
||||
@@ -5,7 +5,7 @@ import ExperienceView from '../views/ExperienceView.vue'
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{ path: '/', component: HomeView },
|
||||
{ path: '/experience',
|
||||
{ path: '/recommSpotify',
|
||||
component: ExperienceView,
|
||||
props: { modelUrl: '/models/door_room_firstVersion_materials-draco.glb', dracoPath: '/draco/' } }
|
||||
]
|
||||
|
||||
@@ -119,7 +119,7 @@ onUnmounted(() => {
|
||||
dispose();
|
||||
});
|
||||
|
||||
function loadModel(url) {
|
||||
function loadModel() {
|
||||
if (model) {
|
||||
scene.remove(model);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import { onMounted, nextTick } from "vue";
|
||||
import gsap from "gsap";
|
||||
import ScrollTrigger from "gsap/ScrollTrigger";
|
||||
import ScrollSmoother from "gsap/ScrollSmoother";
|
||||
import MonitorModel from "../components/sections/MonitorModel.vue";
|
||||
import IntroductionSection from "../components/sections/IntroductionSection.vue";
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
|
||||
|
||||
@@ -30,6 +32,8 @@ onMounted(async () => {
|
||||
<div id="smooth-wrapper">
|
||||
<div id="smooth-content">
|
||||
<WelcomeSection id="welcome" />
|
||||
<IntroductionSection id="welcome" />
|
||||
<MonitorModel id="model" />
|
||||
<!-- <HeroSection id="hero" /> -->
|
||||
<ImageSection id="image" />
|
||||
<TextSection id="text" />
|
||||
|
||||