diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..c2c009d3e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+# Logs
+logs
+*.log
+
+#Ignore our built files
+build/*
+architecture.json
+
+# Ignore sensitive stuff
+/config/*
+!/config/default.json
+
+node_modules
\ No newline at end of file
diff --git a/client/naturalCrit/monsterCard/attackSlot/attackSlot.jsx b/client/naturalCrit/monsterCard/attackSlot/attackSlot.jsx
new file mode 100644
index 000000000..e68678aa5
--- /dev/null
+++ b/client/naturalCrit/monsterCard/attackSlot/attackSlot.jsx
@@ -0,0 +1,118 @@
+var React = require('react');
+var _ = require('lodash');
+var cx = require('classnames');
+
+var AttackSlot = React.createClass({
+ getDefaultProps: function() {
+ return {
+ name : '',
+ uses : null
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ lastRoll: {},
+ usedCount : 0
+ };
+ },
+
+ rollDice : function(key, notation){
+ var additive = 0;
+ var dice = _.reduce([/\+(.*)/, /\-(.*)/], function(r, regexp){
+ var res = r.match(regexp);
+ if(res){
+ additive = res[0]*1;
+ r = r.replace(res[0], '')
+ }
+ return r;
+ }, notation)
+
+ var numDice = dice.split('d')[0];
+ var die = dice.split('d')[1];
+
+ var diceRoll = _.times(numDice, function(){
+ return _.random(1, die);
+ });
+ var res = _.sum(diceRoll) + additive;
+ if(numDice == 1 && die == 20){
+ if(diceRoll[0] == 1) res = 'Fail!';
+ if(diceRoll[0] == 20) res = 'Crit!';
+ }
+ this.state.lastRoll[key] = res
+ this.setState({
+ lastRoll : this.state.lastRoll
+ })
+ },
+
+ renderUses : function(){
+ var self = this;
+ if(!this.props.uses) return null;
+
+ return _.times(this.props.uses, function(index){
+ var atCount = index < self.state.usedCount;
+ return
+ })
+ },
+ updateCount : function(used){
+ this.setState({
+ usedCount : this.state.usedCount + (used ? -1 : 1)
+ });
+ },
+
+ renderNotes : function(){
+ var notes = _.omit(this.props, ['name', 'atk', 'dmg', 'uses', 'heal']);
+ return _.map(notes, function(text, key){
+ return key + ': ' + text
+ }).join(', ');
+ },
+
+ renderRolls : function(){
+ var self = this;
+
+ return _.map(['atk', 'dmg', 'heal'], function(type){
+ if(!self.props[type]) return null;
+ return
+
+
+ {self.state.lastRoll[type] || ''}
+
+ })
+
+ },
+
+
+ render : function(){
+ var self = this;
+ return(
+
+
+
{this.props.name}
+
+ {this.renderUses()}
+
+
+ {this.renderNotes()}
+
+
+
+
+ {this.renderRolls()}
+
+
+ );
+ }
+});
+
+module.exports = AttackSlot;
diff --git a/client/naturalCrit/monsterCard/attackSlot/attackSlot.less b/client/naturalCrit/monsterCard/attackSlot/attackSlot.less
new file mode 100644
index 000000000..fae4b9133
--- /dev/null
+++ b/client/naturalCrit/monsterCard/attackSlot/attackSlot.less
@@ -0,0 +1,67 @@
+
+.attackSlot{
+ //border : 1px solid black;
+ border-bottom: 1px solid #eee;
+ margin-bottom : 5px;
+ font-size : 0.8em;
+ .info, .rolls{
+ display : inline-block;
+ vertical-align : top;
+ }
+ .info{
+ width : 40%;
+ .name{
+ font-weight : 800;
+ }
+ .notes{
+ font-size : 0.8em;
+ }
+ .uses{
+ cursor : pointer;
+ }
+ }
+ .rolls{
+ .roll{
+ margin-bottom : 2px;
+ span{
+ font-weight: 800;
+ }
+ button{
+ width : 70px;
+ margin-right : 5px;
+ cursor : pointer;
+ font-size : 0.7em;
+ font-weight : 800;
+ text-align : left;
+ border : none;
+ outline : 0;
+ i{
+ width : 15px;
+ margin-right : 5px;
+ border-right : 1px solid white;
+ }
+ &:hover{
+ //text-align: right;
+ }
+ }
+ &.atk{
+ button{
+ background-color : fade(@blue, 40%);
+ i { border-color: @blue}
+ }
+ }
+ &.dmg{
+ button{
+ background-color : fade(@red, 40%);
+ i { border-color: @red}
+ }
+ }
+ &.heal{
+ button{
+ background-color : fade(@green, 40%);
+ i { border-color: @green}
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/client/naturalCrit/monsterCard/monsterCard.jsx b/client/naturalCrit/monsterCard/monsterCard.jsx
new file mode 100644
index 000000000..fd9fb8706
--- /dev/null
+++ b/client/naturalCrit/monsterCard/monsterCard.jsx
@@ -0,0 +1,183 @@
+var React = require('react');
+var _ = require('lodash');
+var cx = require('classnames');
+
+var AttackSlot = require('./attackSlot/attackSlot.jsx');
+
+var MonsterCard = React.createClass({
+ getDefaultProps: function() {
+ return {
+ name : '',
+ hp : 1,
+ currentHP : 1,
+ ac: 1,
+ move : 30,
+ attr : {
+ str : 8,
+ con : 8,
+ dex : 8,
+ int : 8,
+ wis : 8,
+ cha : 8
+ },
+ attacks : {},
+ spells : {},
+ abilities : [],
+ items : [],
+
+ updateHP : function(){},
+ remove : function(){},
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ //currentHP: this.props.hp,
+ status : 'normal',
+ usedThings : [],
+
+ lastRoll : {
+
+ },
+
+
+ mousePos : null,
+ tempHP : 0
+ };
+ },
+
+ componentDidMount: function() {
+ window.addEventListener('mousemove', this.handleMouseDrag);
+ window.addEventListener('mouseup', this.handleMouseUp);
+ },
+
+ handleMouseDown : function(e){
+ this.setState({
+ mousePos : {
+ x : e.pageX,
+ y : e.pageY,
+ }
+ });
+ e.stopPropagation()
+ e.preventDefault()
+ },
+ handleMouseUp : function(e){
+ if(!this.state.mousePos) return;
+
+
+ this.props.updateHP(this.props.currentHP + this.state.tempHP);
+ this.setState({
+ mousePos : null,
+ tempHP : 0
+ });
+ },
+
+ handleMouseDrag : function(e){
+ if (!this.state.mousePos) return;
+ var distance = Math.sqrt(Math.pow(e.pageX - this.state.mousePos.x, 2) + Math.pow(e.pageY - this.state.mousePos.y, 2));
+ var mult = (e.pageY > this.state.mousePos.y ? -1 : 1)
+
+ this.setState({
+ tempHP : Math.floor(distance * mult/25)
+ })
+ },
+
+
+ renderHPBox : function(){
+
+ var tempHP
+ if(this.state.tempHP){
+ var sign = (this.state.tempHP > 0 ? '+' : '');
+ tempHP = {['(',sign,this.state.tempHP,')'].join('')}
+ }
+
+ return
+
+ {tempHP} {this.props.currentHP}
+
+
{this.props.hp}
+
+ },
+
+ renderStats : function(){
+
+ },
+
+
+ rollDice : function(key, notation){
+ var additive = 0;
+ var dice = _.reduce([/\+(.*)/, /\-(.*)/], function(r, regexp){
+ var res = r.match(regexp);
+ if(res){
+ additive = res[0]*1;
+ r = r.replace(res[0], '')
+ }
+ return r;
+ }, notation)
+
+ var numDice = dice.split('d')[0];
+ var die = dice.split('d')[1];
+
+ var diceRoll = _.times(numDice, function(){
+ return _.random(1, die);
+ });
+ var res = _.sum(diceRoll) + additive;
+ if(numDice == 1 && die == 20){
+ if(diceRoll[0] == 1) res = 'Fail!';
+ if(diceRoll[0] == 20) res = 'Crit!';
+ }
+ this.state.lastRoll[key] = res
+ this.setState({
+ lastRoll : this.state.lastRoll
+ })
+ },
+
+
+ renderAttacks : function(){
+ var self = this;
+ return _.map(this.props.attacks, function(attack, name){
+ return
+ })
+ },
+
+ renderSpells : function(){
+ var self = this;
+ return _.map(this.props.spells, function(spell, name){
+ return
+ })
+ },
+
+ render : function(){
+ var self = this;
+
+ var condition = ''
+ if(this.props.currentHP + this.state.tempHP > this.props.hp) condition='overhealed';
+ if(this.props.currentHP + this.state.tempHP <= this.props.hp * 0.5) condition='hurt';
+ if(this.props.currentHP + this.state.tempHP <= this.props.hp * 0.2) condition='last_legs';
+ if(this.props.currentHP + this.state.tempHP <= 0) condition='dead';
+
+
+ return(
+
+
+
+
+
+ {this.renderHPBox()}
+
{this.props.name}
+
+
+ {this.renderAttacks()}
+
+
+ {this.renderSpells()}
+
+ {this.props.initiative}
+
+
+
+ );
+ }
+});
+
+module.exports = MonsterCard;
diff --git a/client/naturalCrit/monsterCard/monsterCard.less b/client/naturalCrit/monsterCard/monsterCard.less
new file mode 100644
index 000000000..f3850b8ad
--- /dev/null
+++ b/client/naturalCrit/monsterCard/monsterCard.less
@@ -0,0 +1,77 @@
+
+.noselect(){
+ -webkit-touch-callout : none;
+ -webkit-user-select : none;
+ -khtml-user-select : none;
+ -moz-user-select : none;
+ -ms-user-select : none;
+ user-select : none;
+}
+.monsterCard{
+ position : relative;
+ display : inline-block;
+ vertical-align : top;
+ box-sizing : border-box;
+ width : 250px;
+ margin : 30px;
+ padding : 10px;
+ background-color : white;
+ border : 1px solid #bbb;
+ .healthbar{
+ position : absolute;
+ top : 0px;
+ left : 0px;
+ height : 3px;
+ max-width : 100%;
+ background-color : @green;
+ z-index : 50;
+ }
+ .overhealbar{
+ position : absolute;
+ top : 0px;
+ left : 0px;
+ height : 3px;
+ max-width : 100%;
+ background-color : @blueLight;
+ z-index : 100;
+ }
+ &.hurt{
+ .healthbar{
+ background-color : orange;
+ }
+ }
+ &.last_legs{
+ background-color: lighten(@red, 49%);
+ .healthbar{
+ background-color : red;
+ }
+ }
+ &.dead{
+ opacity: 0.3;
+ }
+ .hpBox{
+ .noselect();
+ position : absolute;
+ top : 5px;
+ right : 5px;
+ cursor : pointer;
+ text-align : right;
+ .currentHP{
+ font-size : 2em;
+ font-weight : 800;
+ line-height : 0.8em;
+ .tempHP{
+ vertical-align : top;
+ font-size : 0.4em;
+ line-height : 0.8em;
+ }
+ }
+ .maxHP{
+ font-size : 0.8em;
+ }
+ .hpText{
+ font-size : 0.6em;
+ font-weight : 800;
+ }
+ }
+}
\ No newline at end of file
diff --git a/client/naturalCrit/naturalCrit.jsx b/client/naturalCrit/naturalCrit.jsx
new file mode 100644
index 000000000..dc4c66c84
--- /dev/null
+++ b/client/naturalCrit/naturalCrit.jsx
@@ -0,0 +1,155 @@
+var React = require('react');
+var _ = require('lodash');
+var cx = require('classnames');
+
+var MonsterCard = require('./monsterCard/monsterCard.jsx');
+
+
+var encounter = {
+
+ name : 'The Big Bad',
+ enemies : ['goblin', 'goblin'],
+ reserve : ['goblin'],
+
+}
+
+var MonsterManual = {
+ 'goblin' : {
+ "hp" : 40,
+ "mov": 30,
+ "attr" : {
+ "str" : 8,
+ "con" : 8,
+ "dex" : 8,
+ "int" : 8,
+ "wis" : 8,
+ "cha" : 8
+ },
+ "attacks" : {
+ "dagger" : {
+ "atk" : "1d20-5",
+ "dmg" : "1d4+5",
+ "type" : "pierce",
+ "notes" : "Super cool"
+ },
+ "bow" : {
+ "atk" : "1d20+2",
+ "dmg" : "6d6",
+ "rng" : "30"
+ }
+ },
+ "spells" : {
+ "fireball": {
+ "dmg" : "6d6",
+ "uses" : 4
+ },
+ "healing_bolt" : {
+ "heal" : "2d8+4",
+ "uses" : 6
+ }
+ },
+ "abilities" : ["pack tactics"],
+ "items" : []
+ }
+}
+
+var attrMod = function(attr){
+ return Math.floor(attr/2) - 5;
+}
+
+
+var NaturalCrit = React.createClass({
+
+ getInitialState: function() {
+ var self = this;
+
+ return {
+ enemies: _.indexBy(_.map(encounter.enemies, function(type, index){
+ return self.createEnemy(type, index)
+ }), 'id')
+ };
+ },
+
+ createEnemy : function(type, index){
+ var stats = MonsterManual[type]
+ return _.extend({
+ id : type + index,
+ name : type,
+ currentHP : stats.hp,
+ initiative : _.random(1,20) + attrMod(stats.attr.dex)
+ }, stats);
+ },
+
+ addPC : function(name, initiative){
+ this.state.enemies[name] = {
+ name : name,
+ id : name,
+ initiative : initiative,
+ isPC : true
+ };
+ this.setState({
+ enemies : this.state.enemies
+ })
+
+ },
+
+
+ addRandomPC : function(){
+ this.addPC(
+ _.sample(['zatch', 'jasper', 'el toro', 'tulik']) + _.random(1,1000),
+ _.random(1,25)
+ )
+ },
+
+
+ updateHP : function(enemyId, newHP){
+ this.state.enemies[enemyId].currentHP = newHP;
+ this.setState({
+ enemies : this.state.enemies
+ });
+ },
+ removeEnemy : function(enemyId){
+ delete this.state.enemies[enemyId];
+ this.setState({
+ enemies : this.state.enemies
+ });
+ },
+
+
+
+
+
+ render : function(){
+ var self = this;
+
+ console.log();
+
+ var sortedEnemies = _.sortBy(this.state.enemies, function(e){
+ return -e.initiative;
+ });
+
+
+ var cards = _.map(sortedEnemies, function(enemy){
+ return
+ })
+
+
+
+ return(
+
+
+ Project Ready!
+
+ {cards}
+
+ );
+ }
+});
+
+module.exports = NaturalCrit;
+
+
diff --git a/client/naturalCrit/naturalCrit.less b/client/naturalCrit/naturalCrit.less
new file mode 100644
index 000000000..40a6b2fd4
--- /dev/null
+++ b/client/naturalCrit/naturalCrit.less
@@ -0,0 +1,19 @@
+@import 'naturalCrit/reset.less';
+//@import 'naturalCrit/elements.less';
+@import 'naturalCrit/animations.less';
+@import 'naturalCrit/colors.less';
+
+body{
+ background-color : #eee;
+ font-family : 'Open Sans', sans-serif;
+ color : #4b5055;
+ font-weight : 100;
+ text-rendering : optimizeLegibility;
+ margin : 0;
+ padding : 0;
+}
+
+.naturalCrit{
+ color : #333;
+ background-color: #eee;
+}
\ No newline at end of file
diff --git a/client/template.dot b/client/template.dot
new file mode 100644
index 000000000..708c46e7c
--- /dev/null
+++ b/client/template.dot
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ {{=vitreum.css}}
+ {{=vitreum.globals}}
+ NaturalCrit
+
+
+ {{=vitreum.component}}
+
+ {{=vitreum.libs}}
+ {{=vitreum.js}}
+ {{=vitreum.reactRender}}
+
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 000000000..1e5864d4c
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,30 @@
+"use strict";
+
+var vitreumTasks = require("vitreum/tasks");
+var gulp = require("gulp");
+
+
+var gulp = vitreumTasks(gulp, {
+ entryPoints: ["./client/naturalCrit"],
+ DEV: true,
+
+ buildPath: "./build/",
+ pageTemplate: "./client/template.dot",
+
+ projectModules: ["./shared/naturalCrit"],
+ additionalRequirePaths : ['./shared'],
+ assetExts: ["*.svg", "*.png", "*.jpg", "*.pdf", "*.eot", "*.ttf", "*.woff", "*.woff2", "*.ico"],
+
+ serverWatchPaths: ["server"],
+ serverScript: "server.js",
+ libs: [
+ "react",
+ "react-dom",
+ "lodash",
+ "classnames",
+
+ ],
+ clientLibs: [],
+});
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..181abd469
--- /dev/null
+++ b/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "naturalCrit",
+ "description": "A super rad project!",
+ "version": "0.0.0",
+ "scripts": {
+ "postinstall": "gulp prod",
+ "start": "node server.js"
+ },
+ "author": "",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "app-module-path": "^1.0.4",
+ "classnames": "^2.2.0",
+ "express": "^4.13.3",
+ "gulp": "^3.9.0",
+ "lodash": "^3.10.1",
+ "react": "^0.14.2",
+ "react-dom": "^0.14.2",
+ "vitreum": "^3.1.1"
+ }
+}
diff --git a/server.js b/server.js
new file mode 100644
index 000000000..29179ba8d
--- /dev/null
+++ b/server.js
@@ -0,0 +1,30 @@
+'use strict';
+require('app-module-path').addPath('./shared');
+var vitreumRender = require('vitreum/render');
+var express = require("express");
+var app = express();
+app.use(express.static(__dirname + '/build'));
+
+
+
+
+app.get('*', function (req, res) {
+ vitreumRender({
+ page: './build/naturalCrit/bundle.dot',
+ globals:{
+
+ },
+ //prerenderWith : './client/naturalCrit/naturalCrit.jsx',
+ initialProps: {
+ url: req.originalUrl
+ },
+ clearRequireCache : true,
+ }, function (err, page) {
+ return res.send(page)
+ });
+});
+
+
+var port = process.env.PORT || 8000;
+app.listen(port);
+console.log('Listening on localhost:' + port);
\ No newline at end of file
diff --git a/server/Server files go here b/server/Server files go here
new file mode 100644
index 000000000..e69de29bb
diff --git a/shared/naturalCrit/animations.less b/shared/naturalCrit/animations.less
new file mode 100644
index 000000000..7857f559e
--- /dev/null
+++ b/shared/naturalCrit/animations.less
@@ -0,0 +1,421 @@
+//Defaults
+@defaultDuration : 0.25s;
+@defaultEasing : ease;
+
+//Animates all properties on an element
+.animateAll(@duration : @defaultDuration, @easing : @defaultEasing){
+ -webkit-transition: all @duration @easing;
+ -moz-transition: all @duration @easing;
+ -o-transition: all @duration @easing;
+ transition: all @duration @easing;
+}
+//Animates Specific property
+.animate(@prop, @duration : @defaultDuration, @easing : @defaultEasing){
+ -webkit-transition: @prop @duration @easing;
+ -moz-transition: @prop @duration @easing;
+ -o-transition: @prop @duration @easing;
+ transition: @prop @duration @easing;
+}
+
+.animateMany(...){
+ @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;
+ -webkit-transition-property: @value;
+ -moz-transition-property: @value;
+ -o-transition-property: @value;
+ transition-property: @value;
+
+ .animateDuration();
+ .animateEasing();
+}
+
+.animateDuration(@duration : @defaultDuration){
+ -webkit-transition-duration: @duration;
+ -moz-transition-duration: @duration;
+ -o-transition-duration: @duration;
+ transition-duration: @duration;
+}
+
+.animateEasing(@easing : @defaultEasing){
+ -webkit-transition-timing-function: @easing;
+ -moz-transition-timing-function: @easing;
+ -o-transition-timing-function: @easing;
+ transition-timing-function: @easing;
+}
+
+
+.transition (@prop, @duration: @defaultDuration) {
+ -webkit-transition: @prop @duration, -webkit-transform @duration;
+ -moz-transition: @prop @duration, -moz-transform @duration;
+ -o-transition: @prop @duration, -o-transform @duration;
+ -ms-transition: @prop @duration, -ms-transform @duration;
+ transition: @prop @duration, transform @duration;
+}
+.transform (@transform) {
+ -webkit-transform: @transform;
+ -moz-transform: @transform;
+ -o-transform: @transform;
+ -ms-transform: @transform;
+ transform: @transform;
+}
+
+
+.delay(@delay){
+ animation-delay:@delay;
+ -webkit-animation-delay:@delay;
+ transition-delay:@delay;
+ -webkit-transition-delay:@delay;
+}
+.keep(){
+ -webkit-animation-fill-mode:forwards;
+ -moz-animation-fill-mode:forwards;
+ -ms-animation-fill-mode:forwards;
+ -o-animation-fill-mode:forwards;
+ animation-fill-mode:forwards;
+}
+
+
+.sequentialDelay(@delayInc : 0.2s, @initialDelay : 0s){
+ &:nth-child(1){.delay(0*@delayInc + @initialDelay)}
+ &:nth-child(2){.delay(1*@delayInc + @initialDelay)}
+ &:nth-child(3){.delay(2*@delayInc + @initialDelay)}
+ &:nth-child(4){.delay(3*@delayInc + @initialDelay)}
+ &:nth-child(5){.delay(4*@delayInc + @initialDelay)}
+ &:nth-child(6){.delay(5*@delayInc + @initialDelay)}
+ &:nth-child(7){.delay(6*@delayInc + @initialDelay)}
+ &:nth-child(8){.delay(7*@delayInc + @initialDelay)}
+ &:nth-child(9){.delay(8*@delayInc + @initialDelay)}
+ &:nth-child(10){.delay(9*@delayInc + @initialDelay)}
+ &:nth-child(11){.delay(10*@delayInc + @initialDelay)}
+ &:nth-child(12){.delay(11*@delayInc + @initialDelay)}
+ &:nth-child(13){.delay(12*@delayInc + @initialDelay)}
+ &:nth-child(14){.delay(13*@delayInc + @initialDelay)}
+ &:nth-child(15){.delay(14*@delayInc + @initialDelay)}
+ &:nth-child(16){.delay(15*@delayInc + @initialDelay)}
+ &:nth-child(17){.delay(16*@delayInc + @initialDelay)}
+ &:nth-child(18){.delay(17*@delayInc + @initialDelay)}
+ &:nth-child(19){.delay(18*@delayInc + @initialDelay)}
+ &:nth-child(20){.delay(19*@delayInc + @initialDelay)}
+}
+
+
+
+.createFrames(@name, @from, @to){
+ @frames: {
+ from { @from(); }
+ to { @to(); }
+ };
+ @-webkit-keyframes @name {@frames();}
+ @-moz-keyframes @name {@frames();}
+ @-ms-keyframes @name {@frames();}
+ @-o-keyframes @name {@frames();}
+ @keyframes @name {@frames();}
+}
+
+.createAnimation(@name, @duration : @defaultDuration, @easing : @defaultEasing){
+ -webkit-animation-name: @name;
+ -moz-animation-name: @name;
+ -ms-animation-name: @name;
+ animation-name: @name;
+ -webkit-animation-duration: @duration;
+ -moz-animation-duration: @duration;
+ -ms-animation-duration: @duration;
+ animation-duration: @duration;
+ -webkit-animation-timing-function: @easing;
+ -moz-animation-timing-function: @easing;
+ -ms-animation-timing-function: @easing;
+ animation-timing-function: @easing;
+}
+
+
+
+/***************************
+ Standard Animations
+****************************/
+
+.fadeIn(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeIn; @duration; @easing);
+ .createFrames(fadeIn,
+ { opacity : 0; },
+ { opacity : 1; }
+ );
+}
+
+.fadeInDown(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeInDown; @duration; @easing);
+ .createFrames(fadeInDown,
+ { opacity : 0; .transform(translateY(20px));},
+ { opacity : 1; .transform(translateY(0px));}
+ );
+}
+
+.fadeInTop(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeInTop; @duration; @easing);
+ .createFrames(fadeInTop,
+ { opacity : 0; .transform(translateY(-20px)); },
+ { opacity : 1; .transform(translateY(0px));}
+ );
+}
+
+.fadeInLeft(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeInLeft; @duration; @easing);
+ .createFrames(fadeInLeft,
+ { opacity: 0; .transform(translateX(-20px));},
+ { opacity: 1; .transform(translateX(0));}
+ );
+}
+
+.fadeInRight(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeInRight; @duration; @easing);
+ .createFrames(fadeInRight,
+ { opacity: 0; .transform(translateX(20px));},
+ { opacity: 1; .transform(translateX(0));}
+ );
+}
+
+.fadeOut(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeOut; @duration; @easing);
+ .createFrames(fadeOut,
+ { opacity : 1; },
+ { opacity : 0; }
+ );
+}
+
+.fadeOutDown(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeOutDown; @duration; @easing);
+ .createFrames(fadeOutDown,
+ { opacity : 1; .transform(translateY(0)); visibility: visible;},
+ { opacity : 0; .transform(translateY(20px)); visibility: hidden;}
+ );
+}
+
+.fadeOutTop(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeOutTop; @duration; @easing);
+ .createFrames(fadeOutTop,
+ { opacity : 1; .transform(translateY(0)); },
+ { opacity : 0; .transform(translateY(-20px)); }
+ );
+}
+
+.fadeOutLeft(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeOutLeft; @duration; @easing);
+ .createFrames(fadeOutLeft,
+ { opacity : 1; .transform(translateX(0));},
+ { opacity : 0; .transform(translateX(-20px));}
+ );
+}
+
+.fadeOutRight(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(fadeOutRight; @duration; @easing);
+ .createFrames(fadeOutRight,
+ { opacity : 1; .transform(translateX(0));},
+ { opacity : 0; .transform(translateX(20px));}
+ );
+}
+
+
+
+
+/***************************
+ Fun Animations
+****************************/
+
+.spin(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(spin, @duration, @easing);
+ .spinKeyFrames(){
+ from { .transform(rotate(0deg)); }
+ to { .transform(rotate(360deg)); }
+ }
+ @-webkit-keyframes spin {.spinKeyFrames();}
+ @-moz-keyframes spin {.spinKeyFrames();}
+ @-ms-keyframes spin {.spinKeyFrames();}
+ @-o-keyframes spin {.spinKeyFrames();}
+ @keyframes spin {.spinKeyFrames();}
+}
+
+.bounce(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(bounce, @duration, @easing);
+ .bounceKeyFrames(){
+ 0%, 20%, 50%, 80%, 100% { .transform(translateY(0));}
+ 40% { .transform(translateY(-30px));}
+ 60% { .transform(translateY(-15px));}
+ }
+ @-webkit-keyframes bounce {.bounceKeyFrames();}
+ @-moz-keyframes bounce {.bounceKeyFrames();}
+ @-ms-keyframes bounce {.bounceKeyFrames();}
+ @-o-keyframes bounce {.bounceKeyFrames();}
+ @keyframes bounce {.bounceKeyFrames();}
+}
+
+.pulse(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(pulse, @duration, @easing);
+ .pulseKeyFrames(){
+ 0% { .transform(scale(1));}
+ 50% { .transform(scale(1.4));}
+ 100% { .transform(scale(1));}
+ }
+ @-webkit-keyframes pulse {.pulseKeyFrames();}
+ @-moz-keyframes pulse {.pulseKeyFrames();}
+ @-ms-keyframes pulse {.pulseKeyFrames();}
+ @-o-keyframes pulse {.pulseKeyFrames();}
+ @keyframes pulse {.pulseKeyFrames();}
+}
+
+.rubberBand(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(rubberBand, @duration, @easing);
+ .rubberBandKeyFrames(){
+ 0% {.transform(scale(1));}
+ 30% {.transform(scaleX(1.25) scaleY(0.75));}
+ 40% {.transform(scaleX(0.75) scaleY(1.25));}
+ 60% {.transform(scaleX(1.15) scaleY(0.85));}
+ 100% {.transform(scale(1));}
+ }
+ @-webkit-keyframes rubberBand {.rubberBandKeyFrames();}
+ @-moz-keyframes rubberBand {.rubberBandKeyFrames();}
+ @-ms-keyframes rubberBand {.rubberBandKeyFrames();}
+ @-o-keyframes rubberBand {.rubberBandKeyFrames();}
+ @keyframes rubberBand {.rubberBandKeyFrames();}
+}
+
+.shake(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(shake, @duration, @easing);
+ .shakeKeyFrames(){
+ 0%, 100% {.transform( translateX(0));}
+ 10%, 30%, 50%, 70%, 90% {.transform( translateX(-10px));}
+ 20%, 40%, 60%, 80% {.transform( translateX(10px));}
+ }
+ @-webkit-keyframes shake {.shakeKeyFrames();}
+ @-moz-keyframes shake {.shakeKeyFrames();}
+ @-ms-keyframes shake {.shakeKeyFrames();}
+ @-o-keyframes shake {.shakeKeyFrames();}
+ @keyframes shake {.shakeKeyFrames();}
+}
+
+.swing(@duration : @defaultDuration, @easing : @defaultEasing){
+ -webkit-transform-origin: top center;
+ -ms-transform-origin: top center;
+ transform-origin: top center;
+ .createAnimation(swing, @duration, @easing);
+ .swingKeyFrames(){
+ 20% {.transform(rotate(15deg));}
+ 40% {.transform(rotate(-10deg));}
+ 60% {.transform(rotate(5deg));}
+ 80% {.transform(rotate(-5deg));}
+ 100% {.transform(rotate(0deg));}
+ }
+ @-webkit-keyframes swing {.swingKeyFrames();}
+ @-moz-keyframes swing {.swingKeyFrames();}
+ @-ms-keyframes swing {.swingKeyFrames();}
+ @-o-keyframes swing {.swingKeyFrames();}
+ @keyframes swing {.swingKeyFrames();}
+}
+
+.twist(@duration : @defaultDuration, @easing : @defaultEasing){
+ -webkit-transform-origin: center center;
+ -ms-transform-origin: center center;
+ transform-origin: center center;
+ .createAnimation(swing, @duration, @easing);
+ .swingKeyFrames(){
+ 20% {.transform(rotate(15deg));}
+ 40% {.transform(rotate(-10deg));}
+ 60% {.transform(rotate(5deg));}
+ 80% {.transform(rotate(-5deg));}
+ 100% {.transform(rotate(0deg));}
+ }
+ @-webkit-keyframes swing {.swingKeyFrames();}
+ @-moz-keyframes swing {.swingKeyFrames();}
+ @-ms-keyframes swing {.swingKeyFrames();}
+ @-o-keyframes swing {.swingKeyFrames();}
+ @keyframes swing {.swingKeyFrames();}
+}
+
+.wobble(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(wobble, @duration, @easing);
+ .wobbleKeyFrames(){
+ 0% {.transform(translateX(0%));}
+ 15% {.transform(translateX(-25%) rotate(-5deg));}
+ 30% {.transform(translateX(20%) rotate(3deg));}
+ 45% {.transform(translateX(-15%) rotate(-3deg));}
+ 60% {.transform(translateX(10%) rotate(2deg));}
+ 75% {.transform(translateX(-5%) rotate(-1deg));}
+ 100% {.transform(translateX(0%));}
+ }
+ @-webkit-keyframes wobble {.wobbleKeyFrames();}
+ @-moz-keyframes wobble {.wobbleKeyFrames();}
+ @-ms-keyframes wobble {.wobbleKeyFrames();}
+ @-o-keyframes wobble {.wobbleKeyFrames();}
+ @keyframes wobble {.wobbleKeyFrames();}
+}
+
+.popIn(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(popIn, @duration, @easing);
+ .popInKeyFrames(){
+ 0% { .transform(scale(0));}
+ 70% { .transform(scale(1.4));}
+ 100% { .transform(scale(1));}
+ }
+ @-webkit-keyframes popIn {.popInKeyFrames();}
+ @-moz-keyframes popIn {.popInKeyFrames();}
+ @-ms-keyframes popIn {.popInKeyFrames();}
+ @-o-keyframes popIn {.popInKeyFrames();}
+ @keyframes popIn {.popInKeyFrames();}
+}
+
+.rumble(@duration : @defaultDuration, @easing : @defaultEasing){
+ .createAnimation(rumble, @duration, @easing);
+ .rumbleKeyFrames(){
+ 2% { .transform(translate(-0.5px, 1.5px) rotate(0.5deg)); }
+ 4% { .transform(translate(-0.5px, 1.5px) rotate(-0.5deg)); }
+ 6% { .transform(translate(-2.5px, -1.5px) rotate(0.5deg)); }
+ 8% { .transform(translate(-2.5px, -2.5px) rotate(-1.5deg)); }
+ 10% { .transform(translate(1.5px, 1.5px) rotate(-1.5deg)); }
+ 12% { .transform(translate(-2.5px, -0.5px) rotate(-0.5deg)); }
+ 14% { .transform(translate(1.5px, -2.5px) rotate(-0.5deg)); }
+ 16% { .transform(translate(0.5px, 1.5px) rotate(0.5deg)); }
+ 18% { .transform(translate(-2.5px, -0.5px) rotate(0.5deg)); }
+ 20% { .transform(translate(-0.5px, -0.5px) rotate(-1.5deg)); }
+ 22% { .transform(translate(-2.5px, -1.5px) rotate(-1.5deg)); }
+ 24% { .transform(translate(-1.5px, -2.5px) rotate(-1.5deg)); }
+ 26% { .transform(translate(0.5px, -0.5px) rotate(-1.5deg)); }
+ 28% { .transform(translate(-0.5px, -1.5px) rotate(-0.5deg)); }
+ 30% { .transform(translate(-2.5px, 1.5px) rotate(0.5deg)); }
+ 32% { .transform(translate(-2.5px, -2.5px) rotate(-0.5deg)); }
+ 34% { .transform(translate(-1.5px, 0.5px) rotate(-1.5deg)); }
+ 36% { .transform(translate(1.5px, -1.5px) rotate(-1.5deg)); }
+ 38% { .transform(translate(0.5px, -0.5px) rotate(-0.5deg)); }
+ 40% { .transform(translate(-0.5px, 0.5px) rotate(0.5deg)); }
+ 42% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); }
+ 44% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); }
+ 46% { .transform(translate(-1.5px, 1.5px) rotate(-1.5deg)); }
+ 48% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); }
+ 50% { .transform(translate(-1.5px, -0.5px) rotate(-1.5deg)); }
+ 52% { .transform(translate(-2.5px, -0.5px) rotate(-1.5deg)); }
+ 54% { .transform(translate(1.5px, 0.5px) rotate(-1.5deg)); }
+ 56% { .transform(translate(0.5px, 0.5px) rotate(-1.5deg)); }
+ 58% { .transform(translate(0.5px, 1.5px) rotate(-0.5deg)); }
+ 60% { .transform(translate(-0.5px, -2.5px) rotate(-0.5deg)); }
+ 62% { .transform(translate(-2.5px, -1.5px) rotate(-0.5deg)); }
+ 64% { .transform(translate(-1.5px, 0.5px) rotate(0.5deg)); }
+ 66% { .transform(translate(0.5px, -0.5px) rotate(-1.5deg)); }
+ 68% { .transform(translate(-1.5px, -0.5px) rotate(-1.5deg)); }
+ 70% { .transform(translate(-0.5px, -2.5px) rotate(-1.5deg)); }
+ 72% { .transform(translate(-2.5px, -0.5px) rotate(-1.5deg)); }
+ 74% { .transform(translate(-2.5px, 0.5px) rotate(0.5deg)); }
+ 76% { .transform(translate(1.5px, -1.5px) rotate(-1.5deg)); }
+ 78% { .transform(translate(1.5px, -2.5px) rotate(0.5deg)); }
+ 80% { .transform(translate(-2.5px, -2.5px) rotate(-0.5deg)); }
+ 82% { .transform(translate(-2.5px, -1.5px) rotate(0.5deg)); }
+ 84% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); }
+ 86% { .transform(translate(-2.5px, 0.5px) rotate(-0.5deg)); }
+ 88% { .transform(translate(-2.5px, -0.5px) rotate(-0.5deg)); }
+ 90% { .transform(translate(-1.5px, -1.5px) rotate(-1.5deg)); }
+ 92% { .transform(translate(-0.5px, -1.5px) rotate(-0.5deg)); }
+ 94% { .transform(translate(0.5px, -0.5px) rotate(-0.5deg)); }
+ 96% { .transform(translate(-2.5px, -2.5px) rotate(0.5deg)); }
+ 98% { .transform(translate(-0.5px, 1.5px) rotate(-0.5deg)); }
+ }
+ @-webkit-keyframes rumble {.rumbleKeyFrames();}
+ @-moz-keyframes rumble {.rumbleKeyFrames();}
+ @-ms-keyframes rumble {.rumbleKeyFrames();}
+ @-o-keyframes rumble {.rumbleKeyFrames();}
+ @keyframes rumble {.rumbleKeyFrames();}
+}
\ No newline at end of file
diff --git a/shared/naturalCrit/colors.less b/shared/naturalCrit/colors.less
new file mode 100644
index 000000000..67768d811
--- /dev/null
+++ b/shared/naturalCrit/colors.less
@@ -0,0 +1,23 @@
+
+@copyGrey : #333333;
+
+@tealLight : #1ABC9C;
+@teal : #16A085;
+@greenLight : #2ECC71;
+@green : #27AE60;
+@blueLight : #3498DB;
+@blue : #2980B9;
+@purpleLight : #9B59B6;
+@purple : #8E44AD;
+@steelLight : #34495E;
+@steel : #2C3E50;
+@yellowLight : #F1C40F;
+@yellow : #F39C12;
+@orangeLight : #E67E22;
+@orange : #D35400;
+@redLight : #E74C3C;
+@red : #C0392B;
+@silverLight : #ECF0F1;
+@silver : #BDC3C7;
+@greyLight : #95A5A6;
+@grey : #7F8C8D;
\ No newline at end of file
diff --git a/shared/naturalCrit/elements.less b/shared/naturalCrit/elements.less
new file mode 100644
index 000000000..6dff02aa7
--- /dev/null
+++ b/shared/naturalCrit/elements.less
@@ -0,0 +1,86 @@
+
+@containerWidth : 1000px;
+
+html, body{
+ position : relative;
+ height : 100%;
+ min-height : 100%;
+ background-color : #eee;
+ font-family : 'Lato', sans-serif;
+ color : @copyGrey;
+}
+.container{
+ position : relative;
+ max-width : @containerWidth;
+ margin : 0 auto;
+ padding-right : 20px;
+ padding-left : 20px;
+}
+h1{
+ margin-top : 10px;
+ margin-bottom : 15px;
+ font-size : 2em;
+}
+h2{
+ margin-top : 10px;
+ margin-bottom : 15px;
+ font-size : 1.5em;
+ font-weight : 900;
+}
+h3{
+ margin-top : 5px;
+ margin-bottom : 7px;
+ font-size : 1em;
+ font-weight : 900;
+}
+p{
+ margin-bottom : 1em;
+ font-size : 16px;
+ color : @copyGrey;
+ line-height : 1.5em;
+}
+code{
+ background-color : #F8F8F8;
+ font-family : 'Courier', mono;
+ color : black;
+ white-space : pre;
+}
+a{
+ color : inherit;
+}
+strong{
+ font-weight : bold;
+}
+button{
+ .button();
+}
+.button(@backgroundColor : @green){
+ .animate(background-color);
+ display : inline-block;
+ padding : 0.6em 1.2em;
+ cursor : pointer;
+ background-color : @backgroundColor;
+ font-family : "Lato", Helvetica, Arial, sans-serif;
+ font-size : 15px;
+ color : white;
+ text-decoration : none;
+ border : none;
+ outline : none;
+ &:hover{
+ background-color : darken(@backgroundColor, 5%);
+ }
+ &:active{
+ background-color : darken(@backgroundColor, 10%);
+ }
+ &:disabled{
+ background-color : @silver !important;
+ }
+}
+.iconButton(@backgroundColor : @green){
+ padding : 0.6em;
+ cursor : pointer;
+ background-color : @backgroundColor;
+ font-size : 14px;
+ color : white;
+ text-align : center;
+}
\ No newline at end of file
diff --git a/shared/naturalCrit/reset.less b/shared/naturalCrit/reset.less
new file mode 100644
index 000000000..b0854aa33
--- /dev/null
+++ b/shared/naturalCrit/reset.less
@@ -0,0 +1,2 @@
+/* Eric Meyer's Reset CSS v2.0 - http://cssreset.com */
+html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}
\ No newline at end of file