Skip to content

Instantly share code, notes, and snippets.

@luruke
Last active October 25, 2019 07:24
Show Gist options
  • Save luruke/71d199c1254799abbabcad6854f6b0c7 to your computer and use it in GitHub Desktop.
Save luruke/71d199c1254799abbabcad6854f6b0c7 to your computer and use it in GitHub Desktop.
// Button DOM
<a href="#" data-component="trackable" data-type="button">Yo, button</a>
// Trackable kapla component (https://github.com/thierrymichel/kapla)
// Using it just to track when some dom is "mounted/unmounted"
import { Component } from 'kapla';
import dom from 'gl/dom';
export default class extends Component {
init() {
dom.register(this.$el);
}
destroy() {
dom.unregister(this.$el);
}
}
// dom.js
// Makes sure to load the correct type of "3D element" based on DOM `data-type`
import Button from './button/button';
import Person from './person/person';
import Cover from './cover/cover';
import Footer from './footer/footer';
import Datep from './date/date';
import Placeholder from './placeholder/placeholder';
import Line from './line/line';
import Listhover from './listhover/listhover';
import Glitch from './glitch/glitch';
import Image from './image/image';
const elements = {
button: Button,
person: Person,
cover: Cover,
footer: Footer,
date: Datep,
placeholder: Placeholder,
line: Line,
listhover: Listhover,
glitch: Glitch,
image: Image,
};
class Dom {
constructor() {
this.id = 0;
this.instances = {};
}
register(el) {
const id = `id_${this.id++}`;
el.dataset.glid = id;
const type = el.dataset.type || 'button';
const instance = new elements[type](el);
this.instances[id] = instance;
el.classList.add('gl');
}
getInstanceFromEl(el) {
return this.instances[el.dataset.glid];
}
unregister(el) {
const instance = this.getInstanceFromEl(el);
el.classList.remove('gl');
instance.destroy();
}
}
export default new Dom();
// button.js
// That's our three.js "object"
import {
Mesh,
PlaneBufferGeometry,
RawShaderMaterial,
} from 'three';
import dom3D from '../dom3D';
import scene from '../scene';
import textures from 'gl/utils/textures';
const geometry = new PlaneBufferGeometry(1, 1, 1, 1);
const material = new RawShaderMaterial({
transparent: true,
fragmentShader: require('./button.frag'),
vertexShader: require('./button.vert'),
});
export default class extends dom3D {
init() {
super.init();
this.geometry = geometry;
this.material = material.clone();
this.material.uniforms = {
uTime: { value: 0 },
uProgress: { value: 0 },
uWind: { value: textures.fromAsset('wind') },
uShow: { value: 0 },
uClipping: { value: 1.0 }
};
this.mesh = new Mesh(this.geometry, this.material);
this.add(this.mesh);
scene.add(this);
}
onRaf({ delta }) {
super.onRaf();
this.material.uniforms.uTime.value += delta * 0.1;
}
}
// dom3D.js
// Where the "magic happens", calculate the size and position
// converting the 2D DOM coordinates to the PerspectiveCamera
import { Object3D } from 'three';
import { component } from 'bidello';
import { viewport, scroll } from './bidello';
import camera from './camera';
export default class extends component(Object3D) {
init() {
this.element = this._args[0];
}
onResize() {
if (!this.element) {
return;
}
const rect = this.element.getBoundingClientRect();
this.bounds = {
left: rect.left,
top: rect.top,
width: rect.width,
height: rect.height,
};
this.updateSize();
this.updatePosition();
}
updateSize() {
this.camUnit = camera.calculateUnitSize(camera.position.z - this.position.z);
/*
calculateUnitSize(distance = this.position.z) {
const vFov = this.fov * Math.PI / 180;
const height = 2 * Math.tan(vFov / 2) * distance;
const width = height * this.aspect;
return {
width,
height
};
}
*/
// Set size
const x = this.bounds.width / viewport.width;
const y = this.bounds.height / viewport.height;
if (!x || !y) {
return;
}
this.scale.x = this.camUnit.width * x;
this.scale.y = this.camUnit.height * y;
}
updatePosition(pos = scroll.y) {
const y = pos;
// Set origin to top left
this.position.x = -(this.camUnit.width / 2) + (this.scale.x / 2);
this.position.y = (this.camUnit.height / 2) - (this.scale.y / 2);
// Set position
this.position.x += (this.bounds.left / viewport.width) * this.camUnit.width;
this.position.y -= ((this.bounds.top - y) / viewport.height) * this.camUnit.height;
}
onRaf() {
this.updatePosition(scroll.easeY);
}
destroy() {
this.parent && this.parent.remove(this);
this.visible = false;
super.destroy();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment