<!--
MAP

W = wall
R = red wall
D = door
G = goal
S = stone wall
* = start

x- 5 4 3 2 1 0 1 2 3 4 5 +x

       G G G G G G G
z-20     S       S
         S       S
         S       S
         S       S
         S       S
z-15     S       S
     W W W W D W W W W   
     W               W
     W   R       R   W
     W               W
z-10 W   R       R   W
     W               W
     W   R       R   W
     W               W
     W W W W D W W W W
z-5      W       W
         W   *   W
         W       W
         W W W W W

z0
x- 5 4 3 2 1 0 1 2 3 4 5 +x
-->
<!-- debug classes for #ui: debug-slowmo, debug-ending -->
<div id="ui">
  <input id="click-to-play" type="checkbox" /><label for="click-to-play">
    <div>
      <h1>CSS-Only Wolfenstein</h1>
      <h6>by Lu Wang</h6>
      <h2>&gt;&gt;CLICK TO PLAY&lt;&lt;</h2>
    </div>
  </label>
  <div class="youwin"><div>YOU WIN</div></div>
  <!-- weapon-fire must cover weapon, declare weapon first -->
  <div class="weapon"></div>
  <input type="checkbox" id="enemy1-check"/><div class="gameover"></div><div class="weapon-fire"></div>
  <input type="checkbox" id="enemy2-check"/><div class="gameover"></div><div class="weapon-fire"></div>
  <input type="checkbox" id="enemy3-check"/><div class="gameover"></div><div class="weapon-fire"></div>
  <input type="checkbox" id="enemy4-check"/><div class="gameover"></div><div class="weapon-fire"></div>
  <input type="checkbox" id="enemy5-check-1"/><div class="gameover"></div><div class="weapon-fire"></div>
  <input type="checkbox" id="enemy5-check-2"/><div class="gameover"></div><div class="weapon-fire"></div>
  <div id="scene" class="scene-v1">
    <div class="camera">
      <div class="camera-arm z">
        <div class="camera-arm x">
          <div class="camera-arm y">
            <div id="world">
              <div class="bj"></div>
              <div class="z-10">
                <div class="floor"></div>
                <div class="ceiling"></div>
              </div>
              <div id="enemy1"><div class="enemy"><label for="enemy1-check"></label></div></div>
              <div id="enemy2"><div class="enemy"><label for="enemy2-check"></label></div></div>
              <div id="enemy3"><div class="enemy"><label for="enemy3-check"></label></div></div>
              <div id="enemy4"><div class="enemy"><label for="enemy4-check"></label></div></div>
              <div id="enemy5"><div class="enemy">
                <label id="enemy5-check-label-1" for="enemy5-check-1"></label>
                <label id="enemy5-check-label-2" for="enemy5-check-2"></label>
              </div></div>
              <!-- goal -->
              <div class="z-21">
                <div class="x-1">
                  <div class="back wall goal"></div>
                </div>
                <div class="x0">
                  <div class="back wall goal"></div>
                </div>
                <div class="x1">
                  <div class="back wall goal"></div>
                </div>
              </div>
              <!-- before goal -->
              <!-- left wall -->
              <div class="x-2">
                <div class="z-20">
                  <div class="right wall rock"></div>
                </div>
                <div class="z-19">
                  <div class="right wall rock"></div>
                </div>
                <div class="z-18">
                  <div class="right wall rock"></div>
                </div>
                <div class="z-17">
                  <div class="right wall rock"></div>
                </div>
                <div class="z-16">
                  <div class="right wall rock"></div>
                </div>
                <div class="z-15">
                  <div class="right wall rock"></div>
                </div>
              </div>
              <!-- right wall -->
              <div class="x2">
                <div class="z-20">
                  <div class="left wall rock"></div>
                </div>
                <div class="z-19">
                  <div class="left wall rock"></div>
                </div>
                <div class="z-18">
                  <div class="left wall rock"></div>
                </div>
                <div class="z-17">
                  <div class="left wall rock"></div>
                </div>
                <div class="z-16">
                  <div class="left wall rock"></div>
                </div>
                <div class="z-15">
                  <div class="left wall rock"></div>
                </div>
              </div>
              <!-- big room -->
              <!-- front wall -->
              <div class="z-14">
                <div class="x-3">
                  <div class="back wall"></div>
                </div>
                <div class="x-2">
                  <div class="back wall"></div>
                </div>
                <div class="x-1">
                  <div class="back wall"></div>
                  <div class="front wall"></div>
                  <div class="right wall door"></div>
                </div>
                <div class="x3">
                  <div class="back wall"></div>
                </div>
                <div class="x2">
                  <div class="back wall"></div>
                </div>
                <div class="x1">
                  <div class="back wall"></div>
                  <div class="front wall"></div>
                  <div class="left wall door"></div>
                </div>
                <div id="door2" class="door"></div>
              </div>
              <!-- left wall -->
              <div class="x-4">
                <div class="z-13">
                  <div class="right wall"></div>
                </div>
                <div class="z-12">
                  <div class="right wall"></div>
                </div>
                <div class="z-11">
                  <div class="right wall"></div>
                </div>
                <div class="z-10">
                  <div class="right wall"></div>
                </div>
                <div class="z-9">
                  <div class="right wall"></div>
                </div>
                <div class="z-8">
                  <div class="right wall"></div>
                </div>
                <div class="z-7">
                  <div class="right wall"></div>
                </div>
              </div>
              <!-- right wall -->
              <div class="x4">
                <div class="z-13">
                  <div class="left wall"></div>
                </div>
                <div class="z-12">
                  <div class="left wall"></div>
                </div>
                <div class="z-11">
                  <div class="left wall"></div>
                </div>
                <div class="z-10">
                  <div class="left wall"></div>
                </div>
                <div class="z-9">
                  <div class="left wall"></div>
                </div>
                <div class="z-8">
                  <div class="left wall"></div>
                </div>
                <div class="z-7">
                  <div class="left wall"></div>
                </div>
              </div>
              <!-- poles -->
              <div class="x2">
                <div class="z-12">
                  <div class="left wall pole"></div>
                  <div class="front wall pole"></div>
                  <div class="right wall pole"></div>
                  <div class="back wall pole"></div>
                </div>
                <div class="z-10">
                  <div class="left wall pole"></div>
                  <div class="front wall pole"></div>
                  <div class="right wall pole"></div>
                  <div class="back wall pole"></div>
                </div>
                <div class="z-8">
                  <div class="left wall pole"></div>
                  <div class="front wall pole"></div>
                  <div class="right wall pole"></div>
                  <div class="back wall pole"></div>
                </div>
              </div>
              <div class="x-2">
                <div class="z-12">
                  <div class="left wall pole"></div>
                  <div class="front wall pole"></div>
                  <div class="right wall pole"></div>
                  <div class="back wall pole"></div>
                </div>
                <div class="z-10">
                  <div class="left wall pole"></div>
                  <div class="front wall pole"></div>
                  <div class="right wall pole"></div>
                  <div class="back wall pole"></div>
                </div>
                <div class="z-8">
                  <div class="left wall pole"></div>
                  <div class="front wall pole"></div>
                  <div class="right wall pole"></div>
                  <div class="back wall pole"></div>
                </div>
              </div>
              <!-- back wall -->
              <div class="z-6">
                <div class="x-3">
                  <div class="front wall"></div>
                </div>
                <div class="x-2">
                  <div class="front wall"></div>
                </div>
                <div class="x-1">
                  <div class="back wall"></div>
                  <div class="front wall"></div>
                  <div class="right wall door"></div>
                </div>
                <div class="x3">
                  <div class="front wall"></div>
                </div>
                <div class="x2">
                  <div class="front wall"></div>
                </div>
                <div class="x1">
                  <div class="back wall"></div>
                  <div class="front wall"></div>
                  <div class="left wall door"></div>
                </div>
                <div id="door1" class="door"></div>
              </div>
              <!-- small big room -->
              <!-- left wall -->
              <div class="x-2">
                <div class="z-5">
                  <div class="right wall"></div>
                </div>
                <div class="z-4">
                  <div class="right wall"></div>
                </div>
                <div class="z-3">
                  <div class="right wall"></div>
                </div>
              </div>
              <!-- right wall -->
              <div class="x2">
                <div class="z-5">
                  <div class="left wall"></div>
                </div>
                <div class="z-4">
                  <div class="left wall"></div>
                </div>
                <div class="z-3">
                  <div class="left wall"></div>
                </div>
              </div>
              <!-- back wall -->
              <div class="z-2">
                <div class="x-1">
                  <div class="front wall"></div>
                </div>
                <div class="x0">
                  <div class="front wall"></div>
                </div>
                <div class="x1">
                  <div class="front wall"></div>
                </div>
              </div>
              <!-- bullets -->
              <div id="bullet1"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet2"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet3"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet4"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet5"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet6"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet7"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet8"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet9"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet10"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet11"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet12"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet13"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet14"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet15"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              <div id="bullet16"><div class="bullet"><div class="face top"></div><div class="face left"></div><div class="face front"></div><div class="face right"></div><div class="face back"></div><div class="face bottom"></div></div></div>
              </div>
            </div> <!-- world -->
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
/*
Used spirtes:

https://www.textures-resource.com/pc_computer/wolf3d/texture/1375/

https://www.spriters-resource.com/pc_computer/wolfenstein3d/sheet/27847/

https://www.spriters-resource.com/pc_computer/wolfenstein3d/sheet/27855/
*/

