Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!--
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>
              
            
!

CSS

              
                /*
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));
  }
}

              
            
!

JS

              
                /* Look ma no JS */
/* https://wang-lu.com */
              
            
!
999px

Console