diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..6253224
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,3 @@
+{
+ "singleQuote": true
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..66eb8bf
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,11 @@
+{
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "three": {
+ "version": "0.119.1",
+ "resolved": "https://registry.npmjs.org/three/-/three-0.119.1.tgz",
+ "integrity": "sha512-GHyh/RiUfQ5VTiWIVRRTANYoXc1PFB1y+jDVRTb649nif1uX1F06PT1TKU3k2+F/MN4UJ3PWvQB53fY2OqKqKw=="
+ }
+ }
+}
diff --git a/webclient/package.json b/webclient/package.json
index b7a9703..b7c7efa 100644
--- a/webclient/package.json
+++ b/webclient/package.json
@@ -20,7 +20,8 @@
"react-scripts": "3.4.1",
"react-to-print": "~2.5.1",
"recharts": "~1.8.5",
- "semantic-ui-react": "~0.88.2"
+ "semantic-ui-react": "~0.88.2",
+ "three": "^0.119.1"
},
"scripts": {
"start": "react-scripts start",
diff --git a/webclient/src/Footer.js b/webclient/src/Footer.js
index ad21593..1c57e74 100644
--- a/webclient/src/Footer.js
+++ b/webclient/src/Footer.js
@@ -1,46 +1,154 @@
-import React from 'react';
+import React, { useRef, useEffect } from 'react';
import { Container, Icon } from 'semantic-ui-react';
+import * as THREE from 'three/build/three.module';
+import { Ship } from './spaceport/Ship';
+
+export const Footer = () => {
+ const footerRef = useRef();
+
+ useEffect(() => {
+ if (!footerRef.current) return;
+
+ let t = 0.01;
+ const shipInterval = 2;
+ let nextShip = shipInterval;
+
+ var scene = new THREE.Scene();
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize(
+ footerRef.current.clientWidth,
+ footerRef.current.clientHeight
+ );
+
+ const camera = new THREE.PerspectiveCamera(65, 1, 0.01, 1000);
+ camera.position.set(4, 1, 4);
+ camera.lookAt(new THREE.Vector3(-8, 0, -2));
+
+ scene.add(camera);
+
+ footerRef.current.appendChild(renderer.domElement);
+
+ let ships = [];
+ const ship = new Ship();
+ scene.add(ship.mesh);
+ ships.push(ship);
+
+ const animate = () => {
+ const deltaTime = 0.075;
+ t += deltaTime;
+
+ // get mouse
+
+ if (t > nextShip) {
+ console.log('bing');
+ const ship = new Ship();
+ scene.add(ship.mesh);
+ ships.push(ship);
+ nextShip += shipInterval + (Math.random() - 0.5) * 2;
+ }
+
+ for (const ship of ships) {
+ ship.update({ deltaTime });
+ if (ship.kill) {
+ console.log('killing ship');
+ scene.remove(ship.mesh);
+ }
+ }
+
+ ships = ships.filter((s) => !s.kill);
+
+ requestAnimationFrame(animate);
+ renderer.render(scene, camera);
+ };
+
+ animate();
+
+ renderer.render(scene, camera);
+ }, [footerRef]);
-export function Footer() {
return (
-
-
+
+
-
+
-
- Contact us: info@protospace.ca
+
+ Contact us:{' '}
+
+ info@protospace.ca
+
-
- Created and hosted by Protospace members for Protospace members.
+
+ Created and hosted by Protospace members for Protospace
+ members.
-
- Spaceport is free and open-source software. Click here to view the source code and license.
+
+ Spaceport is free and open-source software.{' '}
+
+ Click here
+ {' '}
+ to view the source code and license.
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
© 2020 Calgary Protospace Ltd.
-
);
diff --git a/webclient/src/light.css b/webclient/src/light.css
index eeddb3b..530ceec 100644
--- a/webclient/src/light.css
+++ b/webclient/src/light.css
@@ -1,4 +1,5 @@
-html, body {
+html,
+body {
font-size: 16px;
height: 100%;
margin: 0;
@@ -43,7 +44,7 @@ body {
padding-top: 1rem;
}
-.topPadding > .ui.container{
+.topPadding > .ui.container {
min-height: 45rem;
}
@@ -66,7 +67,9 @@ body {
padding-bottom: 24rem;
}
-.course-editor, .class-editor, .transaction-editor {
+.course-editor,
+.class-editor,
+.transaction-editor {
margin-bottom: 1rem;
}
@@ -116,12 +119,22 @@ body {
.footer {
margin-top: -20rem;
-
background: black;
color: white;
+ display: grid;
}
+/* grid bottom */
+.footer canvas {
+ grid-row: 1/2;
+ grid-column: 1/2;
+}
+
+/* grid top */
.footer .container {
+ z-index: 99;
+ grid-row: 1/2;
+ grid-column: 1/2;
padding-top: 3rem;
padding-bottom: 3rem;
}
@@ -151,8 +164,8 @@ body {
margin-right: 0.5em;
}
-
-.darkmode-layer, .darkmode-toggle {
+.darkmode-layer,
+.darkmode-toggle {
z-index: 500;
}
diff --git a/webclient/src/spaceport/Ship.js b/webclient/src/spaceport/Ship.js
new file mode 100644
index 0000000..c0c3034
--- /dev/null
+++ b/webclient/src/spaceport/Ship.js
@@ -0,0 +1,65 @@
+import * as THREE from 'three';
+
+const SHIP_SIZE = 1;
+
+export class Ship {
+ constructor() {
+ this.life = Math.random() * 5 + 3;
+ this.flyIn = true;
+
+ const shipGeo = new THREE.BoxGeometry(
+ SHIP_SIZE * 0.3,
+ SHIP_SIZE * 0.3,
+ SHIP_SIZE
+ );
+ this.mesh = new THREE.Mesh(
+ shipGeo,
+ new THREE.MeshBasicMaterial(0xff0000)
+ );
+ this.y = (Math.random() - 0.5) * 2;
+
+ this.hue = Math.floor(Math.random() * 360);
+
+ this.mesh.material.color.set(
+ new THREE.Color(`hsl(${this.hue},70%,80%)`)
+ );
+ this.mesh.position.x = (Math.random() - 0.5) * 2;
+ this.mesh.position.y = this.y;
+ this.mesh.position.z = -105 + Math.random();
+ }
+
+ update({ deltaTime }) {
+ if (this.flyIn) {
+ this.mesh.scale.z = 10;
+ this.mesh.position.z += 4.75;
+
+ // ship accelerating decreasing
+ // checvk if in space
+ if (this.mesh.position.z > -1 && this.flyIn) {
+ this.flyIn = false;
+ this.mesh.scale.z = 0.5;
+ this.mesh.material.color.set(
+ new THREE.Color(`hsl(${this.hue},70%,100%)`)
+ );
+ }
+ } else {
+ this.mesh.scale.z = 0.5;
+ }
+
+ this.life -= deltaTime;
+
+ this.mesh.position.y = this.y + Math.sin(this.life + this.y) * 0.02;
+
+ if (this.life < 0) {
+ const a = Math.abs(this.life);
+ this.mesh.position.z += a * 2;
+ this.mesh.scale.z = a * 4;
+
+ // accelerate away
+ }
+
+ if (this.mesh.position.z > 5) {
+ this.kill = true;
+ }
+ }
+}
diff --git a/webclient/yarn.lock b/webclient/yarn.lock
index 3df4f32..c83e352 100644
--- a/webclient/yarn.lock
+++ b/webclient/yarn.lock
@@ -10473,6 +10473,11 @@ text-table@0.2.0, text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+three@^0.119.1:
+ version "0.119.1"
+ resolved "https://registry.yarnpkg.com/three/-/three-0.119.1.tgz#9d979a082c4cd9622af8e3498a8dfa026a619332"
+ integrity sha512-GHyh/RiUfQ5VTiWIVRRTANYoXc1PFB1y+jDVRTb649nif1uX1F06PT1TKU3k2+F/MN4UJ3PWvQB53fY2OqKqKw==
+
throat@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"