@use "sass:math";

:root {
  --wall-size: 320px;
  --perspective: 500px;
  --slowmo-start: 16.5s;
  --slowmo-duration: 5s; 
  --bullet-size: 8px;
}

html, body, #scene, .camera, .camera-arm, #world {
  height: 100%;
  width: 100%;
}
 
body {
  background-color: black;
  display: flex;
  justify-content: center;
  align-items: center;
}

input { display: none; }
label, .gameover, .youwin {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

input#click-to-play + label {
  display: flex;
  justify-content: center;
  align-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 100;
}
input#click-to-play + label div {
  font-family: sans-serif;
  font-size: 32px;
  color: white;
}
input#click-to-play + label * {
  text-align: center;
}
input#click-to-play + label div h2 {
  font-family: "impact";
}

input#click-to-play:checked ~ label { display: none; }
/* An injured enemy must not "recover", if being clicked on the second time */
#enemy1-check:checked ~ #scene #enemy1 label,
#enemy2-check:checked ~ #scene #enemy2 label,
#enemy3-check:checked ~ #scene #enemy3 label,
#enemy4-check:checked ~ #scene #enemy4 label,
#enemy5-check-1:checked ~ #scene #enemy5 #enemy5-check-label-1,
#enemy5-check-2:checked ~ #scene #enemy5 #enemy5-check-label-2 {
  display: none;
}

