HTML/CSS/Javascript
Here is a collection of all the projects and code I wrote using HTML, CSS, and Javascript. I have included here my internship work as well as a class project.
Three.js
This script uses a library called Three.js to create a 3D environment on a website. Pick'd in Columbus asked me to create the website for my internship with the company in the summer of 2021. There are many methods being utilized from Three.js, as well as a physics library system called CANNON.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pic'd Test</title>
</head>
<body>
<a href="javascript:void(0)" id="openBtn" onclick="openNav()">
<div></div>
<div></div>
<div></div>
</a>
<div id="mySideNav" class="sideNav">
<a href="javascript:void(0)" class="closeBtn" onclick="closeNav()">
<div></div>
<div></div>
<div></div
></a>
<div id="container">
<h1><u>Flowers</u></h1>
<br />
<h2><i>Roses</i></h2>
<a class="link white" id="whiteRose">White</a>
<a class="link red" id="redRose">Red</a>
<a class="link yellow" id="yellowRose">Yellow</a>
<a class="link lavender" id="lavenderRose"> Lavender </a>
<a class="link orange" id="orangeRose">Orange</a>
<a class="link pink" id="pinkRose">Pink</a>
<br />
<h2><i>Carnations</i></h2>
<a class="link white" id="whiteCarnation">White</a>
<a class="link red" id="redCarnation">Red</a>
<a class="link yellow" id="yellowCarnation">Yellow</a>
<a class="link pink" id="pinkCarnation">Pink</a>
<br />
<h2><i>Lillies</i></h2>
<a class="link white" id="whiteLilly">White</a>
<a class="link yellow" id="yellowLilly">Yellow</a>
<a class="link pink" id="pinkLilly">Pink</a>
<br />
<h2><i>Daisies</i></h2>
<a class="link white" id="whiteDaisy">White</a>
<a class="link red" id="gerberaDaisy">Gerbera</a>
<a class="link yellow" id="yellowDaisy">Yellow</a>
<a class="link pink" id="pinkDaisy">Pink</a>
<br />
<h2><i>Delphinium</i></h2>
<a class="link white" id="whiteDelphinium">White</a>
<a class="link blue" id="blueDelphinium">Blue</a>
<a class="link lavender" id="lavenderDelphinium"> Lavender </a>
<br />
<h2><i>Sunflower</i></h2>
<a class="link yellow" id="sunflower">Sunflower</a>
<br />
<h1><u>Foliage</u></h1>
<a class="link green" id="largeFoliage">Large</a>
<a class="link green" id="mediumFoliage">Medium</a>
<a class="link green" id="smallFoliage">Small</a>
<br />
<br />
<br />
<br />
</div>
</div>
<script>
function openNav() {
document.getElementById("mySideNav").style.width = "400px";
document.getElementById("openBtn").style.display = "none";
}
function closeNav() {
document.getElementById("mySideNav").style.width = "0";
document.getElementById("openBtn").style.display = "block";
}
</script>
<canvas class="webgl"></canvas>
</body>
</html>
Javascript
import "./style.css";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import * as CANNON from "cannon-es";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass.js";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";
/**
* Starting Variables
*/
const objectsToUpdate = [];
const timerQueue = [];
/**
* Canvas
*/
const canvas = document.querySelector("canvas.webgl");
/**
* Scene
*/
const scene = new THREE.Scene();
/**
* Loaders
*/
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("/draco/");
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
/**
* Update all materials
*/
const updateAllMaterials = () => {
scene.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.castShadow = true;
}
if ((child instanceof THREE.Mesh) & (child.name != "Vase")) {
child.receiveShadow = true;
}
});
};
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};
window.addEventListener("resize", () => {
// // Update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
// Update camera
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
// Update renderer
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// Update effect composer
effectComposer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
effectComposer.setSize(sizes.width, sizes.height);
});
/**
* Camera
*/
const camera = new THREE.PerspectiveCamera(
75,
sizes.width / sizes.height,
0.1,
100
);
camera.position.x = 0;
camera.position.y = 1;
camera.position.z = -3;
camera.rotation.x = Math.PI / 8;
camera.rotation.y = Math.PI;
camera.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(camera);
// Cursor
const cursor = {
x: 0,
y: 0,
};
window.addEventListener("mousemove", (event) => {
cursor.x = event.clientX / sizes.width - 0.5;
cursor.y = event.clientY / sizes.height - 0.5;
});
/**
* Physics
*/
// World
const world = new CANNON.World();
world.broadphase = new CANNON.SAPBroadphase(world);
world.allowSleep = true;
world.gravity.set(0, -9.82, 0);
// Material
const defaultMaterial = new CANNON.Material("default");
const defaultContactMaterial = new CANNON.ContactMaterial(
defaultMaterial,
defaultMaterial,
{
friction: 1,
restitution: 0.1,
}
);
world.defaultContactMaterial = defaultContactMaterial;
/**
* Physics Models
*/
// Vase
const vaseBottomShape = new CANNON.Plane();
const vaseBottomBody = new CANNON.Body();
vaseBottomBody.mass = 0;
vaseBottomBody.material = defaultMaterial;
vaseBottomBody.quaternion.setFromAxisAngle(
new CANNON.Vec3(-1, 0, 0),
Math.PI * 0.5
);
vaseBottomBody.addShape(vaseBottomShape);
const vaseWallShapeFront = new CANNON.Box(new CANNON.Vec3(0.7, 0.7, 0.01));
const vaseWallFrontBody = new CANNON.Body();
vaseWallFrontBody.mass = 0;
vaseWallFrontBody.material = defaultMaterial;
vaseWallFrontBody.addShape(vaseWallShapeFront);
const vaseWallShapeBack = new CANNON.Box(new CANNON.Vec3(0.7, 0.7, 0.01));
const vaseWallBackBody = new CANNON.Body();
vaseWallBackBody.mass = 0;
vaseWallBackBody.material = defaultMaterial;
vaseWallBackBody.quaternion.setFromAxisAngle(
new CANNON.Vec3(0, 0, -1),
Math.PI * 0.5
);
vaseWallBackBody.addShape(vaseWallShapeBack);
const vaseWallShapeRight = new CANNON.Box(new CANNON.Vec3(0.7, 0.7, 0.01));
const vaseWallRightBody = new CANNON.Body();
vaseWallRightBody.mass = 0;
vaseWallRightBody.material = defaultMaterial;
vaseWallRightBody.quaternion.setFromAxisAngle(
new CANNON.Vec3(0, 1, 0),
Math.PI * 0.5
);
vaseWallRightBody.addShape(vaseWallShapeRight);
const vaseWallShapeLeft = new CANNON.Box(new CANNON.Vec3(0.7, 0.7, 0.01));
const vaseWallLeftBody = new CANNON.Body();
vaseWallLeftBody.mass = 0;
vaseWallLeftBody.material = defaultMaterial;
vaseWallLeftBody.quaternion.setFromAxisAngle(
new CANNON.Vec3(0, -1, 0),
Math.PI * 0.5
);
vaseWallLeftBody.addShape(vaseWallShapeLeft);
vaseBottomBody.position.set(0.05, -0.8, 0);
vaseWallFrontBody.position.set(0.05, 0, -0.18);
vaseWallBackBody.position.set(0.05, 0, 0.18);
vaseWallRightBody.position.set(-0.18, 0, 0);
vaseWallLeftBody.position.set(0.18, 0, 0);
world.addBody(vaseBottomBody);
world.addBody(vaseWallFrontBody);
world.addBody(vaseWallBackBody);
world.addBody(vaseWallRightBody);
world.addBody(vaseWallLeftBody);
/**
* Blender Models
*/
let mixer = null;
// Static
gltfLoader.load("/models/background/background.glb", (gltf) => {
scene.add(gltf.scene);
});
/**
* Foliage
*/
let largeFoliage = new THREE.Mesh();
let mediumFoliage = new THREE.Mesh();
let smallFoliage = new THREE.Mesh();
const spawnLargeFoliage = function () {
gltfLoader.load("/models/background/largeFoliage.glb", (gltf) => {
largeFoliage = gltf.scene;
scene.add(largeFoliage);
});
};
const spawnMediumFoliage = function () {
gltfLoader.load("/models/background/mediumFoliage.glb", (gltf) => {
mediumFoliage = gltf.scene;
scene.add(mediumFoliage);
});
};
const spawnSmallFoliage = function () {
gltfLoader.load("/models/background/smallFoliage.glb", (gltf) => {
smallFoliage = gltf.scene;
scene.add(smallFoliage);
});
};
const largeFoliageBtn = document.getElementById("largeFoliage");
const mediumFoliageBtn = document.getElementById("mediumFoliage");
const smallFoliageBtn = document.getElementById("smallFoliage");
largeFoliageBtn.addEventListener("click", function (event) {
event.preventDefault();
spawnLargeFoliage();
scene.remove(mediumFoliage);
scene.remove(smallFoliage);
});
mediumFoliageBtn.addEventListener("click", function (event) {
event.preventDefault();
spawnMediumFoliage();
scene.remove(smallFoliage);
scene.remove(largeFoliage);
});
smallFoliageBtn.addEventListener("click", function (event) {
event.preventDefault();
spawnSmallFoliage();
scene.remove(largeFoliage);
scene.remove(mediumFoliage);
});
spawnMediumFoliage();
/**
* Flowers
*/
const length = 0.75;
/**
* Roses
*/
const createFlower = function (location, positionX, positionY, positionZ) {
gltfLoader.load(location, (gltf) => {
let flower = gltf.scene;
flower.position.set(positionX, positionY, positionZ);
scene.add(flower);
// Cannon.js body
const petalShape = new CANNON.Sphere(0.1);
const stemShape = new CANNON.Cylinder(0.01, 0.01, length + 0.4, 6);
const flowerPetal = new CANNON.Body({
mass: 10,
material: defaultMaterial,
});
flowerPetal.addShape(petalShape, new CANNON.Vec3(0, 0.2, 0));
flowerPetal.position.set(positionX, positionY, positionZ);
world.addBody(flowerPetal);
const flowerStem = new CANNON.Body({
mass: 1,
material: defaultMaterial,
});
flowerStem.addShape(stemShape, new CANNON.Vec3(0, -0.5 - length / 2, 0));
flowerStem.position.set(positionX, positionY, positionZ);
world.addBody(flowerStem);
var flowerConstraint = new CANNON.ConeTwistConstraint(
flowerPetal,
flowerStem,
{
pivotA: new CANNON.Vec3(0, 0, 0),
pivotB: new CANNON.Vec3(0, 0, 0),
axisA: CANNON.Vec3.UNIT_Y,
axisB: CANNON.Vec3.UNIT_Y,
angle: Math.PI / 4,
twistAngle: Math.PI / 4,
}
);
world.addConstraint(flowerConstraint);
// Save in objects to update
objectsToUpdate.push({
flowerAndBody: {
flower: flower,
body: flowerPetal,
},
});
timerQueue.push(
setTimeout(() => {
objectsToUpdate.shift();
}, 5000)
);
});
};
/**
* Delphinium
*/
// White Delphinium
const createDelphinium = function (location, positionX, positionY, positionZ) {
gltfLoader.load(location, (gltf) => {
let delphinium = gltf.scene;
delphinium.position.set(positionX, positionY, positionZ);
scene.add(delphinium);
// Cannon.js body
const stemShape = new CANNON.Cylinder(
0.04,
0.04,
Math.random() + length,
6
);
const delphiniumBody = new CANNON.Body({
mass: 3,
material: defaultMaterial,
});
delphiniumBody.addShape(
stemShape,
new CANNON.Vec3(0, -0.5 - length / 2, 0)
);
delphiniumBody.position.set(positionX, positionY, positionZ);
world.addBody(delphiniumBody);
// Save in objects to update
objectsToUpdate.push({
flowerAndBody: {
flower: delphinium,
body: delphiniumBody,
},
});
});
};
// Roses
const whiteRoseBtn = document.getElementById("whiteRose");
const redRoseBtn = document.getElementById("redRose");
const yellowRoseBtn = document.getElementById("yellowRose");
const lavenderRoseBtn = document.getElementById("lavenderRose");
const orangeRoseBtn = document.getElementById("orangeRose");
const pinkRoseBtn = document.getElementById("pinkRose");
whiteRoseBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/roses/whiteRose.glb", 0, 0.8, 0);
});
redRoseBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/roses/redRose.glb", 0, 0.8, 0);
});
yellowRoseBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/roses/yellowRose.glb", 0, 0.8, 0);
});
lavenderRoseBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/roses/lavenderRose.glb", 0, 0.8, 0);
});
orangeRoseBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/roses/orangeRose.glb", 0, 0.8, 0);
});
pinkRoseBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/roses/pinkRose.glb", 0, 0.8, 0);
});
// Carnations
const whiteCarnationBtn = document.getElementById("whiteCarnation");
const redCarnationBtn = document.getElementById("redCarnation");
const yellowCarnationBtn = document.getElementById("yellowCarnation");
const pinkCarnationBtn = document.getElementById("pinkCarnation");
whiteCarnationBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/carnations/whiteCarnation.glb", 0, 0.8, 0);
});
redCarnationBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/carnations/redCarnation.glb", 0, 0.8, 0);
});
yellowCarnationBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/carnations/yellowCarnation.glb", 0, 0.8, 0);
});
pinkCarnationBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/carnations/pinkCarnation.glb", 0, 0.8, 0);
});
// Lillies
const whiteLillyBtn = document.getElementById("whiteLilly");
const yellowLillyBtn = document.getElementById("yellowLilly");
const pinkLillyBtn = document.getElementById("pinkLilly");
whiteLillyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Lillies/whiteLilly.glb", 0, 0.8, 0);
});
yellowLillyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Lillies/yellowLilly.glb", 0, 0.8, 0);
});
pinkLillyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Lillies/pinkLilly.glb", 0, 0.8, 0);
});
// Daisies
const whiteDaisyBtn = document.getElementById("whiteDaisy");
const gerberaDaisyBtn = document.getElementById("gerberaDaisy");
const yellowDaisyBtn = document.getElementById("yellowDaisy");
const pinkDaisyBtn = document.getElementById("pinkDaisy");
whiteDaisyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Daisies/whiteDaisy.glb", 0, 0.8, 0);
});
gerberaDaisyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Daisies/gerberaDaisy.glb", 0, 0.8, 0);
});
yellowDaisyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Daisies/yellowDaisy.glb", 0, 0.8, 0);
});
pinkDaisyBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/Daisies/pinkDaisy.glb", 0, 0.8, 0);
});
// Delphinium
const whiteDelphiniumBtn = document.getElementById("whiteDelphinium");
const blueDelphiniumBtn = document.getElementById("blueDelphinium");
const lavenderDelphiniumBtn = document.getElementById("lavenderDelphinium");
whiteDelphiniumBtn.addEventListener("click", function (event) {
event.preventDefault();
createDelphinium("/models/delphinium/whiteDelphinium.glb", 0, 0.8, 0);
});
blueDelphiniumBtn.addEventListener("click", function (event) {
event.preventDefault();
createDelphinium("/models/delphinium/blueDelphinium.glb", 0, 0.8, 0);
});
lavenderDelphiniumBtn.addEventListener("click", function (event) {
event.preventDefault();
createDelphinium("/models/delphinium/lavenderDelphinium.glb", 0, 0.8, 0);
});
// Sunflower
const sunflowerBtn = document.getElementById("sunflower");
sunflowerBtn.addEventListener("click", function (event) {
event.preventDefault();
createFlower("/models/sunflower/sunflower.glb", 0, 0.8, 0);
});
const clock = new THREE.Clock();
let previousTime = 0;
// Physics for Flowers
const physicsTick = () => {
const elapsedTime = clock.getElapsedTime();
const deltaTime = elapsedTime - previousTime;
previousTime = elapsedTime;
// Update Physics World
world.step(1 / 60, deltaTime, 3);
for (const object of objectsToUpdate) {
object.flowerAndBody.flower.position.copy(
object.flowerAndBody.body.position
);
object.flowerAndBody.flower.quaternion.copy(
object.flowerAndBody.body.quaternion
);
}
// Call tick again on the next frame
window.requestAnimationFrame(physicsTick);
};
physicsTick();
/**
* Lights
*/
// Ambient Light
const ambientLight = new THREE.AmbientLight(0xfdfff2, 0.1);
scene.add(ambientLight);
// Main Spotlight
const mainSpotLight = new THREE.SpotLight(0xffffbd, 10);
mainSpotLight.position.set(3, 30, -10);
scene.add(mainSpotLight);
mainSpotLight.castShadow = true;
mainSpotLight.shadow.mapSize.set(1024 * 4, 1024 * 4);
mainSpotLight.shadow.camera.near = 2;
mainSpotLight.shadow.camera.far = 18;
mainSpotLight.shadow.camera.fov = 1;
mainSpotLight.shadow.normalBias = -0.03;
// Top Spotlight
const topSpotLight = new THREE.SpotLight(0xffffbd, 6);
topSpotLight.position.set(0, 7.5, -0.3);
topSpotLight.penumbra = 1;
scene.add(topSpotLight);
// Rotation
mainSpotLight.rotation.reorder("YXZ");
topSpotLight.rotation.reorder("YXZ");
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
});
renderer.antialias = true;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.physicallyCorrectLights = true;
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 9;
/**
* Post processing
*/
//Render target
let RenderTargetClass = null;
if (renderer.getPixelRatio() === 1 && renderer.capabilities.isWebGL2) {
RenderTargetClass = THREE.WebGLMultisampleRenderTarget;
} else {
RenderTargetClass = THREE.WebGLRenderTarget;
}
//Effect Composer
const effectComposer = new EffectComposer(renderer);
effectComposer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
effectComposer.setSize(sizes.width, sizes.height);
//Render Pass
const renderPass = new RenderPass(scene, camera);
effectComposer.addPass(renderPass);
//Unreal Bloom Pass
const unrealBloomPass = new UnrealBloomPass();
unrealBloomPass.strength = 0.12;
unrealBloomPass.radius = 0;
unrealBloomPass.threshold = 0.6;
effectComposer.addPass(unrealBloomPass);
//Tint pass
const TintShader = {
uniforms: {
tDiffuse: { value: null },
uTint: { value: null },
},
vertexShader: `
varying vec2 vUv;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
vUv = uv;
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform vec3 uTint;
varying vec2 vUv;
void main(){
vec4 color = texture2D(tDiffuse, vUv);
// color.r += 0.2;
// color.b += 0.2;
color.rgb += uTint;
gl_FragColor = color;
}
`,
};
const tintPass = new ShaderPass(TintShader);
tintPass.material.uniforms.uTint.value = new THREE.Vector3();
effectComposer.addPass(tintPass);
// SMAA Pass
if (renderer.getPixelRatio() === 1 && !renderer.capabilities.isWebGl2) {
const smaaPass = new SMAAPass();
effectComposer.addPass(smaaPass);
}
/**
* Animation
*/
// Update Everything
const tick = () => {
if (mixer) {
mixer.update(deltaTime);
}
// Update Materials
updateAllMaterials();
// Update controls
// controls.update();
// Update camera to see all around
camera.position.x = -Math.sin(cursor.x * Math.PI) * 2;
camera.position.y = Math.cos(cursor.y * Math.PI) * 2;
camera.position.z = -Math.cos(cursor.x * Math.PI) * 2;
camera.lookAt(new THREE.Vector3(0, 1, 0));
// Render
effectComposer.render();
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
Clicker Browser Game
I created as a final project for my college course a clicker game with various levels of collectables. The scripts involved with this project use modules to seperate the code out.








