A digital clock inspired by some typography in the GameCube BIOS. No IE support.
Update 7/17/19: Refactored Sass
A Pen by Jon Kantner on CodePen.
A digital clock inspired by some typography in the GameCube BIOS. No IE support.
Update 7/17/19: Refactored Sass
A Pen by Jon Kantner on CodePen.
| - var blocks = 94; | |
| .container | |
| - var d = 6; | |
| - while (d--) { | |
| .digit | |
| - } | |
| .surface | |
| - for (var b = 1;b <= blocks;++b) { | |
| div(class="block b" + b) | |
| .block-outer | |
| .block-inner | |
| .bottom | |
| .front | |
| .left | |
| .right | |
| - } |
| window.addEventListener("load",update); | |
| function update() { | |
| let time = new Date(), | |
| hr = time.getHours(), | |
| min = time.getMinutes(), | |
| sec = time.getSeconds(); | |
| // prepend 0s to single digits | |
| if (hr < 10) | |
| hr = "0" + hr; | |
| if (min < 10) | |
| min = "0" + min; | |
| if (sec < 10) | |
| sec = "0" + sec; | |
| let timeStr = `${hr}${min}${sec}`, | |
| digits = document.querySelectorAll(".digit"), | |
| digitArr = []; | |
| for (let d in digits) { | |
| d = +d; | |
| if (d < digits.length) { | |
| digitArr[d] = timeStr.substr(d,1); | |
| digits[d].className = "digit _" + digitArr[d]; | |
| } | |
| } | |
| setTimeout(update,1000); | |
| } |
| // container and surface | |
| $sqSize: 20px; | |
| $xSpaces: 27; | |
| $ySpaces: 1; | |
| $zSpaces: 5; | |
| $contW: (1em * $xSpaces) * 1.1; | |
| $contH: 1em * $zSpaces * 2; | |
| $xAngle: 105deg; | |
| $zAngle: 0deg; | |
| $prsp: 800px; | |
| // colors | |
| $tr: transparent; | |
| $bl: #000; | |
| $gry: #444; | |
| $grn: #74d447; | |
| // animation, transitions | |
| $dur: 2s; | |
| $tf: cubic-bezier(.4,.1,.6,.9); | |
| $trans: 0.3s; | |
| $bounce: 10px; | |
| $tilt: 7deg; | |
| // * Block placement * | |
| // parameters: x-pos,z-pos | |
| $blocks: | |
| // * Hour * | |
| // tens | |
| (1,5) (2,5) (3,5) | |
| (1,4) (2,4) (3,4) | |
| (1,3) (2,3) (3,3) | |
| (1,2) (2,2) (3,2) | |
| (1,1) (2,1) (3,1) | |
| // ones | |
| (5,5) (6,5) (7,5) | |
| (5,4) (6,4) (7,4) | |
| (5,3) (6,3) (7,3) | |
| (5,2) (6,2) (7,2) | |
| (5,1) (6,1) (7,1) | |
| // colon | |
| (9,4) | |
| (9,2) | |
| // * Minute * | |
| // tens | |
| (11,5) (12,5) (13,5) | |
| (11,4) (12,4) (13,4) | |
| (11,3) (12,3) (13,3) | |
| (11,2) (12,2) (13,2) | |
| (11,1) (12,1) (13,1) | |
| // ones | |
| (15,5) (16,5) (17,5) | |
| (15,4) (16,4) (17,4) | |
| (15,3) (16,3) (17,3) | |
| (15,2) (16,2) (17,2) | |
| (15,1) (16,1) (17,1) | |
| // colon | |
| (19,4) | |
| (19,2) | |
| // * Second * | |
| // tens | |
| (21,5) (22,5) (23,5) | |
| (21,4) (22,4) (23,4) | |
| (21,3) (22,3) (23,3) | |
| (21,2) (22,2) (23,2) | |
| (21,1) (22,1) (23,1) | |
| // ones | |
| (25,5) (26,5) (27,5) | |
| (25,4) (26,4) (27,4) | |
| (25,3) (26,3) (27,3) | |
| (25,2) (26,2) (27,2) | |
| (25,1) (26,1) (27,1); | |
| @mixin placeBlock($x, $z) { | |
| $w: 0.8; // block width | |
| $d: $w; | |
| $h: $w; | |
| $g: (1 - $w) / 2; // half gap between blocks | |
| $x: $x + $g; | |
| $y: 1 + $g; | |
| $z: $z + $g; | |
| transform: translate3d( | |
| 1em*($x - 1), | |
| 1em*(-$y - ($d - 1)), | |
| (1em*$z) + (1em*($h - 1)) | |
| ); | |
| .block-inner div { | |
| &.top, &.bottom { | |
| width: 1em * $w; | |
| height: 1em * $d; | |
| } | |
| &.top { | |
| transform: rotateX(-90deg) translateY(-1em*($d - 1)); | |
| } | |
| &.bottom { | |
| transform: rotateX(-90deg) translateY(-1em*($d - 1)) translateZ(1em*$h); | |
| } | |
| &.front, &.back { | |
| width: 1em * $w; | |
| height: 1em * $h; | |
| } | |
| &.front { | |
| transform: translateZ(1em * ($d - 1)); | |
| } | |
| &.left, &.right { | |
| width: 1em * $d; | |
| height: 1em * $h; | |
| } | |
| &.right { | |
| transform: rotateY(-270deg) translate3d(1em, 0, 1em*($w - $d)); | |
| } | |
| } | |
| } | |
| @mixin moveBlock($x, $z) { | |
| transform: translate3d(1em * $x,0,1em * $z); | |
| } | |
| * { | |
| border: 0; | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| background: | |
| radial-gradient(circle at center,$tr, $bl 95%), | |
| linear-gradient($gry 0.1em, $tr 0) 0 0 / 1em 1em, | |
| linear-gradient(90deg, $gry 0.1em, $bl 0) 0 0 / 1em 1em; | |
| font-size: $sqSize; | |
| height: 100vh; | |
| margin: 0; | |
| overflow: hidden; | |
| } | |
| .container, .surface, .block, .block-outer, .block-inner { | |
| transform-style: preserve-3d; | |
| } | |
| .container, .block, .digit { | |
| position: absolute; | |
| } | |
| .container { | |
| animation: bounce $dur $tf infinite; | |
| display: flex; | |
| margin: auto; | |
| overflow: hidden; | |
| top: 0; | |
| right: 0; | |
| bottom: 0; | |
| left: 0; | |
| width: $contW; | |
| height: $contH; | |
| perspective: $prsp; | |
| } | |
| .surface { | |
| animation: tilt $dur (-$dur*0.75) $tf infinite; | |
| display: block; | |
| width: 1em * $xSpaces; | |
| height: 1em * $ySpaces; | |
| margin: auto; | |
| transform: translateY(1em * $zSpaces/2) rotateX($xAngle) rotateZ($zAngle); | |
| will-change: transform; | |
| } | |
| .block { | |
| bottom: 0; | |
| } | |
| .block-inner { | |
| div { | |
| background-color: $grn; | |
| } | |
| > div { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-content: flex-start; | |
| position: absolute; | |
| width: 1em; | |
| height: 1em; | |
| &.top, &.bottom, &.left, &.right { | |
| &:before { | |
| background-color: #000; | |
| content: ""; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| } | |
| &.top, &.bottom { | |
| &:before { | |
| opacity: 0.2; | |
| } | |
| } | |
| &.left, &.right { | |
| &:before { | |
| opacity: 0.4; | |
| } | |
| } | |
| } | |
| } | |
| .block-outer, .block-inner { | |
| position: relative; | |
| width: 1em; | |
| } | |
| .block-outer { | |
| transition: transform $trans; | |
| } | |
| .block-inner { | |
| transform: rotateX(-90deg) translateZ(1em); | |
| } | |
| .back { | |
| transform: translateZ(-1em) rotateY(180deg); | |
| } | |
| .left { | |
| transform-origin: center left; | |
| transform: rotateY(270deg) translateX(-1em); | |
| } | |
| .right { | |
| transform-origin: top right; | |
| } | |
| .top, .bottom { | |
| transform-origin: top center; | |
| } | |
| // * Render blocks * | |
| // one block only | |
| @if length(nth($blocks,1)) == 1 { | |
| .b1 { | |
| @include placeBlock( | |
| nth($blocks, 1), | |
| nth($blocks, 2) | |
| ); | |
| } | |
| } | |
| // more than one block | |
| @else { | |
| @for $b from 1 through length($blocks) { | |
| .b#{$b} { | |
| @include placeBlock( | |
| nth(nth($blocks, $b), 1), | |
| nth(nth($blocks, $b), 2) | |
| ); | |
| } | |
| } | |
| } | |
| // * Digit display * | |
| @for $p from 1 through 6 { | |
| $step: 15 * ($p - 1); | |
| // deal with colons | |
| $adj: if($p > 4,4,if($p > 2,2,0)); | |
| $step: $step + $adj; | |
| ._0:nth-of-type(#{$p}) ~ .surface { | |
| .b#{5 + $step}, .b#{8 + $step}, .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(-1,0) | |
| } | |
| } | |
| } | |
| ._1:nth-of-type(#{$p}) ~ .surface { | |
| .b#{1 + $step}, .b#{4 + $step}, .b#{7 + $step}, .b#{10 + $step}, .b#{13 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| .b#{2 + $step}, .b#{5 + $step}, .b#{8 + $step}, .b#{11 + $step}, .b#{14 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| ._2:nth-of-type(#{$p}) ~ .surface { | |
| .b#{4 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| .b#{5 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(-1,0) | |
| } | |
| } | |
| .b#{12 + $step} { | |
| .block-outer { | |
| @include moveBlock(-2,0) | |
| } | |
| } | |
| } | |
| @if $p > 1 { | |
| ._3:nth-of-type(#{$p}) ~ .surface { | |
| .b#{4 + $step}, .b#{10 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| .b#{5 + $step}, .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| ._4:nth-of-type(#{$p}) ~ .surface { | |
| .b#{2 + $step}, .b#{5 + $step} { | |
| .block-outer { | |
| @include moveBlock(-1,0) | |
| } | |
| } | |
| .b#{10 + $step}, .b#{13 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| .b#{11 + $step}, .b#{14 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| ._5:nth-of-type(#{$p}) ~ .surface { | |
| .b#{5 + $step} { | |
| .block-outer { | |
| @include moveBlock(-1,0) | |
| } | |
| } | |
| .b#{6 + $step} { | |
| .block-outer { | |
| @include moveBlock(-2,0) | |
| } | |
| } | |
| .b#{10 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| @if $p % 2 == 0 { | |
| ._6:nth-of-type(#{$p}) ~ .surface { | |
| .b#{5 + $step} { | |
| .block-outer { | |
| @include moveBlock(-1,0) | |
| } | |
| } | |
| .b#{6 + $step} { | |
| .block-outer { | |
| @include moveBlock(-2,0) | |
| } | |
| } | |
| .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| ._7:nth-of-type(#{$p}) ~ .surface { | |
| .b#{4 + $step}, .b#{7 + $step}, .b#{10 + $step}, .b#{13 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| .b#{5 + $step}, .b#{8 + $step}, .b#{11 + $step}, .b#{14 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| ._8:nth-of-type(#{$p}) ~ .surface { | |
| .b#{5 + $step}, .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| } | |
| ._9:nth-of-type(#{$p}) ~ .surface { | |
| .b#{5 + $step}, .b#{11 + $step} { | |
| .block-outer { | |
| @include moveBlock(1,0) | |
| } | |
| } | |
| .b#{10 + $step} { | |
| .block-outer { | |
| @include moveBlock(2,0) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /* Animations */ | |
| @keyframes bounce { | |
| from, 50%, to { | |
| transform: translateY(0); | |
| } | |
| 25%, 75% { | |
| transform: translateY($bounce); | |
| } | |
| } | |
| @keyframes tilt { | |
| from, to { | |
| transform: translateY(1em * $zSpaces/2) rotateX($xAngle) rotateZ(-$tilt); | |
| } | |
| 50% { | |
| transform: translateY(1em * $zSpaces/2) rotateX($xAngle) rotateZ($tilt); | |
| } | |
| } |