/* disable 2nd hit at the beginning */
#enemy5-check-label-2 {
  top: 200%;
}

.youwin {
  top: 200%;
  // .youwin must be covered by .gameover
  z-index: 100;
}
.youwin div {
  font-family: "impact";
  font-size: 64px;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 50%;
  width: 100%;
  text-shadow: 2px 2px #777;
}
@keyframes youwin {
  to {
    top: 0;
  }
}

.gameover {
  top: 200%;
  background-color: red;
  z-index: 101;
}
.gameover:after {
  content: 'GAME OVER';
  font-family: "impact";
  font-size: 64px;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
}

#ui {
  position: absolute;
  border: 1px solid black;
  background-color: white;
  height: 600px;
  width: 800px;
  overflow: hidden;
}

#scene {
  perspective: var(--perspective);
}

.camera, .camera-arm {
  transform-style: preserve-3d;
}
 
#world {
  position: absolute;
  top: 50%;
  left: 50%;
  transform-style: preserve-3d;
}

#world * {
  transform-style: preserve-3d;
  position: absolute;
}

.floor, .ceiling {
  top: calc(var(--wall-size) * -12.5);
  left: calc(var(--wall-size) * -5.5);
  height: calc(var(--wall-size) * 25);
  width: calc(var(--wall-size) * 11);
}
.floor {
  transform: translateY(calc(var(--wall-size) * 0.5)) rotateX(90deg);
  background-color: #777;  
}
.ceiling {
  transform: translateY(calc(var(--wall-size) * -0.5)) rotateX(-90deg);
  background-color: #ccc;
}

.wall, .door, .enemy, .bj, .weapon, .weapon-fire {
  height: var(--wall-size);
  width: var(--wall-size);
  image-rendering: pixelated;
  background-image: url("https://i.ibb.co/YTmWH5M/spirtes.png");
  background-size: calc(var(--wall-size) * 5) calc(var(--wall-size) * 6);
}
.wall, .door, .enemy, .bj {
  position: absolute;
  top: calc(-0.5 * var(--wall-size));
  left: calc(-0.5 * var(--wall-size));
}

.wall { background-position: calc(var(--wall-size) * -4) calc(var(--wall-size) * -1); }
.wall.rock { background-position: calc(var(--wall-size) * -3) calc(var(--wall-size) * -4); }
.wall.goal {
  background-position: calc(var(--wall-size) * -4) calc(var(--wall-size) * -5);
  /* camera may go behind goal during ending. */
  backface-visibility: hidden;
}
.wall.door { background-position: calc(var(--wall-size) * -4) calc(var(--wall-size) * -3); }
.wall.pole { 
  background-position: calc(var(--wall-size) * -4) calc(var(--wall-size) * -2);
  /* camera may go inside poles during slowmo */
  backface-visibility: hidden;
}
.door { background-position: calc(var(--wall-size) * -4) calc(var(--wall-size) * -4); }
.wall.front { transform: translateZ(calc(-0.5 * var(--wall-size))) rotateY(180deg); }
.wall.back { transform: translateZ(calc(0.5 * var(--wall-size))); }
.wall.left { transform: translateX(calc(-0.5 * var(--wall-size))) rotateY(-90deg); }
.wall.right { transform: translateX(calc(0.5 * var(--wall-size))) rotateY(90deg); }

.bj {
  background-position: 0 calc(var(--wall-size) * -1);
}

@keyframes bj-run {
  0% {
    background-position: 0 calc(var(--wall-size) * -1);
  }
  25% {
    background-position: calc(var(--wall-size) * -1) calc(var(--wall-size) * -1); 
  }
  50% {
    background-position: calc(var(--wall-size) * -2) calc(var(--wall-size) * -1);
  }
  75% {
    background-position: calc(var(--wall-size) * -3) calc(var(--wall-size) * -1);
  } 
}

@keyframes bj-jump {
  0% {
    background-position: 0 calc(var(--wall-size) * -2);
  }
  33% {
    background-position: calc(var(--wall-size) * -1) calc(var(--wall-size) * -2); 
  }
  66% {
    background-position: calc(var(--wall-size) * -2) calc(var(--wall-size) * -2);
  }
  100% {
    background-position: calc(var(--wall-size) * -3) calc(var(--wall-size) * -2);
  }
}

@for $i from -4 through 4 {
  .x#{$i} {
    transform: translateX(calc(#{$i} * var(--wall-size)));
  }
}
@for $i from -21 through -2 {
  .z#{$i} {
    transform: translateZ(calc(#{$i} * var(--wall-size)));
  }
}

.weapon, .weapon-fire {
  position: absolute;
  left: 240px;
  bottom: calc(-1 * var(--wall-size));
  background-position: 0 0;
  z-index: 99;
  pointer-events: none;
}

.weapon {
  left: 240px;
}

/*********** debug ***********/
#ui.debug-overview input#click-to-play + label,
#ui.debug-overview .ceiling { 
  display: none; 
}
#ui.debug-overview .camera-arm.z {
  animation: camera-arm-z-overview-zoom 10s infinite;
}

@keyframes camera-arm-z-overview-zoom {
  0% {
    transform: translateZ(-500px);
  }
  50% {
    transform: translateZ(-1000px);
  }
  100% {
    transform: translateZ(-500px);
  }
}

#ui.debug-overview .camera-arm.y {
  transform: translateY(640px);
}

