D:\code_gitee\abigail-bloom-portolio-bokoko33\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Abigail Bloom</title>
</head>
<body class="light-theme">
<div class="experience">
<canvas class="experience-canvas"></canvas>
</div>
<!-- Preloader -->
<div class="preloader">
<div class="preloader-wrapper">
<div class="loading">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
</div>
</div>
</div>
<div class="page" asscroll-container>
<div class="toggle-bar">
<div class="sun-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path fill="currentColor" d="M12 5Q11.575 5 11.288 4.712Q11 4.425 11 4V2Q11 1.575 11.288 1.287Q11.575 1 12 1Q12.425 1 12.713 1.287Q13 1.575 13 2V4Q13 4.425 12.713 4.712Q12.425 5 12 5ZM16.95 7.05Q16.675 6.775 16.675 6.362Q16.675 5.95 16.95 5.65L18.35 4.225Q18.65 3.925 19.062 3.925Q19.475 3.925 19.775 4.225Q20.05 4.5 20.05 4.925Q20.05 5.35 19.775 5.625L18.35 7.05Q18.075 7.325 17.65 7.325Q17.225 7.325 16.95 7.05ZM20 13Q19.575 13 19.288 12.712Q19 12.425 19 12Q19 11.575 19.288 11.287Q19.575 11 20 11H22Q22.425 11 22.712 11.287Q23 11.575 23 12Q23 12.425 22.712 12.712Q22.425 13 22 13ZM12 23Q11.575 23 11.288 22.712Q11 22.425 11 22V20Q11 19.575 11.288 19.288Q11.575 19 12 19Q12.425 19 12.713 19.288Q13 19.575 13 20V22Q13 22.425 12.713 22.712Q12.425 23 12 23ZM5.65 7.05 4.225 5.65Q3.925 5.35 3.925 4.925Q3.925 4.5 4.225 4.225Q4.5 3.95 4.925 3.95Q5.35 3.95 5.625 4.225L7.05 5.65Q7.325 5.925 7.325 6.35Q7.325 6.775 7.05 7.05Q6.75 7.325 6.35 7.325Q5.95 7.325 5.65 7.05ZM18.35 19.775 16.95 18.35Q16.675 18.05 16.675 17.638Q16.675 17.225 16.95 16.95Q17.225 16.675 17.638 16.675Q18.05 16.675 18.35 16.95L19.775 18.35Q20.075 18.625 20.062 19.05Q20.05 19.475 19.775 19.775Q19.475 20.075 19.05 20.075Q18.625 20.075 18.35 19.775ZM2 13Q1.575 13 1.288 12.712Q1 12.425 1 12Q1 11.575 1.288 11.287Q1.575 11 2 11H4Q4.425 11 4.713 11.287Q5 11.575 5 12Q5 12.425 4.713 12.712Q4.425 13 4 13ZM4.225 19.775Q3.95 19.5 3.95 19.075Q3.95 18.65 4.225 18.375L5.65 16.95Q5.925 16.675 6.338 16.675Q6.75 16.675 7.05 16.95Q7.35 17.25 7.35 17.663Q7.35 18.075 7.05 18.375L5.65 19.775Q5.35 20.075 4.925 20.075Q4.5 20.075 4.225 19.775ZM12 18Q9.5 18 7.75 16.25Q6 14.5 6 12Q6 9.5 7.75 7.75Q9.5 6 12 6Q14.5 6 16.25 7.75Q18 9.5 18 12Q18 14.5 16.25 16.25Q14.5 18 12 18ZM12 16Q13.65 16 14.825 14.825Q16 13.65 16 12Q16 10.35 14.825 9.175Q13.65 8 12 8Q10.35 8 9.175 9.175Q8 10.35 8 12Q8 13.65 9.175 14.825Q10.35 16 12 16Z"/></svg>
</div>
<button class="toggle-button">
<div class="toggle-circle"></div>
</button>
<div class="moon-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path fill="currentColor" d="M12 21Q8.25 21 5.625 18.375Q3 15.75 3 12Q3 8.25 5.625 5.625Q8.25 3 12 3Q12.35 3 12.688 3.025Q13.025 3.05 13.35 3.1Q12.325 3.825 11.713 4.987Q11.1 6.15 11.1 7.5Q11.1 9.75 12.675 11.325Q14.25 12.9 16.5 12.9Q17.875 12.9 19.025 12.287Q20.175 11.675 20.9 10.65Q20.95 10.975 20.975 11.312Q21 11.65 21 12Q21 15.75 18.375 18.375Q15.75 21 12 21ZM12 19Q14.2 19 15.95 17.788Q17.7 16.575 18.5 14.625Q18 14.75 17.5 14.825Q17 14.9 16.5 14.9Q13.425 14.9 11.262 12.738Q9.1 10.575 9.1 7.5Q9.1 7 9.175 6.5Q9.25 6 9.375 5.5Q7.425 6.3 6.213 8.05Q5 9.8 5 12Q5 14.9 7.05 16.95Q9.1 19 12 19ZM11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Q11.75 12.25 11.75 12.25Z"/></svg>
</div>
</div>
<div class="page-wrapper" asscroll>
<section class="hero">
<div class="hero-wrapper">
<!-- Intro Stuff -->
<div class="intro-text">Welcome to my portfolio!</div>
<div class="arrow-svg-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path fill="currentColor" d="M12 14.95q-.2 0-.375-.063-.175-.062-.325-.212L6.675 10.05q-.275-.275-.262-.688.012-.412.287-.687.275-.275.7-.275.425 0 .7.275l3.9 3.9 3.925-3.925q.275-.275.688-.263.412.013.687.288.275.275.275.7 0 .425-.275.7l-4.6 4.6q-.15.15-.325.212-.175.063-.375.063Z"/></svg>
</div>
<div class="hero-main">
<h1 class="hero-main-title">Abigail Bloom</h1>
<p class="hero-main-description">Digital Media Student | 3D Artist</p>
</div>
<div class="hero-second">
<p class="hero-second-subheading first-sub">AbigailBloom</p>
<p class="hero-second-subheading second-sub">Portfolio</p>
</div>
</div>
</section>
<div class="first-move section-margin"></div>
<section class="first-section section left">
<div class="progress-wrapper progress-bar-wrapper-left">
<div class="progress-bar"></div>
</div>
<div class="section-intro-wrapper">
<h1 class="section-title">
<span class="section-title-text">About Me</span>
<div class="section-title-decoration styleOne"></div>
<div class="section-title-decoration styleTwo"></div>
<div class="section-title-decoration styleThree"></div>
</h1>
<span class="section-number">01</span>
</div>
<div class="section-detail-wrapper">
<!-- <h3 class="section-heading">Hello!</h3> -->
<p class="section-text">Hi there ! I'm a third-year digital media student from UK currently studying in Germany. My dream is to work for Disney or Pixar one day.</p>
<p class="section-text"> I love creating art and playing with my cats! I also like drinking bubble tea and going for hikes! Totally hippie lol ✌️. Welcome to my portfolio!</p>
<!-- <h3 class="section-heading">Lorem Ipsum</h3>
<p class="section-text">Lorem ipsum dolor sit amet consectetur adipisicing elit. Hic expedita qui quae officiis, magni velit iste repellat consequuntur temporibus. Quasi atque officia iste beatae rerum, harum itaque accusamus. At, natus?</p> -->
<!-- <h3 class="section-heading">Lorem Ipsum</h3>
<p class="section-text">Lorem ipsum dolor sit amet consectetur adipisicing elit. Hic expedita qui quae officiis, magni velit iste repellat consequuntur temporibus. Quasi atque officia iste beatae rerum, harum itaque accusamus. At, natus?</p> -->
</div>
</section>
<div class="second-move section-margin"></div>
<section class="second-section section right">
<div class="progress-wrapper progress-bar-wrapper-right">
<div class="progress-bar blue-background"></div>
</div>
<div class="section-intro-wrapper blue-text blue-border">
<h1 class="section-title blue-text blue-border">
<span class="section-title-text blue-text">My Work</span>
<div class="section-title-decoration styleOne blue-border"></div>
<div class="section-title-decoration styleTwo blue-border"></div>
<div class="section-title-decoration styleThree blue-background blue-border"></div>
</h1>
<span class="section-number blue-text">02</span>
</div>
<div class="section-detail-wrapper">
<h3 class="section-heading">Candycane Village</h3>
<p class="section-text">This project is in progress but it's about a super colorful village where the entire world including the people are candies. So far the story is that they are set out to explore their "space" only to realize it's a human that will try to destroy them.</p>
<h3 class="section-heading">Rebecca's Reddish Radishes</h3>
<p class="section-text">Oh what's that? Why, it's a red radish! Oop, another one! In this playful and comedy animation, Rebecca, a young farmer, decided to plant radishes for the first time, but there is a big twist!</p>
<h3 class="section-heading">Flora</h3>
<p class="section-text">A heartwarming story about a little orphan girl who tries to find her way back home.</p>
</div>
</section>
<div class="third-move section-margin"></div>
<section class="third-section section left">
<div class="progress-wrapper progress-bar-wrapper-left">
<div class="progress-bar green-background"></div>
</div>
<div class="section-intro-wrapper green-text green-border">
<h1 class="section-title green-text green-border">
<span class="section-title-text green-text">Contact Me</span>
<div class="section-title-decoration styleOne green-border"></div>
<div class="section-title-decoration styleTwo green-border"></div>
<div class="section-title-decoration styleThree green-background green-border"></div>
</h1>
<span class="section-number green-text">03</span>
</div>
<div class="section-detail-wrapper">
<h3 class="section-heading">ArtStation</h3>
<p class="section-text">I post all my work here. I don't want to link it yet because I want to sort it out a little bit!</p>
<h3 class="section-heading">Instagram</h3>
<p class="section-text">Check out my personal instagram for travel pics and food and stuff.</p>
<h3 class="section-heading">LinkedIn</h3>
<p class="section-text">Career updates and so much more!</p>
</div>
</section>
</div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>
D:\code_gitee\abigail-bloom-portolio-bokoko33\main.js
import "./style.css";
import Experience from "./Experience/Experience.js";
const experience = new Experience(document.querySelector(".experience-canvas"));
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Camera.js
import * as THREE from "three";
import Experience from "./Experience.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
export default class Camera {
constructor() {
this.experience = new Experience();
this.sizes = this.experience.sizes;
this.scene = this.experience.scene;
this.canvas = this.experience.canvas;
this.createPerspectiveCamera();
this.createOrthographicCamera();
this.setOrbitControls();
}
createPerspectiveCamera() {
this.perspectiveCamera = new THREE.PerspectiveCamera(
35,
this.sizes.aspect,
0.1,
1000
);
this.scene.add(this.perspectiveCamera);
this.perspectiveCamera.position.x = 29;
this.perspectiveCamera.position.y = 14;
this.perspectiveCamera.position.z = 12;
}
createOrthographicCamera() {
this.orthographicCamera = new THREE.OrthographicCamera(
(-this.sizes.aspect * this.sizes.frustrum) / 2,
(this.sizes.aspect * this.sizes.frustrum) / 2,
this.sizes.frustrum / 2,
-this.sizes.frustrum / 2,
-50,
50
);
// 6.5
this.orthographicCamera.position.y = 5.65;
this.orthographicCamera.position.z = 10;
this.orthographicCamera.rotation.x = -Math.PI / 6;
this.scene.add(this.orthographicCamera);
// this.helper = new THREE.CameraHelper(this.orthographicCamera);
// this.scene.add(this.helper);
const size = 20;
const divisions = 20;
// const gridHelper = new THREE.GridHelper(size, divisions);
// this.scene.add(gridHelper);
// const axesHelper = new THREE.AxesHelper(10);
// this.scene.add(axesHelper);
}
setOrbitControls() {
this.controls = new OrbitControls(this.perspectiveCamera, this.canvas);
this.controls.enableDamping = true;
this.controls.enableZoom = false;
}
resize() {
// Updating Perspective Camera on Resize
this.perspectiveCamera.aspect = this.sizes.aspect;
this.perspectiveCamera.updateProjectionMatrix();
// Updating Orthographic Camera on Resize
this.orthographicCamera.left =
(-this.sizes.aspect * this.sizes.frustrum) / 2;
this.orthographicCamera.right =
(this.sizes.aspect * this.sizes.frustrum) / 2;
this.orthographicCamera.top = this.sizes.frustrum / 2;
this.orthographicCamera.bottom = -this.sizes.frustrum / 2;
this.orthographicCamera.updateProjectionMatrix();
}
update() {
// console.log(this.perspectiveCamera.position);
this.controls.update();
// this.helper.matrixWorldNeedsUpdate = true;
// this.helper.update();
// this.helper.position.copy(this.orthographicCamera.position);
// this.helper.rotation.copy(this.orthographicCamera.rotation);
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Experience.js
import * as THREE from "three";
import Sizes from "./Utils/Sizes.js";
import Time from "./Utils/Time.js";
import Resources from "./Utils/Resources.js";
import assets from "./Utils/assets.js";
import Camera from "./Camera.js";
import Theme from "./Theme.js";
import Renderer from "./Renderer.js";
import Preloader from "./Preloader.js";
import World from "./World/World.js";
import Controls from "./World/Controls.js";
export default class Experience {
static instance;
constructor(canvas) {
if (Experience.instance) {
return Experience.instance;
}
Experience.instance = this;
this.canvas = canvas;
this.scene = new THREE.Scene();
this.time = new Time();
this.sizes = new Sizes();
this.camera = new Camera();
this.renderer = new Renderer();
this.resources = new Resources(assets);
this.theme = new Theme();
this.world = new World();
this.preloader = new Preloader();
this.preloader.on("enablecontrols", () => {
this.controls = new Controls();
});
this.sizes.on("resize", () => {
this.resize();
});
this.time.on("update", () => {
this.update();
});
}
resize() {
this.camera.resize();
this.world.resize();
this.renderer.resize();
}
update() {
this.preloader.update();
this.camera.update();
this.world.update();
this.renderer.update();
if (this.controls) {
this.controls.update();
}
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Preloader.js
import { EventEmitter } from "events";
import Experience from "./Experience.js";
import GSAP from "gsap";
import convert from "./Utils/covertDivsToSpans.js";
export default class Preloader extends EventEmitter {
constructor() {
super();
this.experience = new Experience();
this.scene = this.experience.scene;
this.sizes = this.experience.sizes;
this.resources = this.experience.resources;
this.camera = this.experience.camera;
this.world = this.experience.world;
this.device = this.sizes.device;
this.sizes.on("switchdevice", (device) => {
this.device = device;
});
this.world.on("worldready", () => {
this.setAssets();
this.playIntro();
});
}
setAssets() {
convert(document.querySelector(".intro-text"));
convert(document.querySelector(".hero-main-title"));
convert(document.querySelector(".hero-main-description"));
convert(document.querySelector(".hero-second-subheading"));
convert(document.querySelector(".second-sub"));
this.room = this.experience.world.room.actualRoom;
this.roomChildren = this.experience.world.room.roomChildren;
console.log(this.roomChildren);
}
firstIntro() {
return new Promise((resolve) => {
this.timeline = new GSAP.timeline();
this.timeline.set(".animatedis", { y: 0, yPercent: 100 });
this.timeline.to(".preloader", {
opacity: 0,
delay: 1,
onComplete: () => {
document
.querySelector(".preloader")
.classList.add("hidden");
},
});
if (this.device === "desktop") {
this.timeline
.to(this.roomChildren.cube.scale, {
x: 1.4,
y: 1.4,
z: 1.4,
ease: "back.out(2.5)",
duration: 0.7,
})
.to(this.room.position, {
x: -1,
ease: "power1.out",
duration: 0.7,
});
} else {
this.timeline
.to(this.roomChildren.cube.scale, {
x: 1.4,
y: 1.4,
z: 1.4,
ease: "back.out(2.5)",
duration: 0.7,
})
.to(this.room.position, {
z: -1,
ease: "power1.out",
duration: 0.7,
});
}
this.timeline
.to(".intro-text .animatedis", {
yPercent: 0,
stagger: 0.05,
ease: "back.out(1.7)",
})
.to(
".arrow-svg-wrapper",
{
opacity: 1,
},
"same"
)
.to(
".toggle-bar",
{
opacity: 1,
onComplete: resolve,
},
"same"
);
});
}
secondIntro() {
return new Promise((resolve) => {
this.secondTimeline = new GSAP.timeline();
this.secondTimeline
.to(
".intro-text .animatedis",
{
yPercent: 100,
stagger: 0.05,
ease: "back.in(1.7)",
},
"fadeout"
)
.to(
".arrow-svg-wrapper",
{
opacity: 0,
},
"fadeout"
)
.to(
this.room.position,
{
x: 0,
y: 0,
z: 0,
ease: "power1.out",
},
"same"
)
.to(
this.roomChildren.cube.rotation,
{
y: 2 * Math.PI + Math.PI / 4,
},
"same"
)
.to(
this.roomChildren.cube.scale,
{
x: 10,
y: 10,
z: 10,
},
"same"
)
.to(
this.camera.orthographicCamera.position,
{
y: 6.5,
},
"same"
)
.to(
this.roomChildren.cube.position,
{
x: 0.638711,
y: 8.5618,
z: 1.3243,
},
"same"
)
.set(this.roomChildren.body.scale, {
x: 1,
y: 1,
z: 1,
})
.to(
this.roomChildren.cube.scale,
{
x: 0,
y: 0,
z: 0,
duration: 1,
},
"introtext"
)
.to(
".hero-main-title .animatedis",
{
yPercent: 0,
stagger: 0.07,
ease: "back.out(1.7)",
},
"introtext"
)
.to(
".hero-main-description .animatedis",
{
yPercent: 0,
stagger: 0.07,
ease: "back.out(1.7)",
},
"introtext"
)
.to(
".first-sub .animatedis",
{
yPercent: 0,
stagger: 0.07,
ease: "back.out(1.7)",
},
"introtext"
)
.to(
".second-sub .animatedis",
{
yPercent: 0,
stagger: 0.07,
ease: "back.out(1.7)",
},
"introtext"
)
.to(
this.roomChildren.aquarium.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
">-0.5"
)
.to(
this.roomChildren.clock.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
">-0.4"
)
.to(
this.roomChildren.shelves.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
">-0.3"
)
.to(
this.roomChildren.floor_items.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
">-0.2"
)
.to(
this.roomChildren.desks.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
">-0.1"
)
.to(
this.roomChildren.table_stuff.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
">-0.1"
)
.to(this.roomChildren.computer.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
})
.set(this.roomChildren.mini_floor.scale, {
x: 1,
y: 1,
z: 1,
})
.to(
this.roomChildren.chair.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
"chair"
)
.to(
this.roomChildren.fish.scale,
{
x: 1,
y: 1,
z: 1,
ease: "back.out(2.2)",
duration: 0.5,
},
"chair"
)
.to(
this.roomChildren.chair.rotation,
{
y: 4 * Math.PI + Math.PI / 4,
ease: "power2.out",
duration: 1,
},
"chair"
)
.to(".arrow-svg-wrapper", {
opacity: 1,
onComplete: resolve,
});
});
}
onScroll(e) {
if (e.deltaY > 0) {
this.removeEventListeners();
this.playSecondIntro();
}
}
onTouch(e) {
this.initalY = e.touches[0].clientY;
}
onTouchMove(e) {
let currentY = e.touches[0].clientY;
let difference = this.initalY - currentY;
if (difference > 0) {
console.log("swipped up");
this.removeEventListeners();
this.playSecondIntro();
}
this.intialY = null;
}
removeEventListeners() {
window.removeEventListener("wheel", this.scrollOnceEvent);
window.removeEventListener("touchstart", this.touchStart);
window.removeEventListener("touchmove", this.touchMove);
}
async playIntro() {
this.scaleFlag = true;
await this.firstIntro();
this.moveFlag = true;
this.scrollOnceEvent = this.onScroll.bind(this);
this.touchStart = this.onTouch.bind(this);
this.touchMove = this.onTouchMove.bind(this);
window.addEventListener("wheel", this.scrollOnceEvent);
window.addEventListener("touchstart", this.touchStart);
window.addEventListener("touchmove", this.touchMove);
}
async playSecondIntro() {
this.moveFlag = false;
await this.secondIntro();
this.scaleFlag = false;
this.emit("enablecontrols");
}
move() {
if (this.device === "desktop") {
this.room.position.set(-1, 0, 0);
} else {
this.room.position.set(0, 0, -1);
}
}
scale() {
this.roomChildren.rectLight.width = 0;
this.roomChildren.rectLight.height = 0;
if (this.device === "desktop") {
this.room.scale.set(0.11, 0.11, 0.11);
} else {
this.room.scale.set(0.07, 0.07, 0.07);
}
}
update() {
if (this.moveFlag) {
this.move();
}
if (this.scaleFlag) {
this.scale();
}
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Renderer.js
import * as THREE from "three";
import Experience from "./Experience.js";
export default class Renderer {
constructor() {
this.experience = new Experience();
this.sizes = this.experience.sizes;
this.scene = this.experience.scene;
this.canvas = this.experience.canvas;
this.camera = this.experience.camera;
this.setRenderer();
}
setRenderer() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true,
});
this.renderer.physicallyCorrectLights = true;
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.renderer.toneMapping = THREE.CineonToneMapping;
this.renderer.toneMappingExposure = 1.75;
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setSize(this.sizes.width, this.sizes.height);
this.renderer.setPixelRatio(this.sizes.pixelRatio);
}
resize() {
this.renderer.setSize(this.sizes.width, this.sizes.height);
this.renderer.setPixelRatio(this.sizes.pixelRatio);
}
update() {
// this.renderer.setViewport(0, 0, this.sizes.width, this.sizes.height);
this.renderer.render(this.scene, this.camera.orthographicCamera);
// Second Screen
// this.renderer.setScissorTest(true);
// this.renderer.setViewport(
// this.sizes.width - this.sizes.width / 3,
// this.sizes.height - this.sizes.height / 3,
// this.sizes.width / 3,
// this.sizes.height / 3
// );
// this.renderer.setScissor(
// this.sizes.width - this.sizes.width / 3,
// this.sizes.height - this.sizes.height / 3,
// this.sizes.width / 3,
// this.sizes.height / 3
// );
// this.renderer.render(this.scene, this.camera.perspectiveCamera);
// this.renderer.setScissorTest(false);
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Theme.js
import { EventEmitter } from "events";
export default class Theme extends EventEmitter {
constructor() {
super();
this.theme = "light";
this.toggleButton = document.querySelector(".toggle-button");
this.toggleCircle = document.querySelector(".toggle-circle");
this.setEventListeners();
}
setEventListeners() {
this.toggleButton.addEventListener("click", () => {
this.toggleCircle.classList.toggle("slide");
this.theme = this.theme === "light" ? "dark" : "light";
document.body.classList.toggle("dark-theme");
document.body.classList.toggle("light-theme");
// console.log(this.theme);
this.emit("switch", this.theme);
});
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Utils\assets.js
export default [
{
name: "room",
type: "glbModel",
path: "/models/Finale Version 16.glb",
},
{
name: "screen",
type: "videoTexture",
path: "/textures/kda.mp4",
},
];
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Utils\covertDivsToSpans.js
export default function (element) {
element.style.overflow = "hidden";
element.innerHTML = element.innerText
.split("")
.map((char) => {
if (char === " ") {
return `<span> </span>`;
}
return `<span class="animatedis">${char}</span>`;
})
.join("");
return element;
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Utils\Resources.js
import * as THREE from "three";
import { EventEmitter } from "events";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import Experience from "../Experience.js";
export default class Resources extends EventEmitter {
constructor(assets) {
super();
this.experience = new Experience();
this.renderer = this.experience.renderer;
this.assets = assets;
this.items = {};
this.queue = this.assets.length;
this.loaded = 0;
this.setLoaders();
this.startLoading();
}
setLoaders() {
this.loaders = {};
this.loaders.gltfLoader = new GLTFLoader();
this.loaders.dracoLoader = new DRACOLoader();
this.loaders.dracoLoader.setDecoderPath("/draco/");
this.loaders.gltfLoader.setDRACOLoader(this.loaders.dracoLoader);
}
startLoading() {
for (const asset of this.assets) {
if (asset.type === "glbModel") {
this.loaders.gltfLoader.load(asset.path, (file) => {
this.singleAssetLoaded(asset, file);
});
} else if (asset.type === "videoTexture") {
this.video = {};
this.videoTexture = {};
this.video[asset.name] = document.createElement("video");
this.video[asset.name].src = asset.path;
this.video[asset.name].muted = true;
this.video[asset.name].playsInline = true;
this.video[asset.name].autoplay = true;
this.video[asset.name].loop = true;
this.video[asset.name].play();
this.videoTexture[asset.name] = new THREE.VideoTexture(
this.video[asset.name]
);
// this.videoTexture[asset.name].flipY = false;
this.videoTexture[asset.name].minFilter = THREE.NearestFilter;
this.videoTexture[asset.name].magFilter = THREE.NearestFilter;
this.videoTexture[asset.name].generateMipmaps = false;
this.videoTexture[asset.name].encoding = THREE.sRGBEncoding;
this.singleAssetLoaded(asset, this.videoTexture[asset.name]);
}
}
}
singleAssetLoaded(asset, file) {
this.items[asset.name] = file;
this.loaded++;
if (this.loaded === this.queue) {
this.emit("ready");
}
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Utils\Sizes.js
import { EventEmitter } from "events";
export default class Sizes extends EventEmitter {
constructor() {
super();
this.width = window.innerWidth;
this.height = window.innerHeight;
this.aspect = this.width / this.height;
this.pixelRatio = Math.min(window.devicePixelRatio, 2);
this.frustrum = 5;
if (this.width < 968) {
this.device = "mobile";
} else {
this.device = "desktop";
}
window.addEventListener("resize", () => {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.aspect = this.width / this.height;
this.pixelRatio = Math.min(window.devicePixelRatio, 2);
this.emit("resize");
if (this.width < 968 && this.device !== "mobile") {
this.device = "mobile";
this.emit("switchdevice", this.device);
} else if (this.width >= 968 && this.device !== "desktop") {
this.device = "desktop";
this.emit("switchdevice", this.device);
}
});
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\Utils\Time.js
import { EventEmitter } from "events";
export default class Time extends EventEmitter {
constructor() {
super();
this.start = Date.now();
this.current = this.start;
this.elapsed = 0;
this.delta = 16;
this.update();
}
update() {
const currentTime = Date.now();
this.delta = currentTime - this.current;
this.current = currentTime;
this.elapsed = this.current - this.start;
this.emit("update");
window.requestAnimationFrame(() => this.update());
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\World\Controls.js
import * as THREE from "three";
import Experience from "../Experience.js";
import GSAP from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger.js";
import ASScroll from "@ashthornton/asscroll";
export default class Controls {
constructor() {
this.experience = new Experience();
this.scene = this.experience.scene;
this.sizes = this.experience.sizes;
this.resources = this.experience.resources;
this.time = this.experience.time;
this.camera = this.experience.camera;
this.room = this.experience.world.room.actualRoom;
this.room.children.forEach((child) => {
if (child.type === "RectAreaLight") {
this.rectLight = child;
}
});
this.circleFirst = this.experience.world.floor.circleFirst;
this.circleSecond = this.experience.world.floor.circleSecond;
this.circleThird = this.experience.world.floor.circleThird;
GSAP.registerPlugin(ScrollTrigger);
document.querySelector(".page").style.overflow = "visible";
if (
!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
)
) {
this.setSmoothScroll();
}
this.setScrollTrigger();
}
setupASScroll() {
// https://github.com/ashthornton/asscroll
const asscroll = new ASScroll({
ease: 0.5,
disableRaf: true,
});
GSAP.ticker.add(asscroll.update);
ScrollTrigger.defaults({
scroller: asscroll.containerElement,
});
ScrollTrigger.scrollerProxy(asscroll.containerElement, {
scrollTop(value) {
if (arguments.length) {
asscroll.currentPos = value;
return;
}
return asscroll.currentPos;
},
getBoundingClientRect() {
return {
top: 0,
left: 0,
width: window.innerWidth,
height: window.innerHeight,
};
},
fixedMarkers: true,
});
asscroll.on("update", ScrollTrigger.update);
ScrollTrigger.addEventListener("refresh", asscroll.resize);
requestAnimationFrame(() => {
asscroll.enable({
newScrollElements: document.querySelectorAll(
".gsap-marker-start, .gsap-marker-end, [asscroll]"
),
});
});
return asscroll;
}
setSmoothScroll() {
this.asscroll = this.setupASScroll();
}
setScrollTrigger() {
ScrollTrigger.matchMedia({
//Desktop
"(min-width: 969px)": () => {
// console.log("fired desktop");
this.room.scale.set(0.11, 0.11, 0.11);
this.rectLight.width = 0.5;
this.rectLight.height = 0.7;
this.camera.orthographicCamera.position.set(0, 6.5, 10);
this.room.position.set(0, 0, 0);
// First section -----------------------------------------
this.firstMoveTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".first-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
// markers: true,
invalidateOnRefresh: true,
},
});
this.firstMoveTimeline.fromTo(
this.room.position,
{ x: 0, y: 0, z: 0 },
{
x: () => {
return this.sizes.width * 0.0014;
},
}
);
// Second section -----------------------------------------
this.secondMoveTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".second-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
invalidateOnRefresh: true,
},
})
.to(
this.room.position,
{
x: () => {
return 1;
},
z: () => {
return this.sizes.height * 0.0032;
},
},
"same"
)
.to(
this.room.scale,
{
x: 0.4,
y: 0.4,
z: 0.4,
},
"same"
)
.to(
this.rectLight,
{
width: 0.5 * 4,
height: 0.7 * 4,
},
"same"
);
// Third section -----------------------------------------
this.thirdMoveTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".third-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
invalidateOnRefresh: true,
},
}).to(this.camera.orthographicCamera.position, {
y: 1.5,
x: -4.1,
});
},
// Mobile
"(max-width: 968px)": () => {
// console.log("fired mobile");
// Resets
this.room.scale.set(0.07, 0.07, 0.07);
this.room.position.set(0, 0, 0);
this.rectLight.width = 0.3;
this.rectLight.height = 0.4;
this.camera.orthographicCamera.position.set(0, 6.5, 10);
// First section -----------------------------------------
this.firstMoveTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".first-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
// invalidateOnRefresh: true,
},
}).to(this.room.scale, {
x: 0.1,
y: 0.1,
z: 0.1,
});
// Second section -----------------------------------------
this.secondMoveTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".second-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
invalidateOnRefresh: true,
},
})
.to(
this.room.scale,
{
x: 0.25,
y: 0.25,
z: 0.25,
},
"same"
)
.to(
this.rectLight,
{
width: 0.3 * 3.4,
height: 0.4 * 3.4,
},
"same"
)
.to(
this.room.position,
{
x: 1.5,
},
"same"
);
// Third section -----------------------------------------
this.thirdMoveTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".third-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
invalidateOnRefresh: true,
},
}).to(this.room.position, {
z: -4.5,
});
},
// all
all: () => {
this.sections = document.querySelectorAll(".section");
this.sections.forEach((section) => {
this.progressWrapper =
section.querySelector(".progress-wrapper");
this.progressBar = section.querySelector(".progress-bar");
if (section.classList.contains("right")) {
GSAP.to(section, {
borderTopLeftRadius: 10,
scrollTrigger: {
trigger: section,
start: "top bottom",
end: "top top",
scrub: 0.6,
},
});
GSAP.to(section, {
borderBottomLeftRadius: 700,
scrollTrigger: {
trigger: section,
start: "bottom bottom",
end: "bottom top",
scrub: 0.6,
},
});
} else {
GSAP.to(section, {
borderTopRightRadius: 10,
scrollTrigger: {
trigger: section,
start: "top bottom",
end: "top top",
scrub: 0.6,
},
});
GSAP.to(section, {
borderBottomRightRadius: 700,
scrollTrigger: {
trigger: section,
start: "bottom bottom",
end: "bottom top",
scrub: 0.6,
},
});
}
GSAP.from(this.progressBar, {
scaleY: 0,
scrollTrigger: {
trigger: section,
start: "top top",
end: "bottom bottom",
scrub: 0.4,
pin: this.progressWrapper,
pinSpacing: false,
},
});
});
// All animations
// First section -----------------------------------------
this.firstCircle = new GSAP.timeline({
scrollTrigger: {
trigger: ".first-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
},
}).to(this.circleFirst.scale, {
x: 3,
y: 3,
z: 3,
});
// Second section -----------------------------------------
this.secondCircle = new GSAP.timeline({
scrollTrigger: {
trigger: ".second-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
},
})
.to(
this.circleSecond.scale,
{
x: 3,
y: 3,
z: 3,
},
"same"
)
.to(
this.room.position,
{
y: 0.7,
},
"same"
);
// Third section -----------------------------------------
this.thirdCircle = new GSAP.timeline({
scrollTrigger: {
trigger: ".third-move",
start: "top top",
end: "bottom bottom",
scrub: 0.6,
},
}).to(this.circleThird.scale, {
x: 3,
y: 3,
z: 3,
});
// Mini Platform Animations
this.secondPartTimeline = new GSAP.timeline({
scrollTrigger: {
trigger: ".third-move",
start: "center center",
},
});
this.room.children.forEach((child) => {
if (child.name === "Mini_Floor") {
this.first = GSAP.to(child.position, {
x: -5.44055,
z: 13.6135,
duration: 0.3,
});
}
if (child.name === "Mailbox") {
this.second = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
duration: 0.3,
});
}
if (child.name === "Lamp") {
this.third = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2)",
duration: 0.3,
});
}
if (child.name === "FloorFirst") {
this.fourth = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2)",
duration: 0.3,
});
}
if (child.name === "FloorSecond") {
this.fifth = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
duration: 0.3,
});
}
if (child.name === "FloorThird") {
this.sixth = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2)",
duration: 0.3,
});
}
if (child.name === "Dirt") {
this.seventh = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2)",
duration: 0.3,
});
}
if (child.name === "Flower1") {
this.eighth = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2)",
duration: 0.3,
});
}
if (child.name === "Flower2") {
this.ninth = GSAP.to(child.scale, {
x: 1,
y: 1,
z: 1,
ease: "back.out(2)",
duration: 0.3,
});
}
});
this.secondPartTimeline.add(this.first);
this.secondPartTimeline.add(this.second);
this.secondPartTimeline.add(this.third);
this.secondPartTimeline.add(this.fourth, "-=0.2");
this.secondPartTimeline.add(this.fifth, "-=0.2");
this.secondPartTimeline.add(this.sixth, "-=0.2");
this.secondPartTimeline.add(this.seventh, "-=0.2");
this.secondPartTimeline.add(this.eighth);
this.secondPartTimeline.add(this.ninth, "-=0.1");
},
});
}
resize() {}
update() {}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\World\Environment.js
import * as THREE from "three";
import Experience from "../Experience.js";
import GSAP from "gsap";
import GUI from "lil-gui";
export default class Environment {
constructor() {
this.experience = new Experience();
this.scene = this.experience.scene;
// this.gui = new GUI({ container: document.querySelector(".hero-main") });
this.obj = {
colorObj: { r: 0, g: 0, b: 0 },
intensity: 3,
};
this.setSunlight();
// this.setGUI();
}
setGUI() {
this.gui.addColor(this.obj, "colorObj").onChange(() => {
this.sunLight.color.copy(this.obj.colorObj);
this.ambientLight.color.copy(this.obj.colorObj);
console.log(this.obj.colorObj);
});
this.gui.add(this.obj, "intensity", 0, 10).onChange(() => {
this.sunLight.intensity = this.obj.intensity;
this.sunLight.ambientLight = this.obj.intensity;
});
}
setSunlight() {
this.sunLight = new THREE.DirectionalLight("#ffffff", 3);
this.sunLight.castShadow = true;
this.sunLight.shadow.camera.far = 20;
this.sunLight.shadow.mapSize.set(2048, 2048);
this.sunLight.shadow.normalBias = 0.05;
// const helper = new THREE.CameraHelper(this.sunLight.shadow.camera);
// this.scene.add(helper);
this.sunLight.position.set(-1.5, 7, 3);
this.scene.add(this.sunLight);
this.ambientLight = new THREE.AmbientLight("#ffffff", 1);
this.scene.add(this.ambientLight);
}
switchTheme(theme) {
// console.log(this.sunLight);
if (theme === "dark") {
GSAP.to(this.sunLight.color, {
r: 0.17254901960784313,
g: 0.23137254901960785,
b: 0.6862745098039216,
});
GSAP.to(this.ambientLight.color, {
r: 0.17254901960784313,
g: 0.23137254901960785,
b: 0.6862745098039216,
});
GSAP.to(this.sunLight, {
intensity: 0.78,
});
GSAP.to(this.ambientLight, {
intensity: 0.78,
});
} else {
GSAP.to(this.sunLight.color, {
r: 255 / 255,
g: 255 / 255,
b: 255 / 255,
});
GSAP.to(this.ambientLight.color, {
r: 255 / 255,
g: 255 / 255,
b: 255 / 255,
});
GSAP.to(this.sunLight, {
intensity: 3,
});
GSAP.to(this.ambientLight, {
intensity: 1,
});
}
}
resize() {}
update() {}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\World\Floor.js
import * as THREE from "three";
import Experience from "../Experience.js";
export default class Floor {
constructor() {
this.experience = new Experience();
this.scene = this.experience.scene;
this.setFloor();
this.setCircles();
}
setFloor() {
this.geometry = new THREE.PlaneGeometry(100, 100);
this.material = new THREE.MeshStandardMaterial({
color: 0xffe6a2,
side: THREE.BackSide,
});
this.plane = new THREE.Mesh(this.geometry, this.material);
this.scene.add(this.plane);
this.plane.rotation.x = Math.PI / 2;
this.plane.position.y = -0.3;
this.plane.receiveShadow = true;
}
setCircles() {
const geometry = new THREE.CircleGeometry(5, 64);
const material = new THREE.MeshStandardMaterial({ color: 0xe5a1aa });
const material2 = new THREE.MeshStandardMaterial({ color: 0x8395cd });
const material3 = new THREE.MeshStandardMaterial({ color: 0x7ad0ac });
this.circleFirst = new THREE.Mesh(geometry, material);
this.circleSecond = new THREE.Mesh(geometry, material2);
this.circleThird = new THREE.Mesh(geometry, material3);
this.circleFirst.position.y = -0.29;
this.circleSecond.position.y = -0.28;
this.circleSecond.position.x = 2;
this.circleThird.position.y = -0.27;
this.circleFirst.scale.set(0, 0, 0);
this.circleSecond.scale.set(0, 0, 0);
this.circleThird.scale.set(0, 0, 0);
this.circleFirst.rotation.x =
this.circleSecond.rotation.x =
this.circleThird.rotation.x =
-Math.PI / 2;
this.circleFirst.receiveShadow =
this.circleSecond.receiveShadow =
this.circleThird.receiveShadow =
true;
this.scene.add(this.circleFirst);
this.scene.add(this.circleSecond);
this.scene.add(this.circleThird);
}
resize() {}
update() {}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\World\Room.js
import * as THREE from "three";
import Experience from "../Experience.js";
import GSAP from "gsap";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";
export default class Room {
constructor() {
this.experience = new Experience();
this.scene = this.experience.scene;
this.resources = this.experience.resources;
this.time = this.experience.time;
this.room = this.resources.items.room;
this.actualRoom = this.room.scene;
this.roomChildren = {};
this.lerp = {
current: 0,
target: 0,
ease: 0.1,
};
this.setModel();
this.setAnimation();
this.onMouseMove();
}
setModel() {
this.actualRoom.children.forEach((child) => {
child.castShadow = true;
child.receiveShadow = true;
if (child instanceof THREE.Group) {
child.children.forEach((groupchild) => {
groupchild.castShadow = true;
groupchild.receiveShadow = true;
});
}
// console.log(child);
if (child.name === "Aquarium") {
// console.log(child);
child.children[0].material = new THREE.MeshPhysicalMaterial();
child.children[0].material.roughness = 0;
child.children[0].material.color.set(0x549dd2);
child.children[0].material.ior = 3;
child.children[0].material.transmission = 1;
child.children[0].material.opacity = 1;
}
if (child.name === "Computer") {
child.children[1].material = new THREE.MeshBasicMaterial({
map: this.resources.items.screen,
});
}
if (child.name === "Mini_Floor") {
child.position.x = -0.289521;
child.position.z = 8.83572;
}
// if (
// child.name === "Mailbox" ||
// child.name === "Lamp" ||
// child.name === "FloorFirst" ||
// child.name === "FloorSecond" ||
// child.name === "FloorThird" ||
// child.name === "Dirt" ||
// child.name === "Flower1" ||
// child.name === "Flower2"
// ) {
// child.scale.set(0, 0, 0);
// }
child.scale.set(0, 0, 0);
if (child.name === "Cube") {
// child.scale.set(1, 1, 1);
child.position.set(0, -1, 0);
child.rotation.y = Math.PI / 4;
}
this.roomChildren[child.name.toLowerCase()] = child;
});
const width = 0.5;
const height = 0.7;
const intensity = 1;
const rectLight = new THREE.RectAreaLight(
0xffffff,
intensity,
width,
height
);
rectLight.position.set(7.68244, 7, 0.5);
rectLight.rotation.x = -Math.PI / 2;
rectLight.rotation.z = Math.PI / 4;
this.actualRoom.add(rectLight);
this.roomChildren["rectLight"] = rectLight;
// const rectLightHelper = new RectAreaLightHelper(rectLight);
// rectLight.add(rectLightHelper);
// console.log(this.room);
this.scene.add(this.actualRoom);
this.actualRoom.scale.set(0.11, 0.11, 0.11);
}
setAnimation() {
this.mixer = new THREE.AnimationMixer(this.actualRoom);
this.swim = this.mixer.clipAction(this.room.animations[0]);
this.swim.play();
}
onMouseMove() {
window.addEventListener("mousemove", (e) => {
this.rotation =
((e.clientX - window.innerWidth / 2) * 2) / window.innerWidth;
this.lerp.target = this.rotation * 0.05;
});
}
resize() {}
update() {
this.lerp.current = GSAP.utils.interpolate(
this.lerp.current,
this.lerp.target,
this.lerp.ease
);
this.actualRoom.rotation.y = this.lerp.current;
this.mixer.update(this.time.delta * 0.0009);
}
}
D:\code_gitee\abigail-bloom-portolio-bokoko33\Experience\World\World.js
import * as THREE from "three";
import Experience from "../Experience.js";
import Room from "./Room.js";
import Floor from "./Floor.js";
import Controls from "./Controls.js";
import Environment from "./Environment.js";
import { EventEmitter } from "events";
export default class World extends EventEmitter {
constructor() {
super();
this.experience = new Experience();
this.sizes = this.experience.sizes;
this.scene = this.experience.scene;
this.canvas = this.experience.canvas;
this.camera = this.experience.camera;
this.resources = this.experience.resources;
this.theme = this.experience.theme;
this.resources.on("ready", () => {
this.environment = new Environment();
this.floor = new Floor();
this.room = new Room();
// this.controls = new Controls();
this.emit("worldready");
});
this.theme.on("switch", (theme) => {
this.switchTheme(theme);
});
// this.sizes.on("switchdevice", (device) => {
// this.switchDevice(device);
// });
}
switchTheme(theme) {
if (this.environment) {
this.environment.switchTheme(theme);
}
}
// switchDevice(device) {
// if (this.controls) {
// this.controls.switchDevice(device);
// }
// }
resize() {}
update() {
if (this.room) {
this.room.update();
}
if (this.controls) {
this.controls.update();
}
}
}