Edmonton skyline

Edmonton

Orbit

Orbit

Launch

Launch

Innovate

Innovate

Envisioning Edmonton as an Aerospace Hub

https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js

(function() {
var STL_B64 = “REPLACE_WITH_STL_BASE64”;

function b64ToArrayBuffer(b64) {
var bin = atob(b64);
var buf = new ArrayBuffer(bin.length);
var view = new Uint8Array(buf);
for (var i = 0; i < bin.length; i++) view[i] = bin.charCodeAt(i);
return buf;
}

function parseBinarySTL(buffer) {
var view = new DataView(buffer);
var numTris = view.getUint32(80, true);
var geo = new THREE.BufferGeometry();
var verts = new Float32Array(numTris * 9);
var norms = new Float32Array(numTris * 9);
var offset = 84;
for (var i = 0; i < numTris; i++) {
var nx = view.getFloat32(offset, true);
var ny = view.getFloat32(offset+4, true);
var nz = view.getFloat32(offset+8, true);
offset += 12;
for (var j = 0; j < 3; j++) {
var vi = i*9 + j*3;
verts[vi] = view.getFloat32(offset, true);
verts[vi+1] = view.getFloat32(offset+4, true);
verts[vi+2] = view.getFloat32(offset+8, true);
norms[vi] = nx; norms[vi+1] = ny; norms[vi+2] = nz;
offset += 12;
}
offset += 2;
}
geo.setAttribute(‘position’, new THREE.BufferAttribute(verts, 3));
geo.setAttribute(‘normal’, new THREE.BufferAttribute(norms, 3));
return geo;
}

var canvas = document.getElementById(‘eaoCanvas’);
var size = Math.min(window.innerWidth * 0.22, 260);
canvas.width = size;
canvas.height = size;

var renderer = new THREE.WebGLRenderer({ canvas: canvas, alpha: true, antialias: true });
renderer.setSize(size, size);
renderer.setPixelRatio(window.devicePixelRatio || 1);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(40, 1, 0.001, 100);
camera.position.set(0, 0, 0.12);

var ambient = new THREE.AmbientLight(0x4ec2e7, 0.4);
scene.add(ambient);
var dirA = new THREE.DirectionalLight(0x4ec2e7, 1.2);
dirA.position.set(1, 2, 3);
scene.add(dirA);
var dirB = new THREE.DirectionalLight(0xffffff, 0.5);
dirB.position.set(-2, -1, 1);
scene.add(dirB);
var rimLight = new THREE.PointLight(0x4ec2e7, 0.8, 1);
rimLight.position.set(0, 0.05, 0.05);
scene.add(rimLight);

var mesh;
var mouseX = 0, mouseY = 0;
var targetX = 0, targetY = 0;

var buf = b64ToArrayBuffer(STL_B64);
var geo = parseBinarySTL(buf);
geo.computeBoundingBox();
var box = geo.boundingBox;
var cx = (box.max.x + box.min.x) / 2;
var cy = (box.max.y + box.min.y) / 2;
var cz = (box.max.z + box.min.z) / 2;
geo.translate(-cx, -cy, -cz);

var maxDim = Math.max(
box.max.x – box.min.x,
box.max.y – box.min.y,
box.max.z – box.min.z
);
var scale = 0.06 / maxDim;

var mat = new THREE.MeshPhongMaterial({
color: 0x4ec2e7,
emissive: 0x0a3040,
specular: 0xffffff,
shininess: 80,
side: THREE.DoubleSide
});

mesh = new THREE.Mesh(geo, mat);
mesh.scale.set(scale, scale, scale);
scene.add(mesh);

var hero = document.querySelector(‘.eao-hero’);
hero.addEventListener(‘mousemove’, function(e) {
var rect = hero.getBoundingClientRect();
mouseX = ((e.clientX – rect.left) / rect.width – 0.5) * 2;
mouseY = ((e.clientY – rect.top) / rect.height – 0.5) * 2;
});
hero.addEventListener(‘mouseleave’, function() {
mouseX = 0; mouseY = 0;
});

var autoRotY = 0;
function animate() {
requestAnimationFrame(animate);
autoRotY += 0.005;
targetX += (mouseY * 0.6 – targetX) * 0.05;
targetY += (mouseX * 0.6 – targetY) * 0.05;
if (mesh) {
mesh.rotation.x = targetX;
mesh.rotation.y = autoRotY + targetY;
}
renderer.render(scene, camera);
}
animate();
})();