#ui.debug-overview .camera-arm.x {
  transform: rotateX(-25deg);
}

#ui.debug-slowmo .scene-v1 .bj {
  transform: translate3d(0, 0, calc(-10 * var(--wall-size))) rotateY(180deg);
}

#ui.debug-slowmo input#click-to-play + label,
#ui.debug-ending input#click-to-play + label { 
  display: none;
}

#ui.debug-slowmo .scene-v1 #world {
  animation-name: move-to-center, world-slowmo-move;
  animation-duration: 0.5s, var(--slowmo-duration);
  animation-delay: 0s, 1s;
  animation-timing-function: linear, ease-in-out;
  animation-iteration-count: 1, infinite;
  animation-fill-mode: forwards, forwards;
}

@keyframes world-slowmo-move {
  0% {
    transform: translate3d(0, 0, calc(10 * var(--wall-size)));
  }
  50% {
    transform: translate3d(0, 0, calc(11 * var(--wall-size)));
  }
  0% {
    transform: translate3d(0, 0, calc(10 * var(--wall-size)));
  }
}

#ui.debug-slowmo .scene-v1 #enemy5 {
  animation-name: enemy5-enter, enemy5-stay, enemy5-move-fast-steps;
  animation-duration: 0.5s, 0.1s, 0.5s;
  animation-delay: 0s, 0.5s, 0.6s;
  animation-timing-function: linear, step-start, ease-in-out;
  animation-iteration-count: 1, 1, infinite;
  animation-fill-mode: none, none, none;
}

#ui.debug-slowmo .scene-v1 #enemy5 .enemy {
  animation-name: enemy-walk, enemy-before-attack, enemy-attack;
  animation-duration: 0.5s, 0.1s, 0.1s;
  animation-delay: 0s, 0.5s, 0.6s;
  animation-timing-function: step-end, step-end, step-end;
  animation-iteration-count: 1, 1, infinite;
  animation-fill-mode: none, none, none;
}

#ui.debug-slowmo .scene-v1 .camera-arm.y {
  animation-name: camera-arm-y-slowmo-rotation;
  animation-duration: var(--slowmo-duration);
  animation-delay: 1s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-fill-mode: none;
}

#ui.debug-slowmo .scene-v1 .camera-arm.z {
  animation-name: camera-arm-z-slowmo-zoom;
  animation-duration: var(--slowmo-duration);
  animation-delay: 1s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-fill-mode: none;
}

#ui.debug-slowmo .scene-v1 .camera-arm.x {
  animation-name: camera-arm-x-slowmo-rotation;
  animation-duration: var(--slowmo-duration);
  animation-delay: 1s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-fill-mode: none;
}


#ui.debug-ending .scene-v1 #world {
  animation-name: in-front-of-door2, move-before-goal;
  animation-duration: 0.5s, 2s;
  animation-delay: 0s, 1s;
  animation-timing-function: linear, ease-out;
  animation-iteration-count: 1, 1;
  animation-fill-mode: forwards, forwards;
}

#ui.debug-ending .scene-v1 .bj {
  animation-name: bj-enter, bj-run, bj-run-towards-goal, bj-jump;
  animation-duration: 0.5s, 1.5s, 2s, 1s;
  animation-delay: 0s, 0s, 1s, 2s;
  animation-timing-function: step-start, step-end, ease-out, step-end;
  animation-iteration-count: 1, 3, 1, 1;
  animation-fill-mode: forwards, forwards, forwards, forwards;
}

#ui.debug-ending .scene-v1 .camera-arm.y {
  animation-name: camera-arm-y-ending;
  animation-duration: 1s;
  animation-delay: 1.5s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

#ui.debug-ending scene-v1 .camera-arm.z {
  animation-name: camera-arm-z-ending;
  animation-duration: 1s;
  animation-delay: 1.5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

#ui.debug-ending .scene-v1 .camera-arm.x {
  animation-name: camera-arm-x-ending;
  animation-duration: 1s;
  animation-delay: 1.5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

/*********** end of debug ***********/


/**************** animation V1 ****************/
/*
0s starting point
1s -> 2s move until in front of door1
2s -> 2.5s door1 open
3s -> 5s move in front of door2
5s -> 5.5s door2 open
  4.8s -> 5.3s enemy1 move west
  5.3s -> 5.5s enemy1 shoot
  6s -> maybe gameover
6s -> 6.5s turn left (west)
6.3s -> 7s move to top-left-corner
6.8s -> 7.3s turn 180 (east)
  7s -> 7.5s door2 close
  7s -> 7.5s enemy2 move south
  7.5s -> 7.7s enemy2 shoot
  8.2s -> maybe gameover
8.5s -> 10.5s move to bottom-left-corner
8.3s -> 8.8s turn left (north)
  10s -> 10.5s enemy3 move west
  10.5s -> 10.7s enemy3 shoot
  11.2s -> maybe gameover
11s -> 13s move to bottom-right-corner
  12s -> 12.5s enemy4 move west
  12.5s -> 12.7s enemy4 shoot
  13.2s -> maybe gameover
13.5s -> 14.5s move to lower-center-right
14s -> 14.5s turn left (west)
14.5s -> 15.5s move to lower-center
15s -> 15.5s turn right (north)
15.5s -> 16s move to center
  15.5s -> 16s enemy5 move west (speed x 2)
  16s -> 16.1s enemy5 shoot
  16.1s -> enemy5 move fast steps
  16.3s -> maybe gameover
16.5s -> 21.5s slowmo
  21s -> allow hit second hp
  21.8s -> maybe gameover
22.5s -> 23s move in front of door2
23s -> 23.5s door2 open
24s -> 26s move before goal
 24.5s -> 25.5s camera
 26s -> 26.5s you win
*/

