First steps, need to sort out perspective stuff with the lights.
A Pen by Mario Nebl on CodePen.
| <nav class="toolbar"> | |
| <label class="trigger" for="animationstate">Toggle animation</label> | |
| <label class="trigger" for="gutterstate">Toggle plain gutter</label> | |
| </nav> | |
| <input type="checkbox" class="state animationstate" id="animationstate" /> | |
| <input type="checkbox" class="state gutterstate" id="gutterstate" /> | |
| <div class="camera"> | |
| <div class="scene"> | |
| <figure class="pyramid"> | |
| <div class="base"></div> | |
| <div class="face"></div> | |
| <div class="face"></div> | |
| <div class="face"></div> | |
| <div class="face"></div> | |
| </figure> | |
| <div class="light"> | |
| <div class="incoming"></div> | |
| <div class="outgoing"></div> | |
| </div> | |
| </div> | |
| </div> |
| var sceneEl = document.querySelectorAll('.scene')[0]; | |
| var sceneTransform = { | |
| x: 90, | |
| y: 0, | |
| dirty: false | |
| }; | |
| var moveScene = function(){ | |
| if (! sceneTransform.dirty) { | |
| return requestAnimationFrame(moveScene); | |
| } | |
| sceneEl.style.transform = 'rotateX('+ sceneTransform.x + 'deg) rotateY('+ sceneTransform.y +'deg)'; | |
| sceneTransform.dirty = false; | |
| requestAnimationFrame(moveScene); | |
| } | |
| requestAnimationFrame(moveScene); | |
| var setScene = function(x, y) { | |
| y = y || 0; | |
| sceneTransform.x = sceneTransform.x + x; | |
| sceneTransform.y = sceneTransform.y + y; | |
| sceneTransform.dirty = true; | |
| } | |
| document.addEventListener('keydown', function(e){ | |
| switch(e.keyCode){ | |
| case 38: // up | |
| case 87: // w | |
| setScene(1, 0); | |
| break; | |
| case 39: // right | |
| case 68: // d | |
| setScene(0, 1); | |
| break; | |
| case 40: // down | |
| case 83: // s | |
| setScene(-1, 0); | |
| break; | |
| case 37: // left | |
| case 65: // a | |
| setScene(0, -1); | |
| break; | |
| } | |
| }, false); |
| @b:20rem; | |
| @h:20rem; | |
| @sceneTransform: rotateX(90deg); | |
| @gutterTransform: translateZ(-100px); | |
| @borderWidth:.2rem; | |
| @borderColor:#b7d4da; | |
| @a:sqrt(@b/2 * @b/2 + @h*@h); | |
| @aRel:sqrt(@a/@b); | |
| @bRel:sqrt(@b/@a); | |
| @sideLength:sqrt(@b/2 * @b/2 + @h*@h); | |
| @sideDeg:asin(@b/1.95 / @sideLength); | |
| @closeDeg:120deg; // todo: calculate | |
| @skewOffset:75%; | |
| @secondSideTransform: translate3d(-@b/2, -@b/@h*50%, 0) rotate(90deg); | |
| @thirdSideTransform: translate3d(0%, -@b, 0) rotate(180deg); | |
| @fourthSideTransform: translate3d(@b/2, -@b/@h*50%, 0) rotate(-90deg); | |
| @keyframes rotate{ | |
| 0% { | |
| transform: rotate(0); | |
| } | |
| 100% { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| @keyframes discodisco{ | |
| 0% { | |
| filter: saturate(1); | |
| } | |
| 50% { | |
| filter: saturate(0.1); | |
| } | |
| } | |
| @keyframes pulse{ | |
| 0% { | |
| opacity: 1; | |
| } | |
| 50% { | |
| opacity: .3; | |
| } | |
| } | |
| @keyframes shine{ | |
| 0% { | |
| transform: skewX(-75deg) scaleX(0); | |
| } | |
| 100% { | |
| transform: skewX(-75deg) scaleX(1); | |
| } | |
| } | |
| @keyframes break{ | |
| 0% { | |
| transform: skewX((360deg - @closeDeg - 30deg)*-1) skewY(-17deg) translateY(100px) translateX(100px) scaleX(0); | |
| } | |
| 100% { | |
| transform: skewX((360deg - @closeDeg - 30deg)*-1) skewY(-17deg) translateY(100px) translateX(100px) scaleX(1); | |
| } | |
| } | |
| *{ | |
| box-sizing: border-box; | |
| } | |
| figure{ | |
| margin: 0; | |
| } | |
| html,body{ | |
| margin: 0; | |
| padding: 0; | |
| height: 100%; | |
| background: #000; | |
| font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
| font-size: 10px; | |
| color: #fff; | |
| width: 100%; | |
| overflow: hidden; | |
| } | |
| .toolbar{ | |
| position: fixed; | |
| width: 100%; | |
| z-index: 10; | |
| padding: 5px; | |
| background: rgba(255,255,255,.4); | |
| } | |
| .trigger{ | |
| display: inline-block; | |
| font-size: 1.3rem; | |
| padding: 5px 10px; | |
| &:hover, | |
| &:active{ | |
| background: rgba(0,0,0,.3); | |
| transition: .3s background ease-in; | |
| } | |
| } | |
| .state{ | |
| position: absolute; | |
| top: 0; | |
| left: -100vw; | |
| } | |
| .camera{ | |
| display: flex; | |
| align-items: center; | |
| height: 100%; | |
| persepective: 1000px; | |
| } | |
| .scene{ | |
| flex-grow: 1; | |
| text-align: center; | |
| transform: @sceneTransform; | |
| transform-style: preserve-3d; | |
| animation-play-state: paused; | |
| &::before{ | |
| content: ''; | |
| opacity: 0; | |
| position: absolute; | |
| top: -500vh; | |
| left: -500vw; | |
| display: block; | |
| height: 1000vh; | |
| width: 1000vw; | |
| transition: .3s opacity ease-in; | |
| transform: @gutterTransform; | |
| background-image: linear-gradient(fadeout(#fff, 50%) 2px, transparent 2px), | |
| linear-gradient(90deg, fadeout(#fff, 50%) 2px, transparent 2px), | |
| linear-gradient(fadeout(#fff, 70%) 1px, transparent 1px), | |
| linear-gradient(90deg, fadeout(#fff, 70%) 1px, transparent 1px); | |
| background-size:100px 100px, 100px 100px, 20px 20px, 20px 20px; | |
| background-position:-2px -2px, -2px -2px, -1px -1px, -1px -1px; | |
| } | |
| } | |
| .pyramid{ | |
| display: inline-block; | |
| animation-play-state: inherit; | |
| transform-style: preserve-3d; | |
| } | |
| .base,.face{ | |
| transform-origin: 50% 0; | |
| transition: .3s transform ease-in; | |
| } | |
| .base{ | |
| content: '@{sideDeg}'; | |
| width: @b; | |
| height: @b; | |
| border: @borderWidth solid @borderColor; | |
| box-shadow: inset 0 0 1rem fadeout(@borderColor, 90%), 0 0 1rem fadeout(@borderColor, 90%); | |
| } | |
| .face{ | |
| position: absolute; | |
| z-index:1; | |
| width: @b; | |
| height: @h; | |
| -webkit-clip-path: polygon(100/3% 0, 50% 100%, 100*2/3% 0); | |
| -moz-clip-path: polygon(100/3% 0, 50% 100%, 100*2/3% 0); | |
| -ms-clip-path: polygon(100/3% 0, 50% 100%, 100*2/3% 0); | |
| clip-path: polygon(100/3% 0, 50% 100%, 100*2/3% 0); | |
| border-top: @borderWidth solid @borderColor; | |
| &:nth-child(2){ | |
| transform: rotateX(@closeDeg); | |
| } | |
| &:nth-child(3){ | |
| transform: @secondSideTransform rotateX(@closeDeg); | |
| } | |
| &:nth-child(4){ | |
| transform: @thirdSideTransform rotateX(@closeDeg); | |
| } | |
| &:nth-child(5){ | |
| transform: @fourthSideTransform rotateX(@closeDeg); | |
| } | |
| &::before, | |
| &::after{ | |
| content: ''; | |
| position: absolute; | |
| z-index:2; | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| box-sizing: border-box; | |
| box-shadow: inset 0 1px 1rem fadeout(@borderColor, 50%), inset 1px 0 1rem fadeout(@borderColor, 50%), inset 0 -1px 1rem fadeout(@borderColor, 50%), inset -1px 0 1rem fadeout(@borderColor, 50%), 0 1px .3rem fadeout(@borderColor, 50%), 1px 0 .3rem fadeout(@borderColor, 50%), 0 -1px .3rem fadeout(@borderColor, 50%), -1px 0 .3rem fadeout(@borderColor, 50%); | |
| } | |
| &::before{ | |
| transform: skewX(@sideDeg) translateX(-@skewOffset); // todo: calculate | |
| border-right: @borderWidth solid @borderColor; | |
| } | |
| &::after{ | |
| transform: skewX(-@sideDeg) translateX(@skewOffset); // todo: calculate | |
| border-left: @borderWidth solid @borderColor; | |
| } | |
| } | |
| .animationstate:checked ~ .camera{ | |
| .scene{ | |
| animation-play-state: running; | |
| } | |
| } | |
| .gutterstate:checked ~ .camera{ | |
| .scene::before{ | |
| opacity: 1; | |
| } | |
| } | |
| .light{ | |
| position: fixed; | |
| right: 0; | |
| left: 0; | |
| height: 60%; | |
| transform: rotateX(90deg) translateZ(@b/2); | |
| transform-origin: 0 top; | |
| animation-play-state: inherit; | |
| .incoming{ | |
| position: absolute; | |
| right: 50%; | |
| height: 100%; | |
| width: 50%; | |
| transform: rotateX(180deg) rotateZ(3deg); | |
| animation-play-state: inherit; | |
| &::before{ | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| right: 0; | |
| left: -20px; | |
| z-index: 2; | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| box-sizing: border-box; | |
| border-right: 12px solid rgba(255,255,255,0.8); | |
| transform: skewX(-75deg); | |
| transform-origin: 100% 0; | |
| animation: pulse 5s infinite, shine .3s linear 1; | |
| animation-play-state: inherit; | |
| } | |
| } | |
| .outgoing{ | |
| position: absolute; | |
| left: 50%; | |
| height: 100%; | |
| width: 50%; | |
| transform-style: preserve-3d; | |
| tranform: rotateZ(-3deg); | |
| animation-play-state: inherit; | |
| } | |
| .outgoing{ | |
| &::before{ | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| display: block; | |
| width: 100%; | |
| height: 50px; | |
| background: linear-gradient(to top, #dc1231, #dc1231 16.666% , #e98d14 16.666%, #e98d14 33.332%, #ffff29 33.332%, #ffff29 49.998%, #75bf27 49.998%, #75bf27 66.664%, #73cbee 66.664%, #73cbee 83.333%, #6a518f 83.333%); | |
| transform-origin: 0 0; | |
| transform: skewX((360deg - @closeDeg - 30deg)*-1) skewY(-17deg) translateY(100px) translateX(100px); | |
| animation: discodisco 5s infinite, break .3s linear 1; | |
| animation-play-state: inherit; | |
| } | |
| } | |
| } |
First steps, need to sort out perspective stuff with the lights.
A Pen by Mario Nebl on CodePen.