Implement companion styling and animations

This commit is contained in:
Dennis Schoepf 2021-07-19 00:07:13 +02:00
parent ab372d6627
commit 7cec5fa2fb
9 changed files with 236 additions and 1 deletions

View file

@ -1,12 +1,15 @@
import create from 'zustand/vanilla';
import { Scenes } from './scenes/scenes';
import { CompanionState } from './ui/companion';
export interface State {
currentScene: Scenes;
companionState: CompanionState;
}
const store = create<State>(() => ({
currentScene: Scenes.OVERVIEW,
companionState: CompanionState.IDLE,
}));
export default store;

131
src/ui/companion.ts Normal file
View file

@ -0,0 +1,131 @@
import anime from 'animejs/lib/anime.es';
import { reject } from 'core-js/fn/promise';
import store from '../store';
export enum CompanionState {
IDLE = 'IDLE',
AWAIT = 'AWAIT',
ACTIVE = 'ACTIVE',
SUCCESS = 'SUCCESS',
}
export class Companion {
ref: HTMLElement;
hoverAnimation: any;
constructor() {
this.ref = document.getElementById('companion');
this.ref.addEventListener('click', () => this.handleClick());
this.ref.addEventListener('mouseover', () => this.handleMouseEnter());
this.ref.addEventListener('mouseleave', () => this.handleMouseLeave());
store.subscribe(
(companionState) => {
if (companionState === CompanionState.ACTIVE) {
this.showActiveShape();
this.scaleUpCompanion();
this.pupilFollowCursor();
} else if (companionState === CompanionState.IDLE) {
this.scaleDownCompanion();
this.showIdleShape();
} else if (companionState === CompanionState.AWAIT) {
this.playAwaitAnimation();
} else if (companionState === CompanionState.SUCCESS) {
this.playSuccessAnimation();
this.scaleDownCompanion();
this.showIdleShape();
}
},
(state) => state.companionState
);
}
showActiveShape() {
const mouth = document.getElementById('companion-mouth');
mouth.style.opacity = '100%';
anime({
targets: '#companion-shape polygon',
points: [{ value: '40,0 68,12 80,40 80,75 40,80 0,75 0,40 12,12' }],
easing: 'easeOutQuad',
duration: 500,
loop: false,
});
}
showIdleShape() {
const mouth = document.getElementById('companion-mouth');
mouth.style.opacity = '0%';
anime({
targets: '#companion-shape polygon',
points: [{ value: '40,0 68,12 80,40 68,68 40,80 12,68 0,40 12,12' }],
easing: 'easeOutQuad',
duration: 500,
loop: false,
});
}
scaleUpCompanion() {
anime({
targets: '#companion',
scale: 3,
translateX: -15,
translateY: -12,
loop: false,
duration: 700,
});
}
scaleDownCompanion() {
anime({
targets: '#companion',
scale: 1,
loop: false,
translateX: 0,
translateY: 0,
duration: 800,
});
}
playSuccessAnimation() {}
playAwaitAnimation() {}
pupilFollowCursor() {
document.addEventListener('mousemove', (e) => {
const pupil = document.getElementById('companion-pupil');
const pupDim = pupil.getBoundingClientRect();
pupil.style.transform = `translate(${-((pupDim.x - e.pageX) * 0.005)}px, ${-(
(pupDim.y - e.pageY) *
0.015
)}px)`;
});
}
handleClick() {
const { companionState } = store.getState();
let newCompanionState: CompanionState;
if (companionState === CompanionState.ACTIVE) {
newCompanionState = CompanionState.IDLE;
} else {
newCompanionState = CompanionState.ACTIVE;
}
store.setState({ companionState: newCompanionState });
}
handleMouseEnter() {
this.showActiveShape();
}
handleMouseLeave() {
const { companionState } = store.getState();
if (companionState !== CompanionState.ACTIVE) {
this.showIdleShape();
}
}
}