.scene-v1 .camera {
  transform: translateZ(var(--perspective));
}

.scene-v1 #world {
  transform: translate3d(0, 0, calc(4 * var(--wall-size)));
}

#click-to-play:checked ~ .scene-v1 #world {
  animation-name: in-front-of-door1, in-front-of-door2, move-to-top-left-corner, move-to-bottom-left-corner, move-to-bottom-right-corner, move-to-lower-center-right, move-to-lower-center, move-to-center, world-slowmo-move, in-front-of-door2, move-before-goal;
  animation-duration: 1s, 2s, 0.7s, 2s, 2s, 1s, 1s, 0.5s, 5s, 0.5s, 2s;
  animation-delay: 1s, 3s, 6.3s, 8.5s, 11s, 13.5s, 14.5s, 15.5s, 16.5s, 22.5s, 24s;
  animation-timing-function: linear, linear, linear, linear, linear, linear, linear, linear, ease-in-out, linear, ease-out;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@keyframes in-front-of-door1 {
  to {
    transform: translate3d(0, 0, calc(5 * var(--wall-size)));
  }
}
@keyframes in-front-of-door2 {
  to {
    transform: translate3d(0, 0, calc(13 * var(--wall-size)));
  }
} 

@keyframes move-to-top-left-corner {
  to {
    transform: translate3d(calc(3 * var(--wall-size)), 0, calc(13 * var(--wall-size)));
  }
}
@keyframes move-to-bottom-left-corner {
  to {
    transform: translate3d(calc(3 * var(--wall-size)), 0, calc(7 * var(--wall-size)));
  }
}
@keyframes move-to-bottom-right-corner {
  to {
    transform: translate3d(calc(-3 * var(--wall-size)), 0, calc(7 * var(--wall-size)));
  }
}
@keyframes move-to-lower-center-right {
  to {
    transform: translate3d(calc(-3 * var(--wall-size)), 0, calc(9 * var(--wall-size)));
  }
}
@keyframes move-to-lower-center {
  to {
    transform: translate3d(0, 0, calc(9 * var(--wall-size)));
  }
}
@keyframes move-to-center {
  to {
    transform: translate3d(0, 0, calc(10 * var(--wall-size)));
  }
}
@keyframes move-before-goal {
  to {
    transform: translate3d(0, 0, calc(20 * var(--wall-size)));
  }
}

#click-to-play:checked ~ .scene-v1 .camera-arm.y {
  animation-name: turn-west, turn-east, turn-north, turn-west, turn-north, camera-arm-y-slowmo-rotation, camera-arm-y-ending;
  animation-duration: 0.5s, 0.5s, 0.5s, 0.5s, 0.5s, 5s, 1s;
  animation-delay: 6s, 6.8s, 8.3s, 14s, 15s, 16.5s, 24.5s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

#click-to-play:checked ~ .scene-v1 .camera-arm.z {
  animation-name: camera-arm-z-slowmo-zoom, camera-arm-z-ending;
  animation-duration: 5s, 1s;
  animation-delay: 16.5s, 24.5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@keyframes camera-arm-z-slowmo-zoom {
  0% {
    transform: translateZ(0);
  }
  10% {
    transform: translateZ(100px);
  }
  50% {
    transform: translateZ(-300px);
  }
  90% {
    transform: translateZ(100px);
  }
  100% {
    transform: translateZ(0);
  }
}

@keyframes camera-arm-z-ending {
  0% {
    transform: translateZ(0);
  }
  20% {
    transform: translateZ(100px);
  }
  100% {
    transform: translateZ(-200px);
  }
}

#click-to-play:checked ~ .scene-v1 .camera-arm.x {
  animation-name: camera-arm-x-slowmo-rotation, camera-arm-x-ending;
  animation-duration: 5s, 1s;
  animation-delay: 16.5s, 24.5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@keyframes camera-arm-x-slowmo-rotation {
  0% {
    transform: rotateX(0deg);
  }
  50% {
    transform: rotateX(-25deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}

@keyframes camera-arm-x-ending {
  0% {
    transform: rotateX(0deg);
  }
  100% {
    transform: rotateX(13deg);
  }
}

@keyframes turn-west {
  to {
    transform: rotateY(-90deg);
  }
}

@keyframes turn-east {
  to {
    transform: rotateY(90deg);
  }
}

@keyframes turn-north {
  to {
    transform: rotateY(0deg);
  }
}

@keyframes camera-arm-y-slowmo-rotation {
  0% {
    transform: rotateY(-360deg);
  }
  100% {
    transform: rotateY(0deg);
  }
}

@keyframes camera-arm-y-ending {
  0% {
    transform: rotateY(0deg);
  }
  100% {
    transform: rotateY(180deg);
  }
}

#click-to-play:checked ~ .scene-v1 #door1 {
  animation-name: door-open, door-close;
  animation-duration: 0.5s, 0.5s;
  animation-delay: 2s, 7s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

#click-to-play:checked ~ .scene-v1 #door2 {
  animation-name: door-open, door-close, door-open;
  animation-duration: 0.5s, 0.5s, 0.5s;
  animation-delay: 5s, 7s, 23s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@keyframes door-open {
  to {
    transform: translate3d(calc(1 * var(--wall-size)), 0, 0);
  }
}
@keyframes door-close {
  to {
    transform: translate3d(0, 0, 0);
  }
}

/*
  4.8s -> 5.3s enemy1 move left
  5.3s -> 5.5s enemy1 shoot
  6s -> maybe gameover
*/

#click-to-play:checked ~ .scene-v1 #enemy1 {
  animation-name: enemy1-enter, enemy1-stay, enemy-leave;
  animation-duration: 0.5s, 1.7s, 0.1s;
  animation-delay: 4.8s, 5.3s, 7s;
  animation-timing-function: linear, step-start, step-end;
  animation-iteration-count: 1, 1, 1;
  animation-fill-mode: none, none, forwards;
}

#click-to-play:checked ~ .scene-v1 #enemy1 .enemy {
  animation-name: enemy-walk, enemy-before-attack, enemy-attack;
  animation-duration: 0.5s, 0.2s, 0.1s;
  animation-delay: 0s, 5.3s, 5.5s;
  animation-timing-function: step-end, step-end, step-end;
  animation-iteration-count: 10.6, 1, infinite;
  animation-fill-mode: none, none, none;
}

