<!--
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>>>CLICK TO PLAY<<</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 */
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.