diff --git a/js/html_actuator.js b/js/html_actuator.js index 04a137b9a3f4eb16184bfc1e37449e796e398b1a..150f0b108ecc5e5a8947df4df3b7ebd420e0c985 100644 --- a/js/html_actuator.js +++ b/js/html_actuator.js @@ -42,25 +42,27 @@ HTMLActuator.prototype.clearContainer = function (container) { HTMLActuator.prototype.addTile = function (tile) { var self = this; - var element = document.createElement("div"); + var wrapper = document.createElement("div"); + var inner = document.createElement("div"); var position = tile.previousPosition || { x: tile.x, y: tile.y }; positionClass = this.positionClass(position); // We can't use classlist because it somehow glitches when replacing classes var classes = ["tile", "tile-" + tile.value, positionClass]; - this.applyClasses(element, classes); + this.applyClasses(wrapper, classes); - element.textContent = tile.value; + inner.classList.add("tile-inner"); + inner.textContent = tile.value; if (tile.previousPosition) { // Make sure that the tile gets rendered in the previous position first window.requestAnimationFrame(function () { classes[2] = self.positionClass({ x: tile.x, y: tile.y }); - self.applyClasses(element, classes); // Update the position + self.applyClasses(wrapper, classes); // Update the position }); } else if (tile.mergedFrom) { classes.push("tile-merged"); - this.applyClasses(element, classes); + this.applyClasses(wrapper, classes); // Render the tiles that merged tile.mergedFrom.forEach(function (merged) { @@ -68,11 +70,14 @@ HTMLActuator.prototype.addTile = function (tile) { }); } else { classes.push("tile-new"); - this.applyClasses(element, classes); + this.applyClasses(wrapper, classes); } + // Add the inner part of the tile to the wrapper + wrapper.appendChild(inner); + // Put the tile on the board - this.tileContainer.appendChild(element); + this.tileContainer.appendChild(wrapper); }; HTMLActuator.prototype.applyClasses = function (element, classes) { diff --git a/style/helpers.scss b/style/helpers.scss index a8f108c695aced23d16fbc14bd8e4e894d20e566..4e6dfa6472f42fcfa6a01dc1f104a14cc0028c49 100644 --- a/style/helpers.scss +++ b/style/helpers.scss @@ -24,11 +24,31 @@ @mixin transition($args...) { -webkit-transition: $args; -moz-transition: $args; + transition: $args; } @mixin transition-property($args...) { -webkit-transition-property: $args; -moz-transition-property: $args; + transition-property: $args; +} + +@mixin animation($args...) { + -webkit-animation: $args; + -moz-animation: $args; + animation: $args; +} + +@mixin animation-fill-mode($args...) { + -webkit-animation-fill-mode: $args; + -moz-animation-fill-mode: $args; + animation: $args; +} + +@mixin transform($args...) { + -webkit-transform: $args; + -moz-transform: $args; + transform: $args; } // Keyframe animations @@ -44,16 +64,6 @@ } } -@mixin animation($str) { - -webkit-animation: #{$str}; - -moz-animation: #{$str}; -} - -@mixin animation-fill-mode($str) { - -webkit-animation-fill-mode: #{$str}; - -moz-animation-fill-mode: #{$str}; -} - // Media queries @mixin smaller($width) { @media screen and (max-width: $width) { diff --git a/style/main.css b/style/main.css index c28f9be5cc7bbb1e778e19409dde76c9915c706c..7bb376a29be217bcb3d2a88e5f794219d0b37499 100644 --- a/style/main.css +++ b/style/main.css @@ -87,8 +87,10 @@ h1.title { z-index: 100; -webkit-animation: move-up 600ms ease-in; -moz-animation: move-up 600ms ease-in; + animation: move-up 600ms ease-in; -webkit-animation-fill-mode: both; - -moz-animation-fill-mode: both; } + -moz-animation-fill-mode: both; + animation: both; } .score-container:after { content: "Score"; } @@ -168,8 +170,10 @@ hr { text-align: center; -webkit-animation: fade-in 800ms ease 1200ms; -moz-animation: fade-in 800ms ease 1200ms; + animation: fade-in 800ms ease 1200ms; -webkit-animation-fill-mode: both; - -moz-animation-fill-mode: both; } + -moz-animation-fill-mode: both; + animation: both; } .game-container .game-message p { font-size: 60px; font-weight: bold; @@ -222,229 +226,252 @@ hr { position: absolute; z-index: 2; } -.tile { - width: 106.25px; - height: 106.25px; +.tile, .tile .tile-inner { + width: 107px; + height: 107px; line-height: 116.25px; } - .tile.tile-position-1-1 { - position: absolute; - left: 0px; - top: 0px; } - .tile.tile-position-1-2 { - position: absolute; - left: 0px; - top: 121px; } - .tile.tile-position-1-3 { - position: absolute; - left: 0px; - top: 243px; } - .tile.tile-position-1-4 { - position: absolute; - left: 0px; - top: 364px; } - .tile.tile-position-2-1 { - position: absolute; - left: 121px; - top: 0px; } - .tile.tile-position-2-2 { - position: absolute; - left: 121px; - top: 121px; } - .tile.tile-position-2-3 { - position: absolute; - left: 121px; - top: 243px; } - .tile.tile-position-2-4 { - position: absolute; - left: 121px; - top: 364px; } - .tile.tile-position-3-1 { - position: absolute; - left: 243px; - top: 0px; } - .tile.tile-position-3-2 { - position: absolute; - left: 243px; - top: 121px; } - .tile.tile-position-3-3 { - position: absolute; - left: 243px; - top: 243px; } - .tile.tile-position-3-4 { - position: absolute; - left: 243px; - top: 364px; } - .tile.tile-position-4-1 { - position: absolute; - left: 364px; - top: 0px; } - .tile.tile-position-4-2 { - position: absolute; - left: 364px; - top: 121px; } - .tile.tile-position-4-3 { - position: absolute; - left: 364px; - top: 243px; } - .tile.tile-position-4-4 { - position: absolute; - left: 364px; - top: 364px; } +.tile.tile-position-1-1 { + -webkit-transform: translate(0px, 0px); + -moz-transform: translate(0px, 0px); + transform: translate(0px, 0px); } +.tile.tile-position-1-2 { + -webkit-transform: translate(0px, 121px); + -moz-transform: translate(0px, 121px); + transform: translate(0px, 121px); } +.tile.tile-position-1-3 { + -webkit-transform: translate(0px, 242px); + -moz-transform: translate(0px, 242px); + transform: translate(0px, 242px); } +.tile.tile-position-1-4 { + -webkit-transform: translate(0px, 363px); + -moz-transform: translate(0px, 363px); + transform: translate(0px, 363px); } +.tile.tile-position-2-1 { + -webkit-transform: translate(121px, 0px); + -moz-transform: translate(121px, 0px); + transform: translate(121px, 0px); } +.tile.tile-position-2-2 { + -webkit-transform: translate(121px, 121px); + -moz-transform: translate(121px, 121px); + transform: translate(121px, 121px); } +.tile.tile-position-2-3 { + -webkit-transform: translate(121px, 242px); + -moz-transform: translate(121px, 242px); + transform: translate(121px, 242px); } +.tile.tile-position-2-4 { + -webkit-transform: translate(121px, 363px); + -moz-transform: translate(121px, 363px); + transform: translate(121px, 363px); } +.tile.tile-position-3-1 { + -webkit-transform: translate(242px, 0px); + -moz-transform: translate(242px, 0px); + transform: translate(242px, 0px); } +.tile.tile-position-3-2 { + -webkit-transform: translate(242px, 121px); + -moz-transform: translate(242px, 121px); + transform: translate(242px, 121px); } +.tile.tile-position-3-3 { + -webkit-transform: translate(242px, 242px); + -moz-transform: translate(242px, 242px); + transform: translate(242px, 242px); } +.tile.tile-position-3-4 { + -webkit-transform: translate(242px, 363px); + -moz-transform: translate(242px, 363px); + transform: translate(242px, 363px); } +.tile.tile-position-4-1 { + -webkit-transform: translate(363px, 0px); + -moz-transform: translate(363px, 0px); + transform: translate(363px, 0px); } +.tile.tile-position-4-2 { + -webkit-transform: translate(363px, 121px); + -moz-transform: translate(363px, 121px); + transform: translate(363px, 121px); } +.tile.tile-position-4-3 { + -webkit-transform: translate(363px, 242px); + -moz-transform: translate(363px, 242px); + transform: translate(363px, 242px); } +.tile.tile-position-4-4 { + -webkit-transform: translate(363px, 363px); + -moz-transform: translate(363px, 363px); + transform: translate(363px, 363px); } .tile { - border-radius: 3px; - background: #eee4da; - text-align: center; - font-weight: bold; - z-index: 10; - font-size: 55px; + position: absolute; -webkit-transition: 100ms ease-in-out; -moz-transition: 100ms ease-in-out; - -webkit-transition-property: top, left; - -moz-transition-property: top, left; } - .tile.tile-2 { + transition: 100ms ease-in-out; + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + transition-property: transform; } + .tile .tile-inner { + border-radius: 3px; + background: #eee4da; + text-align: center; + font-weight: bold; + z-index: 10; + font-size: 55px; } + .tile.tile-2 .tile-inner { background: #eee4da; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } - .tile.tile-4 { + .tile.tile-4 .tile-inner { background: #ede0c8; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } - .tile.tile-8 { + .tile.tile-8 .tile-inner { color: #f9f6f2; background: #f2b179; } - .tile.tile-16 { + .tile.tile-16 .tile-inner { color: #f9f6f2; background: #f59563; } - .tile.tile-32 { + .tile.tile-32 .tile-inner { color: #f9f6f2; background: #f67c5f; } - .tile.tile-64 { + .tile.tile-64 .tile-inner { color: #f9f6f2; background: #f65e3b; } - .tile.tile-128 { + .tile.tile-128 .tile-inner { color: #f9f6f2; background: #edcf72; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.2381), inset 0 0 0 1px rgba(255, 255, 255, 0.14286); font-size: 45px; } @media screen and (max-width: 480px) { - .tile.tile-128 { + .tile.tile-128 .tile-inner { font-size: 25px; } } - .tile.tile-256 { + .tile.tile-256 .tile-inner { color: #f9f6f2; background: #edcc61; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.19048); font-size: 45px; } @media screen and (max-width: 480px) { - .tile.tile-256 { + .tile.tile-256 .tile-inner { font-size: 25px; } } - .tile.tile-512 { + .tile.tile-512 .tile-inner { color: #f9f6f2; background: #edc850; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.39683), inset 0 0 0 1px rgba(255, 255, 255, 0.2381); font-size: 45px; } @media screen and (max-width: 480px) { - .tile.tile-512 { + .tile.tile-512 .tile-inner { font-size: 25px; } } - .tile.tile-1024 { + .tile.tile-1024 .tile-inner { color: #f9f6f2; background: #edc53f; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.28571); font-size: 35px; } @media screen and (max-width: 480px) { - .tile.tile-1024 { + .tile.tile-1024 .tile-inner { font-size: 15px; } } - .tile.tile-2048 { + .tile.tile-2048 .tile-inner { color: #f9f6f2; background: #edc22e; box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.55556), inset 0 0 0 1px rgba(255, 255, 255, 0.33333); font-size: 35px; } @media screen and (max-width: 480px) { - .tile.tile-2048 { + .tile.tile-2048 .tile-inner { font-size: 15px; } } @-webkit-keyframes appear { 0% { opacity: 0; -webkit-transform: scale(0); - -moz-transform: scale(0); } + -moz-transform: scale(0); + transform: scale(0); } 100% { opacity: 1; -webkit-transform: scale(1); - -moz-transform: scale(1); } } + -moz-transform: scale(1); + transform: scale(1); } } @-moz-keyframes appear { 0% { opacity: 0; -webkit-transform: scale(0); - -moz-transform: scale(0); } + -moz-transform: scale(0); + transform: scale(0); } 100% { opacity: 1; -webkit-transform: scale(1); - -moz-transform: scale(1); } } + -moz-transform: scale(1); + transform: scale(1); } } @keyframes appear { 0% { opacity: 0; -webkit-transform: scale(0); - -moz-transform: scale(0); } + -moz-transform: scale(0); + transform: scale(0); } 100% { opacity: 1; -webkit-transform: scale(1); - -moz-transform: scale(1); } } + -moz-transform: scale(1); + transform: scale(1); } } -.tile-new { +.tile-new .tile-inner { -webkit-animation: appear 200ms ease 100ms; -moz-animation: appear 200ms ease 100ms; - -webkit-animation-fill-mode: both; - -moz-animation-fill-mode: both; } + animation: appear 200ms ease 100ms; + -webkit-animation-fill-mode: backwards; + -moz-animation-fill-mode: backwards; + animation: backwards; } @-webkit-keyframes pop { 0% { -webkit-transform: scale(0); - -moz-transform: scale(0); } + -moz-transform: scale(0); + transform: scale(0); } 50% { -webkit-transform: scale(1.2); - -moz-transform: scale(1.2); } + -moz-transform: scale(1.2); + transform: scale(1.2); } 100% { -webkit-transform: scale(1); - -moz-transform: scale(1); } } + -moz-transform: scale(1); + transform: scale(1); } } @-moz-keyframes pop { 0% { -webkit-transform: scale(0); - -moz-transform: scale(0); } + -moz-transform: scale(0); + transform: scale(0); } 50% { -webkit-transform: scale(1.2); - -moz-transform: scale(1.2); } + -moz-transform: scale(1.2); + transform: scale(1.2); } 100% { -webkit-transform: scale(1); - -moz-transform: scale(1); } } + -moz-transform: scale(1); + transform: scale(1); } } @keyframes pop { 0% { -webkit-transform: scale(0); - -moz-transform: scale(0); } + -moz-transform: scale(0); + transform: scale(0); } 50% { -webkit-transform: scale(1.2); - -moz-transform: scale(1.2); } + -moz-transform: scale(1.2); + transform: scale(1.2); } 100% { -webkit-transform: scale(1); - -moz-transform: scale(1); } } + -moz-transform: scale(1); + transform: scale(1); } } -.tile-merged { +.tile-merged .tile-inner { z-index: 20; -webkit-animation: pop 200ms ease 100ms; -moz-animation: pop 200ms ease 100ms; - -webkit-animation-fill-mode: both; - -moz-animation-fill-mode: both; } + animation: pop 200ms ease 100ms; + -webkit-animation-fill-mode: backwards; + -moz-animation-fill-mode: backwards; + animation: backwards; } .game-intro { margin-bottom: 0; } @@ -503,8 +530,10 @@ hr { text-align: center; -webkit-animation: fade-in 800ms ease 1200ms; -moz-animation: fade-in 800ms ease 1200ms; + animation: fade-in 800ms ease 1200ms; -webkit-animation-fill-mode: both; - -moz-animation-fill-mode: both; } + -moz-animation-fill-mode: both; + animation: both; } .game-container .game-message p { font-size: 60px; font-weight: bold; @@ -557,79 +586,79 @@ hr { position: absolute; z-index: 2; } - .tile { - width: 57.5px; - height: 57.5px; + .tile, .tile .tile-inner { + width: 58px; + height: 58px; line-height: 67.5px; } - .tile.tile-position-1-1 { - position: absolute; - left: 0px; - top: 0px; } - .tile.tile-position-1-2 { - position: absolute; - left: 0px; - top: 68px; } - .tile.tile-position-1-3 { - position: absolute; - left: 0px; - top: 135px; } - .tile.tile-position-1-4 { - position: absolute; - left: 0px; - top: 203px; } - .tile.tile-position-2-1 { - position: absolute; - left: 68px; - top: 0px; } - .tile.tile-position-2-2 { - position: absolute; - left: 68px; - top: 68px; } - .tile.tile-position-2-3 { - position: absolute; - left: 68px; - top: 135px; } - .tile.tile-position-2-4 { - position: absolute; - left: 68px; - top: 203px; } - .tile.tile-position-3-1 { - position: absolute; - left: 135px; - top: 0px; } - .tile.tile-position-3-2 { - position: absolute; - left: 135px; - top: 68px; } - .tile.tile-position-3-3 { - position: absolute; - left: 135px; - top: 135px; } - .tile.tile-position-3-4 { - position: absolute; - left: 135px; - top: 203px; } - .tile.tile-position-4-1 { - position: absolute; - left: 203px; - top: 0px; } - .tile.tile-position-4-2 { - position: absolute; - left: 203px; - top: 68px; } - .tile.tile-position-4-3 { - position: absolute; - left: 203px; - top: 135px; } - .tile.tile-position-4-4 { - position: absolute; - left: 203px; - top: 203px; } + .tile.tile-position-1-1 { + -webkit-transform: translate(0px, 0px); + -moz-transform: translate(0px, 0px); + transform: translate(0px, 0px); } + .tile.tile-position-1-2 { + -webkit-transform: translate(0px, 67px); + -moz-transform: translate(0px, 67px); + transform: translate(0px, 67px); } + .tile.tile-position-1-3 { + -webkit-transform: translate(0px, 135px); + -moz-transform: translate(0px, 135px); + transform: translate(0px, 135px); } + .tile.tile-position-1-4 { + -webkit-transform: translate(0px, 202px); + -moz-transform: translate(0px, 202px); + transform: translate(0px, 202px); } + .tile.tile-position-2-1 { + -webkit-transform: translate(67px, 0px); + -moz-transform: translate(67px, 0px); + transform: translate(67px, 0px); } + .tile.tile-position-2-2 { + -webkit-transform: translate(67px, 67px); + -moz-transform: translate(67px, 67px); + transform: translate(67px, 67px); } + .tile.tile-position-2-3 { + -webkit-transform: translate(67px, 135px); + -moz-transform: translate(67px, 135px); + transform: translate(67px, 135px); } + .tile.tile-position-2-4 { + -webkit-transform: translate(67px, 202px); + -moz-transform: translate(67px, 202px); + transform: translate(67px, 202px); } + .tile.tile-position-3-1 { + -webkit-transform: translate(135px, 0px); + -moz-transform: translate(135px, 0px); + transform: translate(135px, 0px); } + .tile.tile-position-3-2 { + -webkit-transform: translate(135px, 67px); + -moz-transform: translate(135px, 67px); + transform: translate(135px, 67px); } + .tile.tile-position-3-3 { + -webkit-transform: translate(135px, 135px); + -moz-transform: translate(135px, 135px); + transform: translate(135px, 135px); } + .tile.tile-position-3-4 { + -webkit-transform: translate(135px, 202px); + -moz-transform: translate(135px, 202px); + transform: translate(135px, 202px); } + .tile.tile-position-4-1 { + -webkit-transform: translate(202px, 0px); + -moz-transform: translate(202px, 0px); + transform: translate(202px, 0px); } + .tile.tile-position-4-2 { + -webkit-transform: translate(202px, 67px); + -moz-transform: translate(202px, 67px); + transform: translate(202px, 67px); } + .tile.tile-position-4-3 { + -webkit-transform: translate(202px, 135px); + -moz-transform: translate(202px, 135px); + transform: translate(202px, 135px); } + .tile.tile-position-4-4 { + -webkit-transform: translate(202px, 202px); + -moz-transform: translate(202px, 202px); + transform: translate(202px, 202px); } .game-container { margin-top: 20px; } - .tile { + .tile .tile-inner { font-size: 35px; } .game-message p { diff --git a/style/main.scss b/style/main.scss index b5e2609998fb2f475acc9444e96b7446c6b1d72a..8686dba391708eaf8e8e8b2f8c9ad7e562dc8ef2 100644 --- a/style/main.scss +++ b/style/main.scss @@ -274,17 +274,19 @@ hr { } .tile { - width: $tile-size; - height: $tile-size; - line-height: $tile-size + 10px; + &, .tile-inner { + width: ceil($tile-size); + height: ceil($tile-size); + line-height: $tile-size + 10px; + } // Build position classes @for $x from 1 through $grid-row-cells { @for $y from 1 through $grid-row-cells { &.tile-position-#{$x}-#{$y} { - position: absolute; - left: round(($tile-size + $grid-spacing) * ($x - 1)); - top: round(($tile-size + $grid-spacing) * ($y - 1)); + $xPos: floor(($tile-size + $grid-spacing) * ($x - 1)); + $yPos: floor(($tile-size + $grid-spacing) * ($y - 1)); + @include transform(translate($xPos, $yPos)); } } } @@ -295,17 +297,24 @@ hr { @include game-field; .tile { - border-radius: $tile-border-radius; + position: absolute; // Makes transforms relative to the top-left corner - background: $tile-color; - text-align: center; - font-weight: bold; - z-index: 10; + .tile-inner { + border-radius: $tile-border-radius; - font-size: 55px; + background: $tile-color; + text-align: center; + font-weight: bold; + z-index: 10; + + font-size: 55px; + } + // Movement transition @include transition($transition-speed ease-in-out); - @include transition-property(top, left); + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + transition-property: transform; $base: 2; $exponent: 1; @@ -328,7 +337,7 @@ hr { @while $exponent <= $limit { $power: pow($base, $exponent); - &.tile-#{$power} { + &.tile-#{$power} .tile-inner { // Calculate base background color $gold-percent: ($exponent - 1) / ($limit - 1) * 100; $mixed-background: mix($tile-gold-color, $tile-color, $gold-percent); @@ -381,43 +390,38 @@ hr { @include keyframes(appear) { 0% { opacity: 0; - -webkit-transform: scale(0); - -moz-transform: scale(0); + @include transform(scale(0)); } 100% { opacity: 1; - -webkit-transform: scale(1); - -moz-transform: scale(1); + @include transform(scale(1)); } } -.tile-new { +.tile-new .tile-inner { @include animation(appear 200ms ease $transition-speed); - @include animation-fill-mode(both); + @include animation-fill-mode(backwards); } @include keyframes(pop) { 0% { - -webkit-transform: scale(0); - -moz-transform: scale(0); + @include transform(scale(0)); } 50% { - -webkit-transform: scale(1.2); - -moz-transform: scale(1.2); + @include transform(scale(1.2)); } 100% { - -webkit-transform: scale(1); - -moz-transform: scale(1); + @include transform(scale(1)); } } -.tile-merged { +.tile-merged .tile-inner { z-index: 20; @include animation(pop 200ms ease $transition-speed); - @include animation-fill-mode(both); + @include animation-fill-mode(backwards); } .game-intro { @@ -455,11 +459,6 @@ hr { margin: 0 auto; } - // .scores-container { - // float: left; - // clear: left; - // } - .score-container, .best-container { margin-top: 0; padding: 15px 10px; @@ -478,7 +477,7 @@ hr { } // Rest of the font-size adjustments in the tile class - .tile { + .tile .tile-inner { font-size: 35px; }