#click-to-play:checked ~ #enemy1-check:not(:checked) + .gameover,
#click-to-play:checked ~ #enemy2-check:not(:checked) + .gameover,
#click-to-play:checked ~ #enemy3-check:not(:checked) + .gameover,
#click-to-play:checked ~ #enemy4-check:not(:checked) + .gameover,
#click-to-play:checked ~ #enemy5-check-1:not(:checked) + .gameover,
#click-to-play:checked ~ #enemy5-check-2:not(:checked) + .gameover{
  animation-name: show-gameover;
  animation-duration: 0.3s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

#click-to-play:checked ~ #enemy1-check:not(:checked) + .gameover {
  animation-delay: 6s;
}


#click-to-play:checked ~ #enemy1-check:checked ~ .scene-v1 #enemy1 .enemy,
#click-to-play:checked ~ #enemy2-check:checked ~ .scene-v1 #enemy2 .enemy,
#click-to-play:checked ~ #enemy3-check:checked ~ .scene-v1 #enemy3 .enemy,
#click-to-play:checked ~ #enemy4-check:checked ~ .scene-v1 #enemy4 .enemy {
  animation-name: enemy-hurt;
  animation-duration: 0s;
  animation-delay: 0s;
  animation-timing-function: step-end;
  animation-iteration-count: infinite;
  animation-fill-mode: forwards;
}

@keyframes enemy1-enter {
  from {
    transform: translate3d(calc(1 * var(--wall-size)), 0, calc(-15 * var(--wall-size)));
  }
  to {
    transform: translate3d(0, 0, calc(-15 * var(--wall-size)));
  }
}

@keyframes enemy1-stay {
  to {
    transform: translate3d(0, 0, calc(-15 * var(--wall-size)));
  }
}

@keyframes show-gameover {
  0% {
    top: 0;
    background-color: rgba(255, 0, 0, 0);
  }
  100% {
    top: 0;
    background-color: rgba(255, 0, 0, 1);
  }
}

@keyframes enemy-leave {
  to {
    transform: translate3d(0, 0, 0);
  }
}
@keyframes enemy-walk {
  0% {
    background-position: 0 calc(var(--wall-size) * -3);
  }
  25% {
    background-position: calc(var(--wall-size) * -1) calc(var(--wall-size) * -3); 
  }
  50% {
    background-position: calc(var(--wall-size) * -2) calc(var(--wall-size) * -3); 
  }
  75% {
    background-position: calc(var(--wall-size) * -3) calc(var(--wall-size) * -3); 
  }
}
@keyframes enemy-before-attack {
  0% {
    background-position: 0 calc(var(--wall-size) * -4);
  }
  100% {
    background-position: 0 calc(var(--wall-size) * -4);
  }
}

@keyframes enemy-attack {
  0% {
    background-position: calc(var(--wall-size) * -1) calc(var(--wall-size) * -4);
  }
  50% {
    background-position: calc(var(--wall-size) * -2) calc(var(--wall-size) * -4);
  }
}

@keyframes enemy-hurt {
  0% {
    background-position: 0 calc(var(--wall-size) * -5);
  }
  100% {
    background-position: 0 calc(var(--wall-size) * -5);
  }
}

/*
  7s -> 7.5s enemy2 move down
  7.5s -> 7.7s enemy2 shoot
  8.2s -> maybe gameover
*/

#click-to-play:checked ~ .scene-v1 #enemy2 {
  animation-name: enemy2-enter, enemy2-stay, enemy-leave;
  animation-duration: 0.5s, 1.3s, 0.1s;
  animation-delay: 7s, 7.5s, 8.8s;
  animation-timing-function: linear, step-start, step-end;
  animation-iteration-count: 1, 1, 1;
  animation-fill-mode: none, none, forwards;
}


#click-to-play:checked ~ .scene-v1 #enemy2 .enemy {
  animation-name: enemy-walk, enemy-before-attack, enemy-attack;
  animation-duration: 0.5s, 0.2s, 0.1s;
  animation-delay: 0s, 7.5s, 7.7s;
  animation-timing-function: step-end, step-end, step-end;
  animation-iteration-count: 15, 1, infinite;
  animation-fill-mode: none, none, none;
}

