summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhongheng Liu <z.liu@outlook.com.gr>2025-01-28 07:59:34 +0200
committerZhongheng Liu <z.liu@outlook.com.gr>2025-01-28 07:59:34 +0200
commite23e642996e00d8138ce9035693b59c282babf69 (patch)
treec3fa115b99fa9bf9fd897760756395682051fd9a
parent8a094040e0f89d76b909d2cb694fbb8661c5025a (diff)
downloadstvnliu.gitlab.io-e23e642996e00d8138ce9035693b59c282babf69.tar.gz
stvnliu.gitlab.io-e23e642996e00d8138ce9035693b59c282babf69.tar.bz2
stvnliu.gitlab.io-e23e642996e00d8138ce9035693b59c282babf69.zip
feat: merge 3d of old sitemerging-3d
-rw-r--r--app/src/App.css72
-rw-r--r--app/src/App.tsx220
-rw-r--r--app/src/Topbar/Topbar.tsx30
-rw-r--r--app/src/index.tsx7
-rw-r--r--app/src/texturemap.jpegbin0 -> 19208 bytes
5 files changed, 250 insertions, 79 deletions
diff --git a/app/src/App.css b/app/src/App.css
index 74b5e05..2fe7db2 100644
--- a/app/src/App.css
+++ b/app/src/App.css
@@ -1,38 +1,44 @@
-.App {
- text-align: center;
+body {
+ overflow-x: hidden;
+ margin: 0px;
+ font-family: monospace;
+ color: white;
}
-
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+canvas {
+ position: fixed;
+ top: 0;
+ left: 0;
}
-
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
-}
-
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
+h1 {
+ font-size: 50px;
+}
+main {
+ width: 100vw;
+ height: 200vw;
+ z-index: 99;
+ position: absolute;
justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
+ text-align: center;
+ pointer-events: none;
+}
+section {
+ background: #777b7e;
+ border-radius: 5px;
+ border-color: white;
+ border-width: 5px;
+ min-height: 50vh;
+ padding: 25px;
+ margin-top: 25vh;
+}
+h2 {
+ font-size: 4vh;
+}
+p {
+ font-size: 2vh;
+}
+.left {
+ margin-right: 55%;
}
-
-.App-link {
- color: #61dafb;
-}
-
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
+.right {
+ margin-left: 55%;
}
diff --git a/app/src/App.tsx b/app/src/App.tsx
index b800706..a73f845 100644
--- a/app/src/App.tsx
+++ b/app/src/App.tsx
@@ -1,44 +1,182 @@
+import { render } from '@testing-library/react';
+import { ReactElement, useEffect, useRef } from 'react';
+import * as THREE from 'three';
+import logo from "./texturemap.jpeg";
+
import './App.css';
+export const ThreeApp = (): ReactElement => {
+ const refContainer = useRef<HTMLDivElement>(null);
+ useEffect(() => {
+ console.log("effect running...")
+ const scene = new THREE.Scene();
+ scene.background = new THREE.Color(0x000000)
+ scene.backgroundIntensity = 0.2
+ const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+ const renderer = new THREE.WebGLRenderer();
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ window.onresize = () => {
+ camera.aspect = window.innerWidth / window.innerHeight
+ camera.updateProjectionMatrix()
+ renderer.setSize(window.innerWidth, window.innerHeight)
+ renderer.render(scene, camera)
+ }
+ // render objects
+ const geometry = new THREE.BoxGeometry(2, 2, 2);
+ const material = new THREE.MeshStandardMaterial({});
+ material.map = new THREE.TextureLoader().load(logo)
+ const cube = new THREE.Mesh(geometry, material);
+ const ambientLight = new THREE.AmbientLight(0xffffff, 1);
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
+ scene.add(directionalLight)
+ scene.add(ambientLight)
+ scene.add(cube);
+ document.body.appendChild(renderer.domElement);
-function App() {
- return (
- <div className="App">
- <div className="aboutme">
- <h1>Zhongheng Liu</h1>
- <p>-- Web developer and GNU/Linux enthusiast.</p>
- <button onClick={() => { window.location.assign("/assets/resume.pdf"); }}>Learn more</button>
- <button onClick={() => { window.location.assign("https://gitlab.com/stvnliu"); }}>My GitLab</button>
- </div>
- <div className="projects">
- <h1>My projects</h1>
- <p>These are mostly hobbyist programming projects</p>
- <hr></hr>
- <h3><a href='https://gitlab.com/stvnliu/proteinpedia-next'>
- proteinpedia-next
- </a>
- </h3>
- <p>A content management platform for displaying and managing informatio
- n of proteins and other chemical</p>
- <hr></hr>
- <h3><a href="/assets/paper.pdf">How can privacy and web inter-connectivity be
- enshrined as core principles in self-hosted online chat applications?
- </a></h3>
- <p>An Edexcel Level 3 Artifact Extended Project Qualification (EPQ) on
- the topic of web chat applications, awarded an A* grade by Edexcel</p>
- <p>You may find the relevant GitLab repositories here:</p>
- <span>
- GitHub repositories for
- <a href="https://github.com/stvnliu/epq-web">web</a> and
- <a href="https://github.com/stvnliu/epq-api">backend API</a>
- </span><br />
- <span>
- GitLab repository for
- <a href="https://gitlab.com/stvnliu/epq-web">web</a> and
- <a href="https://gitlab.com/stvnliu/epq-api">backend API</a>
- </span>
- </div>
- </div>
- );
-}
+ camera.position.z = 5;
+ camera.position.y = 2;
+ camera.lookAt(cube.position)
+
+ // progressive animation through scrolling
+ function lerp(x: number, y: number, a: number): number {
+ return (1 - a) * x + a * y
+ }
+ function scalePercent(start: number, end: number) {
+ return (scrollPercent - start) / (end - start)
+ }
+ const animationKeyframes: { start: number; end: number; func: () => void }[] = []
+
+ animationKeyframes.push({
+ start: 0,
+ end: 15,
+ func: () => {
+ camera.lookAt(cube.position.x - 5, cube.position.y, cube.position.z - 10)
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ cube.position.z = lerp(0, 5, scalePercent(0, 15))
+ cube.position.x = lerp(10, -10, scalePercent(0, 15))
+
+ //console.log(cube.position.z)
+ },
+ })
+ animationKeyframes.push({
+ start: 15,
+ end: 30,
+ func: () => {
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ camera.lookAt(cube.position.x - 5, cube.position.y, cube.position.z - 10)
+ //console.log(cube.rotation.z)
+ },
+ })
+ animationKeyframes.push({
+ start: 30,
+ end: 45,
+ func: () => {
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ camera.position.x = lerp(0, 5, scalePercent(30, 45))
+ camera.position.z = lerp(5, -5, scalePercent(30, 45))
+ camera.lookAt(lerp(cube.position.x - 5, cube.position.x + 10, scalePercent(30, 45)), cube.position.y, lerp(cube.position.z - 10, cube.position.z + 10, scalePercent(30, 45)))
+ //console.log(camera.position.x + " " + camera.position.y)
+ },
+ })
+ animationKeyframes.push({
+ start: 45,
+ end: 60,
+ func: () => {
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ camera.lookAt(cube.position.x + 10, cube.position.y, cube.position.z + 10)
+ //console.log(cube.rotation.z)
+ },
+ })
+ animationKeyframes.push({
+ start: 60,
+ end: 70,
+ func: () => {
+ //auto rotate
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ cube.position.x = lerp(-10, 20, scalePercent(60, 70))
+ camera.lookAt(lerp(cube.position.x + 10, cube.position.x - 10, scalePercent(60, 70)), cube.position.y, cube.position.z + 10)
+ },
+ })
+ animationKeyframes.push({
+ start: 70,
+ end: 80,
+ func: () => {
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ camera.lookAt(cube.position.x - 10, cube.position.y, cube.position.z + 10)
+ },
+ })
+ animationKeyframes.push({
+ start: 80,
+ end: 101,
+ func: () => {
+ cube.rotation.x += 0.01
+ cube.rotation.y += 0.01
+ cube.position.x = lerp(20, -5, scalePercent(80, 100))
+ camera.lookAt(lerp(cube.position.x - 10, cube.position.x + 10, scalePercent(80, 101)), cube.position.y, cube.position.z + 10)
+ },
+ })
+
+ function playScrollAnimations() {
+ animationKeyframes.forEach((a) => {
+ if (scrollPercent >= a.start && scrollPercent < a.end) {
+ a.func()
+ }
+ })
+ }
-export default App;
+ let scrollPercent = 0
+ window.onscroll = () => {
+ scrollPercent =
+ ((document.documentElement.scrollTop || document.body.scrollTop) /
+ ((document.documentElement.scrollHeight ||
+ document.body.scrollHeight) -
+ document.documentElement.clientHeight)) *
+ 100;
+ }
+
+ function animate() {
+ requestAnimationFrame(animate);
+ playScrollAnimations()
+ renderer.render(scene, camera);
+ }
+ window.scrollTo({ top: 0, behavior: 'smooth' })
+ animate();
+ }, [])
+
+ return (
+ <main ref={refContainer}>
+ <h1>Website Under Construction</h1>
+ <section className='left'>
+ <h2>Steven Liu</h2>
+ <p>I write sometimes-functional code in JavaScript React, Java, and a bit of Python.</p>
+ </section>
+ <section className='right'>
+ <h2>Changing Objects Position</h2>
+ <p>The cubes position is now changing</p>
+ </section>
+
+ <section className='left'>
+ <h2>Changing Objects Rotation</h2>
+ <p>The cubes rotation is now changing</p>
+ </section>
+
+ <section className='right'>
+ <h2>Changing Camera Position</h2>
+ <p>The camera position is now changing</p>
+ </section>
+
+ <section className='left'>
+ <h2>You are at the bottom</h2>
+ <p>The cube will now be auto rotating</p>
+ <p>
+ Now you can scroll back to the top to reverse the animation
+ </p>
+ </section>
+ </main>
+ )
+}
diff --git a/app/src/Topbar/Topbar.tsx b/app/src/Topbar/Topbar.tsx
new file mode 100644
index 0000000..14ef0ec
--- /dev/null
+++ b/app/src/Topbar/Topbar.tsx
@@ -0,0 +1,30 @@
+export const Topbar = (): React.ReactElement => {
+ return (<nav className="navbar navbar-expand-sm navbar-light bg-light">
+ <a className="navbar-brand" href="#">Navbar</a>
+ <button className="navbar-toggler d-lg-none" type="button" data-toggle="collapse" data-target="#collapsibleNavId" aria-controls="collapsibleNavId"
+ aria-expanded="false" aria-label="Toggle navigation">
+ <span className="navbar-toggler-icon"></span>
+ </button>
+ <div className="collapse navbar-collapse" id="collapsibleNavId">
+ <ul className="navbar-nav mr-auto mt-2 mt-lg-0">
+ <li className="nav-item active">
+ <a className="nav-link" href="#">Home <span className="sr-only">(current)</span></a>
+ </li>
+ <li className="nav-item">
+ <a className="nav-link" href="#">Link</a>
+ </li>
+ <li className="nav-item dropdown">
+ <a className="nav-link dropdown-toggle" href="#" id="dropdownId" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
+ <div className="dropdown-menu" aria-labelledby="dropdownId">
+ <a className="dropdown-item" href="#">Action 1</a>
+ <a className="dropdown-item" href="#">Action 2</a>
+ </div>
+ </li>
+ </ul>
+ <form className="form-inline my-2 my-lg-0">
+ <input className="form-control mr-sm-2" type="text" placeholder="Search" />
+ <button className="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
+ </form>
+ </div>
+ </nav>)
+}; \ No newline at end of file
diff --git a/app/src/index.tsx b/app/src/index.tsx
index 032464f..6a6998b 100644
--- a/app/src/index.tsx
+++ b/app/src/index.tsx
@@ -1,16 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
import reportWebVitals from './reportWebVitals';
+import { ThreeApp } from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
- <React.StrictMode>
- <App />
- </React.StrictMode>
+ <ThreeApp />
);
// If you want to start measuring performance in your app, pass a function
diff --git a/app/src/texturemap.jpeg b/app/src/texturemap.jpeg
new file mode 100644
index 0000000..c9e65e0
--- /dev/null
+++ b/app/src/texturemap.jpeg
Binary files differ