mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-11 12:23:20 +00:00
Typescript + Vuejs
This commit is contained in:
1 parent
adabd2b588
commit
0bebea4a0e
14 files changed
+324
-28
No files matched your search
@@ -44,6 +44,11 @@ Scaling
|
||||
4. Prevent others from calling it
|
||||
5. Caching strategy
|
||||
|
||||
Hardening
|
||||
1. Reduce API surface
|
||||
2. Limit length of input sentences
|
||||
3. Rate limiting
|
||||
|
||||
Presentation
|
||||
- Better frontend UI
|
||||
- Testing page (current frontend)
|
||||
|
||||
@@ -11,6 +11,7 @@ rsync -utrv dictionary bt@jungle.horse:/home/bt/dev/trumpet
|
||||
rsync -utrv config.toml bt@jungle.horse:/home/bt/dev/trumpet
|
||||
|
||||
# Frontend
|
||||
rsync -utrv web/images bt@jungle.horse:/home/bt/dev/trumpet/web
|
||||
rsync -utrv web/*css bt@jungle.horse:/home/bt/dev/trumpet/web
|
||||
rsync -utrv web/*html bt@jungle.horse:/home/bt/dev/trumpet/web
|
||||
pushd frontend
|
||||
|
||||
@@ -6,6 +6,7 @@ banjo-tooie
|
||||
batshit
|
||||
charizard
|
||||
crafted
|
||||
derping
|
||||
dipshit
|
||||
fam
|
||||
fearmongers
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) 2016 Brandon Thomas <bt@brand.io, echelon@gmail.com>
|
||||
|
||||
import PIXI = require('pixi.js');
|
||||
|
||||
// TODO: Clean up this abysmal garbage.
|
||||
export function setup_animation() {
|
||||
//let renderer = new PIXI.WebGLRenderer(800, 470);
|
||||
let renderer = PIXI.autoDetectRenderer(800, 470);
|
||||
renderer.backgroundColor = 0xffffff;
|
||||
|
||||
document.getElementById('animation').appendChild(renderer.view);
|
||||
|
||||
let stage = new PIXI.Container();
|
||||
|
||||
let asset: any = null;
|
||||
let logo: any = null;
|
||||
|
||||
(<any>window).animationState = null;
|
||||
let blinkingStart = null;
|
||||
let talkingStart = null;
|
||||
let start = null;
|
||||
let curFrame = 0;
|
||||
|
||||
function animate() {
|
||||
// start the timer for the next animation loop
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
if ((<any>window).animationState === 'blinking') {
|
||||
if (blinkingStart == null) {
|
||||
blinkingStart = window.performance.now();
|
||||
curFrame = 0;
|
||||
} else {
|
||||
let delta = window.performance.now() - blinkingStart;
|
||||
if (delta > 200) {
|
||||
curFrame = 0;
|
||||
blinkingStart = null;
|
||||
(<any>window).animationState = null;
|
||||
} else if (delta > 150) {
|
||||
curFrame = 4;
|
||||
} else if (delta > 60) {
|
||||
curFrame = 3;
|
||||
} else if (delta > 20) {
|
||||
curFrame = 2;
|
||||
} else if (delta > 10) {
|
||||
curFrame = 1;
|
||||
}
|
||||
}
|
||||
} else if ((<any>window).animationState === 'talking') {
|
||||
if (talkingStart == null) {
|
||||
talkingStart = window.performance.now();
|
||||
curFrame = 5;
|
||||
} else {
|
||||
let delta = window.performance.now() - talkingStart;
|
||||
if (delta > 550) {
|
||||
curFrame = 5;
|
||||
talkingStart = null;
|
||||
//(<any>window).animationState = null;
|
||||
} else if (delta > 580) {
|
||||
curFrame = 6;
|
||||
} else if (delta > 540) {
|
||||
curFrame = 7;
|
||||
} else if (delta > 500) {
|
||||
curFrame = 8;
|
||||
} else if (delta > 460) {
|
||||
curFrame = 9;
|
||||
} else if (delta > 420) {
|
||||
curFrame = 10;
|
||||
} else if (delta > 400) {
|
||||
curFrame = 11;
|
||||
} else if (delta > 360) {
|
||||
curFrame = 12;
|
||||
} else if (delta > 320) {
|
||||
curFrame = 13;
|
||||
} else if (delta > 280) {
|
||||
curFrame = 12;
|
||||
} else if (delta > 240) {
|
||||
curFrame = 11;
|
||||
} else if (delta > 200) {
|
||||
curFrame = 10;
|
||||
} else if (delta > 160) {
|
||||
curFrame = 9;
|
||||
} else if (delta > 120) {
|
||||
curFrame = 8;
|
||||
} else if (delta > 80) {
|
||||
curFrame = 7;
|
||||
} else if (delta > 40) {
|
||||
curFrame = 6;
|
||||
}
|
||||
}
|
||||
} else if ((<any>window).animationState === 'stop_talking') {
|
||||
if (curFrame > 13 || curFrame < 5) {
|
||||
(<any>window).animationState = null;
|
||||
curFrame = 0;
|
||||
} else {
|
||||
if (start == null) {
|
||||
start = window.performance.now();
|
||||
}
|
||||
let delta = window.performance.now() - start;
|
||||
if (delta > 40) {
|
||||
curFrame -= 1;
|
||||
start = window.performance.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asset.gotoAndStop(curFrame);
|
||||
|
||||
// this is the main render call that makes pixi draw your container and its children.
|
||||
renderer.render(stage);
|
||||
}
|
||||
|
||||
let idleImages = [
|
||||
'/assets/images/trumpette/idle_0.png', // 0
|
||||
'/assets/images/trumpette/idle_1.png', // 1
|
||||
'/assets/images/trumpette/idle_2.png', // 2
|
||||
'/assets/images/trumpette/idle_3.png', // 3
|
||||
'/assets/images/trumpette/idle_4.png', // 4
|
||||
];
|
||||
|
||||
let talkImages = [
|
||||
'/assets/images/trumpette/talk_0.png', // 5
|
||||
'/assets/images/trumpette/talk_1.png', // 6
|
||||
'/assets/images/trumpette/talk_2.png', // 7
|
||||
'/assets/images/trumpette/talk_3.png', // 8
|
||||
'/assets/images/trumpette/talk_4.png', // 9
|
||||
'/assets/images/trumpette/talk_5.png', // 10
|
||||
'/assets/images/trumpette/talk_6.png', // 11
|
||||
'/assets/images/trumpette/talk_7.png', // 12
|
||||
'/assets/images/trumpette/talk_8.png', // 13
|
||||
];
|
||||
|
||||
let idleTextures = [];
|
||||
|
||||
for (let image of idleImages) {
|
||||
let texture = PIXI.Texture.fromImage(image);
|
||||
idleTextures.push(texture);
|
||||
}
|
||||
|
||||
for (let image of talkImages) {
|
||||
let texture = PIXI.Texture.fromImage(image);
|
||||
idleTextures.push(texture);
|
||||
}
|
||||
|
||||
logo = new PIXI.Text('Jungle Horse',
|
||||
{font: '150px Impact Bold', fill: 0x000000, align: 'center'});
|
||||
|
||||
PIXI.loader.add('asset', '/assets/images/trumpette/idle_0.png')
|
||||
.load(function (loader, resources) {
|
||||
// This creates a texture from a 'asset.png' image.
|
||||
//asset = new PIXI.Sprite(resources.asset.texture);
|
||||
asset = new PIXI.extras.MovieClip(idleTextures);
|
||||
|
||||
// Setup the position and scale of the asset
|
||||
asset.position.x = 200;
|
||||
asset.position.y = 0;
|
||||
|
||||
asset.scale.x = 0.5;
|
||||
asset.scale.y = 0.5;
|
||||
|
||||
logo.position.y = 260;
|
||||
|
||||
// Add the asset to the scene we are building.
|
||||
stage.addChild(logo);
|
||||
stage.addChild(asset);
|
||||
|
||||
asset.play();
|
||||
// kick off the animation loop (defined below)
|
||||
animate();
|
||||
});
|
||||
|
||||
blinkAnimation();
|
||||
}
|
||||
|
||||
export function talk() {
|
||||
(<any>window).animationState = 'talking';
|
||||
}
|
||||
|
||||
export function stopTalking() {
|
||||
(<any>window).animationState = 'stop_talking';
|
||||
}
|
||||
|
||||
function blink() {
|
||||
(<any>window).animationState = 'blinking';
|
||||
}
|
||||
|
||||
function blinkAnimation() {
|
||||
if ((<any>window).animationState == null) {
|
||||
(<any>window).animationState = 'blinking';
|
||||
}
|
||||
let nextBlink = getRandomInt(1000, 4000);
|
||||
setTimeout(blinkAnimation, nextBlink);
|
||||
}
|
||||
|
||||
function getRandomInt(min: number, max: number) : number {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
declare var buzz: any; // TODO: static types.
|
||||
|
||||
import { talk, stopTalking } from "./animation";
|
||||
|
||||
export default class Audio {
|
||||
sound: any;
|
||||
|
||||
@@ -13,6 +15,15 @@ export default class Audio {
|
||||
this.stop();
|
||||
this.sound = new buzz.sound(url);
|
||||
this.sound.play();
|
||||
|
||||
this.sound.bind('play playing', function() {
|
||||
talk(); // UI
|
||||
});
|
||||
|
||||
|
||||
this.sound.bind('ended pause', function() {
|
||||
stopTalking(); // UI
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
||||
+22
-5
@@ -1,19 +1,36 @@
|
||||
// Copyright (c) 2016 Brandon Thomas <bt@brand.io, echelon@gmail.com>
|
||||
|
||||
/// <reference path='./typings/tsd.d.ts' />
|
||||
|
||||
import Vue = require('vue');
|
||||
|
||||
declare var $: any;
|
||||
|
||||
import { setup_animation } from "./animation";
|
||||
import Audio from "./audio";
|
||||
import { decode_url_hash, get_audio_api_url, set_url_hash } from "./url";
|
||||
import { RawSentence, FilteredSentence } from "./sentence";
|
||||
|
||||
const INPUT = 'input#jungle';
|
||||
|
||||
/*(<any>window).V = new Vue({
|
||||
el: '#image-box',
|
||||
data: {
|
||||
content: 'foo',
|
||||
},
|
||||
});*/
|
||||
|
||||
$(function() {
|
||||
console.log('installing...');
|
||||
window.audio = new Audio();
|
||||
(<any>window).audio = new Audio();
|
||||
install_events();
|
||||
initialize_from_url();
|
||||
focus();
|
||||
|
||||
if ($('#animation').length > 0) {
|
||||
// Only install animation if the page supports it.
|
||||
setup_animation();
|
||||
}
|
||||
});
|
||||
|
||||
function install_events() {
|
||||
@@ -25,7 +42,7 @@ function install_events() {
|
||||
set_url_hash(filtered);
|
||||
|
||||
let url = get_audio_api_url(filtered);
|
||||
window.audio.playUrl(url);
|
||||
(<any>window).audio.playUrl(url);
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
@@ -36,7 +53,7 @@ function install_events() {
|
||||
// ESC key.
|
||||
focus();
|
||||
$(INPUT).val('');
|
||||
window.audio.stop();
|
||||
(<any>window).audio.stop();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,7 +62,7 @@ function install_events() {
|
||||
|
||||
if (ev.keyCode === 27) {
|
||||
$(INPUT).val(''); // ESC key.
|
||||
window.audio.stop();
|
||||
(<any>window).audio.stop();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -57,7 +74,7 @@ function install_events() {
|
||||
|
||||
$('button#clear').on('click', function(ev: any): any {
|
||||
$(INPUT).val(''); // ESC key.
|
||||
window.audio.stop();
|
||||
(<any>window).audio.stop();
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
"dependencies": {
|
||||
"bower": "^1.7.9",
|
||||
"jquery": "^3.0.0",
|
||||
"pixi.js": "^4.1.0",
|
||||
"ts-loader": "^0.8.2",
|
||||
"typescript": "^1.8.10",
|
||||
"vue": "^1.0.28",
|
||||
"wavesurfer.js": "^1.1.12"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"filesGlob": [
|
||||
"./**/*.ts",
|
||||
"!./node_modules/**/*.ts"
|
||||
],
|
||||
"files": [
|
||||
"./main.ts",
|
||||
"./typings/pixi.js/pixi.js.d.ts",
|
||||
"./typings/tsd.d.ts",
|
||||
"./typings/vue/vue.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -7,6 +7,12 @@
|
||||
"installed": {
|
||||
"jquery/jquery.d.ts": {
|
||||
"commit": "73110d92bdab2367e326f297bef3574285cba329"
|
||||
},
|
||||
"vue/vue.d.ts": {
|
||||
"commit": "3cc599268d2dabe3c3ee194e92965ee87440e9c3"
|
||||
},
|
||||
"pixi.js/pixi.js.d.ts": {
|
||||
"commit": "3cc599268d2dabe3c3ee194e92965ee87440e9c3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"globalDependencies": {
|
||||
"vue": "registry:dt/vue#1.0.21+20160929090511"
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -22,10 +22,10 @@ export function set_url_hash(sentence: FilteredSentence) {
|
||||
urlHash = '';
|
||||
|
||||
if (!json) {
|
||||
urlHash = new URI('/').hash('').toString();
|
||||
urlHash = new URI('').hash('').toString();
|
||||
} else {
|
||||
let uriEncoded = encodeURIComponent(json);
|
||||
urlHash = new URI('/').hash(uriEncoded).toString();
|
||||
urlHash = new URI('').hash(uriEncoded).toString();
|
||||
}
|
||||
|
||||
window.history.replaceState(null, null, urlHash);
|
||||
|
||||
@@ -23,6 +23,19 @@ h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#animation canvas {
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#logo {
|
||||
display: none;
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#image-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
+36
-16
@@ -1,28 +1,48 @@
|
||||
img#trump {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
@media screen and (min-height: 600px) {
|
||||
img#trump {
|
||||
height: 400px;
|
||||
@media screen and (min-width: 1px) {
|
||||
#animation canvas {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-height: 800px) {
|
||||
img#trump {
|
||||
height: 500px;
|
||||
@media screen and (min-width: 300px) {
|
||||
#animation canvas {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-height: 1000px) {
|
||||
img#trump {
|
||||
height: 700px;
|
||||
@media screen and (min-width: 400px) {
|
||||
#animation canvas {
|
||||
width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-height: 1500px) {
|
||||
img#trump {
|
||||
height: 1000px;
|
||||
@media screen and (min-width: 450px) {
|
||||
#animation canvas {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 500px) {
|
||||
#animation canvas {
|
||||
width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
#animation canvas {
|
||||
width: 600px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 800px) {
|
||||
#animation canvas {
|
||||
width: 800px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1000px) {
|
||||
#animation canvas {
|
||||
width: 800px;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -10,12 +10,15 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Fira+Sans|Open+Sans" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="animation"></div>
|
||||
<div id="logo">
|
||||
<h1>Text to Trump</h1>
|
||||
</div>
|
||||
<div id="main">
|
||||
<h1>Jungle Horse</h1>
|
||||
|
||||
<div id="image-box">
|
||||
<img id="trump" src="/assets/images/trump_jon.png">
|
||||
</div>
|
||||
<!--<div id="image-box">
|
||||
{{ content }}
|
||||
</div>-->
|
||||
|
||||
<form>
|
||||
<div id="input-box">
|
||||
@@ -32,7 +35,8 @@
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<script src="/assets/output/libraries.js"/></script>
|
||||
<script src="/assets/output/main.built.js"/></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user