#click-to-play:checked ~ #enemy2-check:not(:checked) + .gameover {
  animation-delay: 8.2s;
}

@keyframes enemy2-enter {
  from {
    transform: translate3d(0, 0, calc(-14 * var(--wall-size))) rotateY(-90deg);
  }
  to {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size))) rotateY(-90deg);
  }
}

@keyframes enemy2-stay {
  to {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size))) rotateY(-90deg);
  }
}

/*
  10s -> 10.5s enemy3 move west
  10.5s -> 10.7s enemy3 shoot
  11.2s -> maybe gameover
*/

#click-to-play:checked ~ .scene-v1 #enemy3 {
  animation-name: enemy3-enter, enemy3-stay, enemy-leave;
  animation-duration: 0.5s, 1.5s, 0.1s;
  animation-delay: 10s, 10.5s, 12s;
  animation-timing-function: linear, step-start, step-end;
  animation-iteration-count: 1, 1, 1;
  animation-fill-mode: none, none, forwards;
}

#click-to-play:checked ~ .scene-v1 #enemy3 .enemy {
  animation-name: enemy-walk, enemy-before-attack, enemy-attack;
  animation-duration: 0.5s, 0.2s, 0.1s;
  animation-delay: 0s, 10.5s, 10.7s;
  animation-timing-function: step-end, step-end, step-end;
  animation-iteration-count: 21, 1, infinite;
  animation-fill-mode: none, none, none;
}

#click-to-play:checked ~ #enemy3-check:not(:checked) + .gameover {
  animation-delay: 11.2s;
}

@keyframes enemy3-enter {
  from {
    transform: translate3d(calc(-2 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
  to {
    transform: translate3d(calc(-3 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
}

@keyframes enemy3-stay {
  to {
    transform: translate3d(calc(-3 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
}

/*
  12s -> 12.5s enemy4 move west
  12.5s -> 12.7s enemy4 shoot
  13.2s -> maybe gameover
*/

#click-to-play:checked ~ .scene-v1 #enemy4 {
  animation-name: enemy4-enter, enemy4-stay, enemy-leave;
  animation-duration: 0.5s, 1.5s, 0.1s;
  animation-delay: 12s, 12.5s, 14s;
  animation-timing-function: linear, step-start, step-end;
  animation-iteration-count: 1, 1, 1;
  animation-fill-mode: none, none, forwards;
}

#click-to-play:checked ~ .scene-v1 #enemy4 .enemy {
  animation-name: enemy-walk, enemy-before-attack, enemy-attack;
  animation-duration: 0.5s, 0.2s, 0.1s;
  animation-delay: 0s, 12.5s, 12.7s;
  animation-timing-function: step-end, step-end, step-end;
  animation-iteration-count: 25, 1, infinite;
  animation-fill-mode: none, none, none;
}

#click-to-play:checked ~ #enemy4-check:not(:checked) + .gameover {
  animation-delay: 13.2s;
}

@keyframes enemy4-enter {
  from {
    transform: translate3d(calc(-2 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
  to {
    transform: translate3d(calc(-1 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
}

@keyframes enemy4-stay {
  to {
    transform: translate3d(calc(-1 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
}

/*
  15.5s -> 16s enemy5 move west (speed x 2)
  16s -> 16.1s enemy5 shoot
  16.1s -> enemy5 move fast steps
  16.3s -> maybe gameover
*/
#click-to-play:checked ~ .scene-v1 #enemy5 {
  animation-name: enemy5-enter, enemy5-stay, enemy5-move-fast-steps;
  animation-duration: 0.5s, 0.1s, 1s; 
  animation-delay: 15.5s, 16s, 16.1s;
  animation-timing-function: linear, step-start, ease-in-out;
  animation-iteration-count: 1, 1, infinite;
  animation-fill-mode: none, none, none;
}

#click-to-play:checked ~ .scene-v1 #enemy5 .enemy {
  animation-name: enemy-walk, enemy-before-attack, enemy-attack;
  animation-duration: 0.5s, 0.1s, 0.1s;
  animation-delay: 0s, 16s, 16.1s;
  animation-timing-function: step-end, step-end, step-end;
  animation-iteration-count: 32, 1, infinite;
  animation-fill-mode: none, none, none;
}

#click-to-play:checked ~ #enemy5-check-1:not(:checked) + .gameover {
  animation-delay: 16.3s;
}

#click-to-play:checked ~ #enemy5-check-2:not(:checked) + .gameover {
  animation-delay: 21.8s;
}

@keyframes enemy5-enter {
  from {
    transform: translate3d(calc(2 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
  to {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size)));
  }
}

@keyframes enemy5-stay {
  to {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size)));
  }
}

@keyframes enemy5-move-fast-steps {
  0% {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size)));
  }
  25% {
    transform: translate3d(calc(-2 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
  50% {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size)));
  }
  75% {
    transform: translate3d(calc(2 * var(--wall-size)), 0, calc(-13 * var(--wall-size)));
  }
  100% {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size)));
  }
}

#click-to-play:checked ~ .scene-v1 #enemy5-check-label-2 {
  animation: enemy-check-label-show 0.1s step-start 21s forwards; 
}

@keyframes enemy-check-label-show {
  to {
    top: 0;
  }
}

#click-to-play:checked ~ #enemy5-check-2:checked ~ .scene-v1 #enemy5 {
  /*
  animation-name: enemy5-stay;
  animation-duration: 1s;
  animation-delay: 0s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
  */
  animation-play-state: paused;
}

/* enemy-5-check-1 does not show hurt animation */
#click-to-play:checked ~ #enemy5-check-2:checked ~ .scene-v1 #enemy5 .enemy {
  animation-name: enemy-hurt-then-die;
  animation-duration: 1s;
  animation-delay: 0s;
  animation-timing-function: step-end;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@keyframes enemy-hurt-then-die {
  0% {
    background-position: 0 calc(var(--wall-size) * -5);
  }
  33% {
    background-position: calc(var(--wall-size) * -1) calc(var(--wall-size) * -5);
  }
  66% {
    background-position: calc(var(--wall-size) * -2) calc(var(--wall-size) * -5);
  }
  100% {
    background-position: calc(var(--wall-size) * -3) calc(var(--wall-size) * -5);
  }
}

#click-to-play:checked ~ .scene-v1 .bj {
  animation-name: bj-enter, bj-run, bj-run-towards-goal, bj-jump;
  animation-duration: 0.1s, 0.5s, 2s, 1s;
  animation-delay: 16.4s, 0s, 24s, 25s;
  animation-timing-function: step-start, step-end, ease-out, step-end;
  animation-iteration-count: 1, 50, 1, 1;
  animation-fill-mode: forwards;
}

@keyframes bj-enter {
  to {
    transform: translate3d(0, 0, calc(-10 * var(--wall-size))) rotateY(180deg);  
  }
}

@keyframes bj-run-towards-goal {
  from {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size))) rotateY(180deg);  
  }
  to {
    transform: translate3d(0, 0, calc(-18 * var(--wall-size))) rotateY(180deg);  
  }
}

#click-to-play:checked ~ .youwin {
  animation: youwin 0.5s ease-out 26s forwards;
}

/************* weapon *************/

#click-to-play:checked ~ .weapon {
  animation-name: weapon-show, weapon-hide, weapon-show, weapon-hide;
  animation-duration: 0.5s, 0.5s, 0.5s, 0.5s;
  animation-delay: 0s, 16.5s, 20.5s, 24.5s;
  animation-timing-function: ease-out;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@keyframes weapon-show {
  to {
    bottom: 0;
  }
}
@keyframes weapon-hide {
  to {
    bottom: calc(-1 * var(--wall-size));
  }
}

#enemy1-check:checked + * + .weapon-fire,
#enemy2-check:checked + * + .weapon-fire,
#enemy3-check:checked + * + .weapon-fire,
#enemy4-check:checked + * + .weapon-fire,
#enemy5-check-1:checked + * + .weapon-fire,
#enemy5-check-2:checked + * + .weapon-fire, {
  animation-name: weapon-fire;
  animation-duration: 0.5s;
  animation-delay: 0s;
  animation-timing-function: step-end;
  animation-iteration-count: 1;
  animation-fill-mode: none;
}

@keyframes weapon-fire {
  0% {
    bottom: 0;
    background-position: calc(var(--wall-size) * -2) 0;
  }
  33% {
    bottom: 0;
    background-position: calc(var(--wall-size) * -3) 0;
  }
  66% {
    bottom: 0;
    background-position: calc(var(--wall-size) * -4) 0;
  }
  100% {
    bottom: calc(-1 * var(--wall-size));
    background-position: 0 0;
  }
}

/************* bullet *************/
.bullet .face{
  position: absolute;
  top: calc(-0.5 * var(--bullet-size));
  left: calc(-0.5 * var(--bullet-size));
  height: var(--bullet-size);
  width: var(--bullet-size);
  background-color: red;
}
.bullet .face.front { transform: translateZ(calc(-0.5 * var(--bullet-size))) rotateY(180deg); }
.bullet .face.back { transform: translateZ(calc(0.5 * var(--bullet-size))); }
.bullet .face.left { transform: translateX(calc(-0.5 * var(--bullet-size))) rotateY(-90deg); }
.bullet .face.right { transform: translateX(calc(0.5 * var(--bullet-size))) rotateY(90deg); }
.bullet .face.top { transform: translateY(calc(var(--bullet-size) * 0.5)) rotateX(90deg); }
.bullet .face.bottom { transform: translateY(calc(var(--bullet-size) * -0.5)) rotateX(-90deg); }

#click-to-play:checked ~ .scene-v1 .bullet {
  animation-name: bullet-effect;
  animation-duration: 1s;
  animation-delay: 0s;
  animation-timing-function: linear;
  animation-iteration-count: 4;
  animation-fill-mode: none;
}

@keyframes bullet-effect {
  0% {
    transform: translate3d(0, 0, calc(-13 * var(--wall-size))); 
  }
  100% {
    transform: translate3d(0, 0, calc(-5 * var(--wall-size))); 
  }
}

@for $i from 1 through 16 {
  #click-to-play:checked ~ .scene-v1 #bullet#{$i} {
    transform: translate3d(
      calc((#{math.random()} * 2 - 1) * var(--wall-size)),
      calc((#{math.random()} * 0.5 - 0.25) * var(--wall-size)),
      calc((#{math.random()} * 1) * var(--wall-size)),
    );
  }
  #click-to-play:checked ~ .scene-v1 #bullet#{$i} .bullet {
    animation-delay: calc(#{math.random()}s + var(--slowmo-start));
  }
}
View Compiled
/* Look ma no JS */
/* https://wang-lu.com */

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.