Compare commits
160 Commits
baf6e66244
...
white-bord
| Author | SHA1 | Date | |
|---|---|---|---|
|
36112f1ec8
|
|||
|
b28b44507b
|
|||
|
24b0e72eab
|
|||
|
ab105bf485
|
|||
|
ea8dbff564
|
|||
|
9a2989616a
|
|||
|
d6006e657f
|
|||
|
ce758c1e92
|
|||
|
8a0590f1b3
|
|||
|
70caed8fb8
|
|||
|
b6eeae15b9
|
|||
|
45c0e090e5
|
|||
|
73ec2015ba
|
|||
|
91e1ea9d3a
|
|||
|
798ac21372
|
|||
|
2820c42ba8
|
|||
|
8e043b9e8c
|
|||
|
136ea4156f
|
|||
|
c01c6dcf58
|
|||
|
25826565af
|
|||
|
56b906723c
|
|||
|
20b96da34b
|
|||
|
bd195f7da6
|
|||
|
06b444c37e
|
|||
|
71945a7ade
|
|||
|
0956e3d6e0
|
|||
|
cc4c477a10
|
|||
|
e196d931ca
|
|||
|
a4117b782a
|
|||
|
3e3fd6d7f4
|
|||
|
50a4536994
|
|||
|
a4e210526f
|
|||
|
cb49d42266
|
|||
|
90b1251ebf
|
|||
|
26a4d113b5
|
|||
|
b3d012f489
|
|||
|
021d67b877
|
|||
|
3af40de841
|
|||
|
2d700f1927
|
|||
|
280ff0ef9f
|
|||
|
8e5b45bf6f
|
|||
|
18977dfd1b
|
|||
|
334e0e0178
|
|||
|
02a24ec1f2
|
|||
|
0cb9fd4c27
|
|||
|
e21f9c7dfa
|
|||
|
baf5672de8
|
|||
|
9ed62d1e79
|
|||
|
2a5ce8faab
|
|||
|
4f7d44de4b
|
|||
|
44e048624a
|
|||
|
d7fa6c4fe5
|
|||
|
b5ece6f892
|
|||
|
181b6d28f6
|
|||
|
616b364d40
|
|||
|
e17517e2eb
|
|||
|
e4c0ba5719
|
|||
|
a1028cb054
|
|||
|
1babf41efe
|
|||
|
8d371a52ec
|
|||
|
743e23d729
|
|||
|
46ca9f92d3
|
|||
|
6d0b93dfdb
|
|||
|
97ca770641
|
|||
|
3093d880aa
|
|||
|
fe77be0381
|
|||
|
a7fae60a1c
|
|||
|
7927038fb2
|
|||
|
bb74fbef45
|
|||
|
994a7a7f04
|
|||
|
0c186ccd59
|
|||
|
44d68d79cc
|
|||
|
52a7f37eb0
|
|||
|
1f78b2dc10
|
|||
|
491f5c021a
|
|||
|
c4d9621551
|
|||
|
3d8bc0ce11
|
|||
|
3f665d115a
|
|||
|
d2d4a8e737
|
|||
|
fb4755c870
|
|||
|
3729a3762a
|
|||
| 4b2cd0e5d2 | |||
| 08763c501e | |||
| bc5de2448d | |||
| 67a0f06d03 | |||
| 2f1ec2a6f7 | |||
| 26aeb8f9a2 | |||
| 051fc223e9 | |||
| 9feaa3c098 | |||
| 3175e7b7ad | |||
| 4281bf1735 | |||
| ff37cb7823 | |||
| 2a8df78d22 | |||
| 344575bdc4 | |||
| 2453b2f6b6 | |||
| 25a98bf42d | |||
| 022512a5e6 | |||
| d56af40362 | |||
| f33723a786 | |||
| df95139650 | |||
| d3b527570c | |||
| a1722a700d | |||
| 6cc8a9e645 | |||
| 9023252822 | |||
| 9bf3c0de0c | |||
| 09f4785ef4 | |||
| bf9554d917 | |||
| c33d80facb | |||
| 9282f94956 | |||
| fda289dc9c | |||
| b6e58b41aa | |||
| bd5c7dad3b | |||
| 7faae294dc | |||
| 3b59534f90 | |||
| ec08747066 | |||
| db8a9a3f74 | |||
| 0ac36444c4 | |||
| 5d451db8f9 | |||
| ab023ec982 | |||
| d75696fbc3 | |||
| f97b5f0cf9 | |||
| ffefb77f3f | |||
| 21929261e4 | |||
| 58389623cc | |||
| 04f6eaf5dc | |||
| d56a8a6b06 | |||
| e1992f4c1e | |||
| 27d7a0689d | |||
| df62a40c2a | |||
| 2105296238 | |||
| 05862b8587 | |||
| 6c1291833d | |||
| 095e3f8dbe | |||
| 82929b6f3b | |||
| 29661421a5 | |||
| d3a6f5d6d6 | |||
| 8af1801527 | |||
| 6d95acddd2 | |||
| 6062f6895b | |||
| b726e95bed | |||
| 228fc56916 | |||
| f39d677b62 | |||
| fc21a1b12b | |||
| 072661ff5a | |||
| f93f3c71af | |||
| ed4d9b82c9 | |||
| b17db2ffd4 | |||
| 9f8c38e6bf | |||
| 262a26940c | |||
| 7996e4a7ae | |||
| a0af16d0dd | |||
| 9547e585ca | |||
| 4d0d51e20d | |||
| e7246c0a5d | |||
| 50502be1d1 | |||
| a89a60691c | |||
| a04e118ff1 | |||
| ef8ddca950 | |||
| 8773e65885 | |||
| ebb9f4810b |
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Quatuor
|
||||
|
||||
Falling blocks
|
||||
|
||||

|
||||
187
css/classic.css
187
css/classic.css
@@ -1,118 +1,119 @@
|
||||
.minoes-table {
|
||||
filter:
|
||||
drop-shadow(-1px -1px 0 white)
|
||||
drop-shadow( 1px 1px 0 white);
|
||||
}
|
||||
|
||||
.minoes-table tr {
|
||||
z-index: calc(100 - var(--row));
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
tr.matrix td:not(.mino) {
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
border-right: 1px solid #30303003;
|
||||
border-top: 1px solid #30303003;
|
||||
}
|
||||
|
||||
.mino {
|
||||
background: radial-gradient(
|
||||
ellipse 140% 66% at 122% 88%,
|
||||
var(--background-color) 100%,
|
||||
var(--frontier-color) 105%,
|
||||
var(--light-color) 130%
|
||||
--color: hsl(var(--hue), var(--saturation), 40%);
|
||||
--light: hsl(var(--hue), calc(0.66 * var(--saturation)), 84%);
|
||||
--top: hsl(var(--hue), calc(0.6 * var(--saturation)), 68%);
|
||||
background-color: var(--color);
|
||||
background-image:
|
||||
radial-gradient(
|
||||
ellipse 22% 8% at 25% 22%,
|
||||
#ffffff66,
|
||||
#ffffff33 40%,
|
||||
transparent 70%
|
||||
),
|
||||
radial-gradient(
|
||||
ellipse 140% 85% at 50% -15%,
|
||||
var(--light) 0%,
|
||||
#ffffff77 40%,
|
||||
#00000005 55%
|
||||
),
|
||||
radial-gradient(
|
||||
ellipse 120% 220% at 50% 140%,
|
||||
var(--light) 0%,
|
||||
var(--color) 55%,
|
||||
#00000066 95%
|
||||
);
|
||||
border: 4px solid;
|
||||
padding: 0;
|
||||
opacity: 100%;
|
||||
border-radius: 1px;
|
||||
border: 4px ridge var(--color);
|
||||
border-top-color: var(--light);
|
||||
border-radius: 3px;
|
||||
box-shadow:
|
||||
inset 2px 0 4px rgba(0,0,0,.06),
|
||||
inset -2px 0 4px rgba(0,0,0,.12),
|
||||
0 -4px 0 var(--top);
|
||||
filter: saturate(1.1) contrast(1.05);
|
||||
}
|
||||
|
||||
.I.mino {
|
||||
--background-color: #009FdA;
|
||||
--frontier-color: #43e7fd;
|
||||
--light-color: #afeff9;
|
||||
border-top-color: #7cf2fd;
|
||||
border-left-color: #2ed5e5;
|
||||
border-right-color: #00b8ca;
|
||||
border-bottom-color: #00a4b0;
|
||||
.I {
|
||||
--hue: 193;
|
||||
--saturation: 100%;
|
||||
}
|
||||
|
||||
.J.mino {
|
||||
--background-color: #2E00FB;
|
||||
--frontier-color: #7054fb;
|
||||
--light-color: #b8b4ff;
|
||||
border-top-color: #4985fd;
|
||||
border-left-color: #2f36ea;
|
||||
border-right-color: #0006ca;
|
||||
border-bottom-color: #00009d;
|
||||
.J {
|
||||
--hue: 215;
|
||||
--saturation: 100%;
|
||||
}
|
||||
|
||||
.L.mino {
|
||||
--background-color: #FF7900;
|
||||
--frontier-color: #fe9551;
|
||||
--light-color: #fdd0b7;
|
||||
border-top-color: #fd9f6b;
|
||||
border-left-color: #e76d28;
|
||||
border-right-color: #e74f00;
|
||||
border-bottom-color: #c54800;
|
||||
.L {
|
||||
--hue: 25;
|
||||
--saturation: 100%;
|
||||
}
|
||||
|
||||
.O.mino {
|
||||
--background-color: #FeCB00;
|
||||
--frontier-color: #fce15c;
|
||||
--light-color: #ffedac;;
|
||||
border-top-color: #ffe364;
|
||||
border-left-color: #e7ba23;
|
||||
border-right-color: #e3a707;
|
||||
border-bottom-color: #ca9501;
|
||||
.O {
|
||||
--hue: 42;
|
||||
--saturation: 100%;
|
||||
}
|
||||
|
||||
.S.mino {
|
||||
--background-color: #67EE12;
|
||||
--frontier-color: #93f85a;
|
||||
--light-color: #C8FBA8;
|
||||
border-top-color: #a4fc6d;
|
||||
border-left-color: #5ee82b;
|
||||
border-right-color: #35db00;
|
||||
border-bottom-color: #1cbc02;
|
||||
.S {
|
||||
--hue: 95;
|
||||
--saturation: 100%;
|
||||
}
|
||||
|
||||
.T.mino {
|
||||
--background-color: #B000FE;
|
||||
--frontier-color: #c541fc;
|
||||
--light-color: #edb2ff;
|
||||
border-top-color: #d380ff;
|
||||
border-left-color: #b42deb;
|
||||
border-right-color: #8000cd;
|
||||
border-bottom-color: #6e019a;
|
||||
.T {
|
||||
--hue: 300;
|
||||
--saturation: 56%;
|
||||
}
|
||||
|
||||
.Z.mino {
|
||||
--background-color: #ed2939;
|
||||
--frontier-color: #fe6483;
|
||||
--light-color: #ffb8c5;
|
||||
border-top-color: #fd718d;
|
||||
border-left-color: #e62250;
|
||||
border-right-color: #e20332;
|
||||
border-bottom-color: #ad1936;
|
||||
.Z {
|
||||
--hue: 357;
|
||||
--saturation: 84%;
|
||||
}
|
||||
|
||||
.ghost.mino {
|
||||
background: rgba(0, 0, 0, 10%) !important;
|
||||
border: 3px solid rgba(128, 128, 128, 25%) !important;
|
||||
box-shadow: -2px -2px 6px rgba(128, 128, 128, 25%),
|
||||
-2px 2px 6px rgba(128, 128, 128, 25%),
|
||||
2px -2px 6px rgba(128, 128, 128, 25%),
|
||||
2px 2px 6px rgba(128, 128, 128, 25%);
|
||||
.ghost {
|
||||
border: 3px solid #fff1;
|
||||
padding: 2px;
|
||||
background-color: #fff1;
|
||||
background-clip: content-box;
|
||||
background-image: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.moving.mino {
|
||||
filter: saturate(80%) brightness(150%);
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
filter: saturate(50%) brightness(200%);
|
||||
box-shadow: -1px -1px 4px rgba(128, 128, 128, 25%),
|
||||
-1px 1px 4px rgba(128, 128, 128, 25%),
|
||||
1px -1px 4px rgba(128, 128, 128, 25%),
|
||||
1px 1px 4px rgba(128, 128, 128, 25%);
|
||||
}
|
||||
|
||||
@keyframes locked-animation {
|
||||
@keyframes trail-animation {
|
||||
from {
|
||||
filter: saturate(50%) brightness(400%);
|
||||
box-shadow: -1px -1px 4px rgba(255, 255, 255, 25%),
|
||||
-1px 1px 4px rgba(255, 255, 255, 25%),
|
||||
1px -1px 4px rgba(255, 255, 255, 25%),
|
||||
1px 1px 4px rgba(255, 255, 255, 25%);
|
||||
background-color: #ceffff10;
|
||||
}
|
||||
to {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.locked.mino {
|
||||
animation: locked-animation;
|
||||
animation-duration: 0.2s;
|
||||
@keyframes cleared-line-animation {
|
||||
from {
|
||||
background-color: #fff6;
|
||||
filter: saturate(50%) brightness(300%);
|
||||
box-shadow: 0 0 0 #adb5bd66, 0 0 0 #adb5bd66;
|
||||
}
|
||||
60% {
|
||||
box-shadow: -60px 0 2px #adb5bd33, 60px 0 2px #adb5bd33;
|
||||
}
|
||||
to {
|
||||
background-color: transparent;
|
||||
box-shadow: -100px 0 5px transparent, 100px 0 5px transparent;
|
||||
}
|
||||
}
|
||||
116
css/common.css
116
css/common.css
@@ -1,6 +1,8 @@
|
||||
|
||||
:root {
|
||||
--cell-side: 24px;
|
||||
--cell-side: 25px;
|
||||
--rX: -15;
|
||||
--rY: 0;
|
||||
--tZ: 25px;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -8,18 +10,46 @@ body {
|
||||
}
|
||||
|
||||
@supports (backdrop-filter: blur()) {
|
||||
.modal::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: rgba(33, 37, 41, 30%);
|
||||
backdrop-filter: blur(15px);
|
||||
background-color: #212529b3;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgb(37, 41, 45);
|
||||
background-color: #25292d;
|
||||
}
|
||||
|
||||
#matrixCard {
|
||||
background-image: radial-gradient(#222, #25292d)
|
||||
}
|
||||
|
||||
.card-header {
|
||||
text-shadow: 0 0 2px black;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
text-shadow: 0 0 8px var(--bs-light);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#statsTable td,
|
||||
#statsModal td {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td#timeCell {
|
||||
min-width: 10ch;
|
||||
}
|
||||
|
||||
.minoes-table {
|
||||
@@ -35,19 +65,12 @@ body {
|
||||
margin-top: calc(-1 * var(--buffer-zone-rows) * var(--cell-side));
|
||||
}
|
||||
|
||||
|
||||
@keyframes hard-dropped-table-animation {
|
||||
from {
|
||||
transform: translateY(0);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
transform: translateY(3px);
|
||||
}
|
||||
}
|
||||
#matrixTable.hard-dropped-table-animation {
|
||||
.hard-dropped-table-animation {
|
||||
animation: hard-dropped-table-animation .2s;
|
||||
}
|
||||
|
||||
@@ -66,30 +89,45 @@ td {
|
||||
overflow: hidden;
|
||||
width: var(--cell-side);
|
||||
height: var(--cell-side);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@keyframes trail-animation {
|
||||
from {
|
||||
background-color: rgb(206, 255, 255, 25%);
|
||||
filter: saturate(50%) brightness(300%);
|
||||
background-color: #ceffff40;
|
||||
}
|
||||
to {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes locked-animation {
|
||||
from {
|
||||
filter: saturate(50%) brightness(400%);
|
||||
}
|
||||
}
|
||||
|
||||
.locked.mino {
|
||||
animation: locked-animation;
|
||||
animation-duration: 0.2s;
|
||||
}
|
||||
|
||||
td.trail-animation {
|
||||
animation: trail-animation ease-out .3s;
|
||||
}
|
||||
|
||||
@keyframes cleared-line-animation {
|
||||
from {
|
||||
background-color: rgb(206, 255, 255, 40%);
|
||||
background-color: white;
|
||||
filter: saturate(50%) brightness(300%);
|
||||
box-shadow: -200px 0 5px white, 200px 0 5px white;
|
||||
box-shadow: 0 0 0 #adb5bd, 0 0 0 #adb5bd;
|
||||
}
|
||||
60% {
|
||||
box-shadow: -60px 0 2px #adb5bd66, 60px 0 2px #adb5bd66;
|
||||
}
|
||||
to {
|
||||
background-color: transparent;
|
||||
box-shadow: -100px 0 5px transparent, 100px 0 5px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,13 +135,26 @@ tr.cleared-line-animation {
|
||||
animation: cleared-line-animation ease-out .3s;
|
||||
}
|
||||
|
||||
#holdTable .J,
|
||||
#holdTable .L,
|
||||
#holdTable .S,
|
||||
#holdTable .T,
|
||||
#holdTable .Z,
|
||||
#nextTable .J,
|
||||
#nextTable .L,
|
||||
#nextTable .S,
|
||||
#nextTable .T,
|
||||
#nextTable .Z {
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
#messagesSpan {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px rgba(0, 0, 0, 0.8);
|
||||
color: #fffc;
|
||||
text-shadow: 1px 1px #000c;
|
||||
font-size: 3vmin;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -212,3 +263,28 @@ tr.cleared-line-animation {
|
||||
animation-timing-function: (0.4, 0, 0.6, 1);
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
#statsModal table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#statsModal th {
|
||||
padding-left: 0;
|
||||
padding-right: 0.5rem;
|
||||
padding-bottom: 0.2rem;
|
||||
border-left: 0.5rem solid transparent;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
#statsModal td {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0;
|
||||
padding-bottom: 0.2rem;
|
||||
border-left: 0;
|
||||
border-right: 0.5rem solid transparent;
|
||||
}
|
||||
|
||||
#statsModal tr:last-child th,
|
||||
#statsModal tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@@ -3,19 +3,30 @@ body {
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba(37, 41, 45, 30%);
|
||||
body[data-bs-theme="dark"] {
|
||||
--bs-body-bg: #2125296b;
|
||||
}
|
||||
|
||||
.mino:not(.ghost):not(.locking) {
|
||||
.btn-dark {
|
||||
--bs-btn-bg: #2125296b;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba(37, 41, 45, 40%);
|
||||
}
|
||||
|
||||
tr.matrix td:not(.mino) {
|
||||
border-left : none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.mino:not(.ghost):not(.locking):not(.disabled) {
|
||||
padding: 1px;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
box-shadow:
|
||||
-1px -1px 4px rgba(128, 128, 128, 25%),
|
||||
-1px 1px 4px rgba(128, 128, 128, 25%),
|
||||
1px -1px 4px rgba(128, 128, 128, 25%),
|
||||
1px 1px 4px rgba(128, 128, 128, 25%);
|
||||
border-radius: 4px;
|
||||
background-color: rgba(128, 128, 128, 25%);
|
||||
box-shadow: 0px 0px 8px rgba(128, 128, 128, 75%);
|
||||
}
|
||||
|
||||
.mino:not(.ghost):not(.locking):before {
|
||||
@@ -23,7 +34,7 @@ body {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
inset: 0;
|
||||
margin: 1px;
|
||||
margin: 1px 1px 0px 0px;
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
--glint-x: calc(50% + 50% * (var(--piece-column) - var(--column))/10);
|
||||
@@ -37,23 +48,24 @@ body {
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-mode: luminance;
|
||||
mask-composite: intersect;
|
||||
}
|
||||
}
|
||||
|
||||
.ghost.mino {
|
||||
background: transparent;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
background: rgba(242, 255, 255, 10%);
|
||||
border : 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 3px;
|
||||
box-shadow:
|
||||
-1px -1px 8px rgba(242, 255, 255, 32%),
|
||||
-1px 1px 8px rgba(242, 255, 255, 32%),
|
||||
1px -1px 8px rgba(242, 255, 255, 32%),
|
||||
1px 1px 8px rgba(242, 255, 255, 32%);
|
||||
box-shadow: 0px 0px 10px rgba(242, 255, 255, 75%);
|
||||
}
|
||||
|
||||
.moving.mino {
|
||||
border-width: 1px;
|
||||
background: rgba(186, 211, 255, 30%);
|
||||
border-color: rgba(242, 255, 255, 0.7);
|
||||
box-shadow: 0px 0px 5px rgba(128, 128, 128, 75%);
|
||||
}
|
||||
|
||||
.moving.mino:not(.locking) {
|
||||
padding: 2px;
|
||||
background: rgba(186, 211, 255, 30%);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
@@ -61,11 +73,17 @@ body {
|
||||
background: rgba(186, 211, 255, 70%);
|
||||
border-color: rgba(242, 255, 255, 0.7);
|
||||
border-radius: 4px;
|
||||
box-shadow:
|
||||
-1px -1px 8px rgba(186, 211, 255, 27%),
|
||||
-1px 1px 8px rgba(186, 211, 255, 27%),
|
||||
1px -1px 8px rgba(186, 211, 255, 27%),
|
||||
1px 1px 8px rgba(186, 211, 255, 27%);
|
||||
box-shadow: 0px 0px 10px rgba(242, 255, 255, 100%);
|
||||
}
|
||||
|
||||
.disabled.mino {
|
||||
opacity: 60%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.disabled.mino:before {
|
||||
opacity: 50%;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@keyframes locked-animation {
|
||||
@@ -75,8 +93,3 @@ body {
|
||||
border-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.locked.mino {
|
||||
animation: locked-animation;
|
||||
animation-duration: 0.2s;
|
||||
}
|
||||
@@ -5,7 +5,12 @@
|
||||
.minoes-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
filter: drop-shadow(5px 8px 0 rgba(9, 9, 9, 22%));
|
||||
filter:
|
||||
drop-shadow(-2px 0 0 white)
|
||||
drop-shadow(2px 0 0 white)
|
||||
drop-shadow(0 -2px 0 white)
|
||||
drop-shadow(0 2px 0 white)
|
||||
drop-shadow(5px 8px 0 rgba(9, 9, 9, 22%));
|
||||
}
|
||||
|
||||
.minoes-table tr {
|
||||
@@ -32,47 +37,48 @@ tr.matrix td:not(.mino) {
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
display: block;
|
||||
box-shadow: 0 -6px 0 var(--light-color);
|
||||
box-shadow: 0 -6px 0 var(--box-shadow-color);
|
||||
}
|
||||
|
||||
.I.mino {
|
||||
--background-color: #42AFE1;
|
||||
--light-color: #6CEAFF;
|
||||
--box-shadow-color: #6CEAFF;
|
||||
}
|
||||
|
||||
.J.mino {
|
||||
--background-color: #1165B5;
|
||||
--light-color: #339BFF;
|
||||
--box-shadow-color: #339BFF;
|
||||
}
|
||||
|
||||
.L.mino {
|
||||
--background-color: #F38927;
|
||||
--light-color: #FFBA59;
|
||||
--box-shadow-color: #FFBA59;
|
||||
}
|
||||
|
||||
.O.mino {
|
||||
--background-color: #F6D03C;
|
||||
--light-color: #FFFF7F;
|
||||
--box-shadow-color: #FFFF7F;
|
||||
}
|
||||
|
||||
.S.mino {
|
||||
--background-color: #51B84D;
|
||||
--light-color: #84F880;
|
||||
--box-shadow-color: #84F880;
|
||||
}
|
||||
|
||||
.T.mino {
|
||||
--background-color: #9739A2;
|
||||
--light-color: #D958E9;
|
||||
--box-shadow-color: #D958E9;
|
||||
}
|
||||
|
||||
.Z.mino {
|
||||
--background-color: #EB4F65;
|
||||
--light-color: #FF7F79;
|
||||
--box-shadow-color: #FF7F79;
|
||||
}
|
||||
|
||||
.ghost.mino {
|
||||
opacity: 50%;
|
||||
opacity: 5%;
|
||||
box-shadow: none;
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
|
||||
.moving.mino {
|
||||
@@ -80,7 +86,8 @@ tr.matrix td:not(.mino) {
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
filter: saturate(50%) brightness(130%);
|
||||
--background-color: white;
|
||||
--box-shadow-color: #DDD;
|
||||
}
|
||||
|
||||
.locked.mino {
|
||||
@@ -88,6 +95,10 @@ tr.matrix td:not(.mino) {
|
||||
animation-duration: 0.2s;
|
||||
}
|
||||
|
||||
.disabled.mino {
|
||||
filter: brightness(50%) contrast(50%);
|
||||
}
|
||||
|
||||
@keyframes locked-animation {
|
||||
from {
|
||||
filter: saturate(50%) brightness(300%);
|
||||
@@ -101,4 +112,14 @@ tr.matrix td:not(.mino) {
|
||||
to {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes trail-animation {
|
||||
from {
|
||||
background-color: #ceffff10;
|
||||
filter: saturate(50%) brightness(110%);
|
||||
}
|
||||
to {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
148
css/opera.css
Normal file
148
css/opera.css
Normal file
@@ -0,0 +1,148 @@
|
||||
body {
|
||||
--bs-gutter-x: 0;
|
||||
background: black !important;
|
||||
}
|
||||
|
||||
#screenRow {
|
||||
gap: 0 !important;
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .1em;
|
||||
}
|
||||
|
||||
#screenRow {
|
||||
--bs-gutter-x: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: black;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0.5em !important;
|
||||
}
|
||||
|
||||
.card-header,
|
||||
.card-header th{
|
||||
background: transparent;
|
||||
font-weight: 400 !important;
|
||||
font-size: 1.3em;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#screenRow .table {
|
||||
--bs-border-width: 0;
|
||||
}
|
||||
|
||||
#holdTable {
|
||||
margin: 0 0 0 auto !important;
|
||||
}
|
||||
|
||||
#holdTable,
|
||||
#nextTable {
|
||||
border-bottom: 2px solid white;
|
||||
}
|
||||
|
||||
#statsTable {
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
#statsTable tr {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#statsTable td,
|
||||
#statsTable th {
|
||||
margin: 0;
|
||||
padding: 0 !important;
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#statsTable th {
|
||||
display: inline;
|
||||
flex-flow: row;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
#statsTable td {
|
||||
font-size: 1.3em;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
}
|
||||
|
||||
td#timeCell {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#matrixCard {
|
||||
background: transparent;
|
||||
border-top: none;
|
||||
border-left: 4px solid white;
|
||||
border-right: 4px solid white;
|
||||
border-bottom: 4px solid white;
|
||||
}
|
||||
|
||||
.mino {
|
||||
padding: 0;
|
||||
opacity: 100%;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.I.mino {
|
||||
background-color: #42AFE1;
|
||||
border-color: #6CEAFF;
|
||||
}
|
||||
|
||||
.J.mino {
|
||||
background-color: #1165B5;
|
||||
border-color: #339BFF;
|
||||
}
|
||||
|
||||
.L.mino {
|
||||
background-color: #F38927;
|
||||
border-color: #FFBA59;
|
||||
}
|
||||
|
||||
.O.mino {
|
||||
background-color: #F6D03C;
|
||||
border-color: #FFFF7F;
|
||||
}
|
||||
|
||||
.S.mino {
|
||||
background-color: #32ee3e;
|
||||
border-color: #84F880;
|
||||
}
|
||||
|
||||
.T.mino {
|
||||
background-color: #9739A2;
|
||||
border-color: #D958E9;
|
||||
}
|
||||
|
||||
.Z.mino {
|
||||
background-color: #EB4F65;
|
||||
border-color: #FF7F79;
|
||||
}
|
||||
|
||||
.ghost.mino {
|
||||
background-color: #fff4;
|
||||
border-color: #fff8;
|
||||
}
|
||||
|
||||
.moving.mino {
|
||||
filter: saturate(80%) brightness(150%);
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
filter: saturate(50%) brightness(200%);
|
||||
}
|
||||
|
||||
.disabled.mino {
|
||||
filter: brightness(50%) contrast(80%);
|
||||
opacity: 70%;
|
||||
}
|
||||
97
css/pop.css
97
css/pop.css
@@ -1,97 +0,0 @@
|
||||
body {
|
||||
background-image: url("pop/bg.png");
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba(37, 41, 45, 50%);
|
||||
}
|
||||
|
||||
@supports (backdrop-filter: blur()) {
|
||||
.card {
|
||||
background-color: rgba(33, 37, 41, 20%);
|
||||
backdrop-filter: blur(3px);
|
||||
}
|
||||
}
|
||||
|
||||
tr.matrix td:not(.mino) {
|
||||
border-left : 1px solid #222;
|
||||
border-right : 1px solid #222;
|
||||
border-top : 1px solid #111;
|
||||
border-bottom: 1px solid #111;
|
||||
}
|
||||
|
||||
.mino {
|
||||
background: rgba(255, 255, 255, 33%);
|
||||
border: 6px solid var(--color);
|
||||
padding: 0;
|
||||
opacity: 100%;
|
||||
border-radius: 4px;
|
||||
filter: blur(1px);
|
||||
box-shadow: 0 0 10px var(--color);
|
||||
}
|
||||
|
||||
.I.mino {
|
||||
--color: #9bf6ff;
|
||||
}
|
||||
|
||||
.J.mino {
|
||||
--color: #a0c4ff;
|
||||
}
|
||||
|
||||
.L.mino {
|
||||
--color: #ffd6a5;
|
||||
}
|
||||
|
||||
.O.mino {
|
||||
--color: #fdffb6;
|
||||
}
|
||||
|
||||
.T.mino {
|
||||
--color: #bdb2ff;
|
||||
}
|
||||
|
||||
.S.mino {
|
||||
--color: #caffbf;
|
||||
}
|
||||
|
||||
.Z.mino {
|
||||
--color: #ffadad;
|
||||
}
|
||||
|
||||
.ghost.mino {
|
||||
filter: brightness(150%) blur(2px);
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
.moving.mino {
|
||||
filter: brightness(120%);
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
--color: white;
|
||||
filter: blur(2px);
|
||||
}
|
||||
|
||||
@keyframes locked-animation {
|
||||
from {
|
||||
background: white;
|
||||
--color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.locked.mino {
|
||||
animation: locked-animation;
|
||||
animation-duration: 0.2s;
|
||||
}
|
||||
|
||||
@keyframes cleared-line-animation {
|
||||
from {
|
||||
background-color: rgb(206, 255, 255, 40%);
|
||||
filter: saturate(50%) brightness(300%);
|
||||
box-shadow: -200px 0 10px white, 200px 0 10px white;
|
||||
}
|
||||
to {
|
||||
box-shadow: -200px 0 50px transparent, 200px 0 50px transparent;
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,11 @@
|
||||
|
||||
#statsTable,
|
||||
.card,
|
||||
.card-header,
|
||||
#messagesSpan {
|
||||
font-family: "Early GameBoy", monospace;
|
||||
font-smooth: never;
|
||||
-webkit-font-smoothing: none;
|
||||
color: #254806;
|
||||
text-shadow: -1px -1px 3px rgba(0, 0, 0, 40%), 1px 1px 1px rgba(0, 0, 0, 40%);
|
||||
}
|
||||
@@ -76,7 +79,7 @@
|
||||
text-shadow: -2px -2px #808302, -2px 2px #808302, 2px -2px #808302, 2px 2px #808302;
|
||||
}
|
||||
|
||||
td {
|
||||
.minoes-table td {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
@@ -114,16 +117,17 @@ td {
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0;
|
||||
35% {
|
||||
opacity: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
animation: blinker 0.04s step-start infinite;
|
||||
animation: blinker 0.08s step-start infinite;
|
||||
}
|
||||
|
||||
.ghost.mino {
|
||||
.ghost.mino,
|
||||
.disabled.mino {
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
@@ -131,11 +135,15 @@ td {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.hard-dropped-table-animation {
|
||||
animation: hard-dropped-table-animation steps(1) .2s;
|
||||
}
|
||||
|
||||
@keyframes cleared-line-animation {
|
||||
5%, 15%, 25%, 35%, 45%, 55%, 65%, 75%, 85%, 95% {
|
||||
10%, 30%, 50%, 70%, 90% {
|
||||
opacity: 0;
|
||||
}
|
||||
10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% {
|
||||
20%, 40%, 60%, 80% {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
css/retro/edo3adc8h2re1.jpeg
Normal file
BIN
css/retro/edo3adc8h2re1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 298 KiB |
370
css/stereo.css
Normal file
370
css/stereo.css
Normal file
@@ -0,0 +1,370 @@
|
||||
body {
|
||||
background-image: url(stereo/bg.jpg),
|
||||
radial-gradient(circle at center,
|
||||
#39444f 0%,
|
||||
#2c323b 25%,
|
||||
#293036 28%,
|
||||
#252b32 34%,
|
||||
#242930 38%,
|
||||
#1a1d22 52%,
|
||||
#191c22 53%,
|
||||
#151519 63%,
|
||||
#141418 65%,
|
||||
#0f0f12 74%,
|
||||
#0a0c0d 100%);
|
||||
background-repeat: space;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
#sceneDiv {
|
||||
perspective: 500px;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
#sceneDiv:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
#sceneDiv * {
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
#screenRow {
|
||||
display: block;
|
||||
transform: translateZ(var(--tZ)) rotateX(calc((var(--rX)) * 1deg)) rotateY(calc((var(--rY)) * 1deg));
|
||||
}
|
||||
|
||||
#screenRow * {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#screenRow .col {
|
||||
display: inline-block !important;
|
||||
width: max-content;
|
||||
height: 100%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #36394180;
|
||||
}
|
||||
|
||||
#matrixCard {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#screenRow .card>* {
|
||||
transform: translateZ(var(--cell-side));
|
||||
}
|
||||
|
||||
#screenRow .card-header {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.card,
|
||||
.card-header {
|
||||
text-shadow:
|
||||
calc(-0.3px * var(--rY)) calc(0.4px * var(--rX)) 5px #0008;
|
||||
}
|
||||
|
||||
#holdTable .mino {
|
||||
--row: 7;
|
||||
--column: -5;
|
||||
}
|
||||
|
||||
#nextTable .mino {
|
||||
--row: 15;
|
||||
--column: 15;
|
||||
}
|
||||
|
||||
.minoes-table th,
|
||||
.minoes-table td {
|
||||
display: inline-block !important;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.minoes-table tr {
|
||||
width: max-content;
|
||||
height: var(--cell-side);
|
||||
}
|
||||
|
||||
#statsTable tr {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#statsTable th,
|
||||
#statsTable td {
|
||||
display: table-cell;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
tr.matrix td:not(.mino) {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.minoes-table td {
|
||||
width: var(--cell-side) !important;
|
||||
height: var(--cell-side) !important;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.minoes-table .mino,
|
||||
.minoes-table .mino::before,
|
||||
.minoes-table .mino + :not(.mino)::before,
|
||||
.minoes-table .mino::after {
|
||||
--light-x: calc(-0.5 - var(--rY) / 30 - var(--column) / 10 + 1);
|
||||
--light-y: calc(-0.5 + var(--rX) / 20 - var(--row) / 6 + 4);
|
||||
--center-color: hsla(var(--h), var(--s), calc(var(--l) * var(--light) * 1.1), var(--a));
|
||||
--edge-color: hsla(var(--h), var(--s), calc(var(--l) * (var(--light) * 0.9)), var(--a));
|
||||
background: var(--center-color);
|
||||
border-radius: 2px;
|
||||
border: 2px outset var(--center-color);
|
||||
}
|
||||
|
||||
.minoes-table .mino::before,
|
||||
.minoes-table .mino + :not(.mino)::before,
|
||||
.minoes-table .mino::after,
|
||||
td.trail-animation::before,
|
||||
td.trail-animation::after,
|
||||
tr.cleared-line-animation td::before,
|
||||
tr.cleared-line-animation td::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
width: var(--cell-side);
|
||||
height: var(--cell-side);
|
||||
}
|
||||
|
||||
/* Front face */
|
||||
.minoes-table .mino,
|
||||
td.trail-animation {
|
||||
--light: calc(
|
||||
1
|
||||
+ (var(--light-y) * 0.3)
|
||||
+ (var(--light-x) * 0.2)
|
||||
);
|
||||
--center-x: calc(35% + var(--light-x) * 10%);
|
||||
--center-y: calc(35% + var(--light-y) * 10%);
|
||||
background: radial-gradient(
|
||||
circle at var(--center-x) var(--center-y),
|
||||
var(--center-color) 15%,
|
||||
var(--edge-color) 100%
|
||||
);
|
||||
box-shadow: 0 0 7px hsla(var(--h), var(--s), calc(var(--l) * var(--light) * 1.3), 20%);
|
||||
}
|
||||
|
||||
/* Left face */
|
||||
.minoes-table .mino::before,
|
||||
td.trail-animation::before,
|
||||
tr.cleared-line-animation td::before,
|
||||
.left .minoes-table .mino + .mino::before {
|
||||
--light: calc(
|
||||
1.1
|
||||
+ (var(--light-x) * -0.2)
|
||||
+ (var(--light-y) * 0.15)
|
||||
);
|
||||
transform: translate3d(-1.5px, -1.5px, calc(-1 * var(--cell-side))) rotateY(-90deg);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
/* Right face */
|
||||
.right .minoes-table .mino + .mino::before,
|
||||
.minoes-table .mino + :not(.mino)::before,
|
||||
.right td.trail-animation::before,
|
||||
.right tr.cleared-line-animation td::before {
|
||||
--light: calc(
|
||||
0.85
|
||||
+ (var(--light-x) * -0.2)
|
||||
+ (var(--light-y) * -0.15)
|
||||
);
|
||||
--center-x: calc(65% + var(--light-x) * 10%);
|
||||
--center-y: calc(35% + var(--light-y) * 10%);
|
||||
filter: saturate(0.95);
|
||||
transform: translate3d(0, 0, calc(-1 * var(--cell-side))) rotateY(-90deg);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.right .minoes-table .mino:last-child::before {
|
||||
transform: translate3d(-1.5px, -1.5px, calc(-1 * var(--cell-side))) rotateY(90deg) !important;
|
||||
transform-origin: right !important;
|
||||
}
|
||||
|
||||
/* Top face */
|
||||
.minoes-table .mino::after,
|
||||
td.trail-animation::after,
|
||||
tr.cleared-line-animation td::after {
|
||||
--light: calc(
|
||||
1.5
|
||||
+ (var(--light-y) * 0.2)
|
||||
);
|
||||
transform: translate3d(-1.5px, -1.5px, calc(-1 * var(--cell-side))) rotateX(90deg);
|
||||
transform-origin: top;
|
||||
}
|
||||
|
||||
/* Bottom face */
|
||||
.bottom .minoes-table .mino::after,
|
||||
.bottom td.trail-animation::after,
|
||||
.bottom tr.cleared-line-animation td::after {
|
||||
--light: calc(
|
||||
1.1
|
||||
+ (var(--light-y) * -0.3)
|
||||
);
|
||||
--center-x: calc(65% + var(--light-x) * 10%);
|
||||
--center-y: calc(65% + var(--light-y) * 10%);
|
||||
filter: saturate(0.95);
|
||||
transform: translate3d(-1.5px, -1.5px, calc(-1 * var(--cell-side))) rotateX(-90deg);
|
||||
transform-origin: bottom;
|
||||
}
|
||||
|
||||
.J.mino, .J.mino + :not(.mino) { --h: 210deg; --s: 78%; --l: 52%; --a: 0.75; }
|
||||
.L.mino, .L.mino + :not(.mino) { --h: 28deg; --s: 85%; --l: 52%; --a: 0.75; }
|
||||
.O.mino, .O.mino + :not(.mino) { --h: 48deg; --s: 88%; --l: 52%; --a: 0.75; }
|
||||
.I.mino, .I.mino + :not(.mino) { --h: 200deg; --s: 70%; --l: 52%; --a: 0.75; }
|
||||
.S.mino, .S.mino + :not(.mino) { --h: 118deg; --s: 45%; --l: 52%; --a: 0.75; }
|
||||
.T.mino, .T.mino + :not(.mino) { --h: 293deg; --s: 48%; --l: 52%; --a: 0.75; }
|
||||
.Z.mino, .Z.mino + :not(.mino) { --h: 352deg; --s: 75%; --l: 52%; --a: 0.75; }
|
||||
|
||||
.ghost.mino, .ghost.mino + :not(.mino) { --h: 0deg; --s: 0%; --l: 55%; --a: 0.40; }
|
||||
.locking.mino, .locking.mino + :not(.mino) { --h: 0deg; --s: 0%; --l: 92%; --a: 0.72; }
|
||||
.disabled.mino, .disabled.mino + :not(.mino) { --h: 0deg; --s: 0%; --l: 45%; --a: 0.72; }
|
||||
|
||||
#holdTable .J + :not(.mino),
|
||||
#holdTable .L + :not(.mino),
|
||||
#holdTable .S + :not(.mino),
|
||||
#holdTable .T + :not(.mino),
|
||||
#holdTable .Z + :not(.mino),
|
||||
#nextTable .J + :not(.mino),
|
||||
#nextTable .L + :not(.mino),
|
||||
#nextTable .S + :not(.mino),
|
||||
#nextTable .T + :not(.mino),
|
||||
#nextTable .Z + :not(.mino) {
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
@keyframes trail-animation {
|
||||
from {
|
||||
background-color: hsla(180, 100%, 100%, 0.1);
|
||||
border-color: hsla(180, 100%, 100%, 0.1);
|
||||
}
|
||||
to {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
td.trail-animation::before,
|
||||
td.trail-animation::after {
|
||||
animation: trail-animation ease-out .3s;
|
||||
}
|
||||
|
||||
@keyframes locked-animation {
|
||||
from {
|
||||
--h: 0deg; --s: 0%; --l: 100%; --a: 1;
|
||||
box-shadow: 0 0 10px hsla(180, 100%, 100%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.locked.mino::before,
|
||||
.locked.mino::after {
|
||||
animation: locked-animation;
|
||||
animation-duration: .2s;
|
||||
}
|
||||
|
||||
@keyframes cleared-line-animation {
|
||||
from {
|
||||
background-color: white !important;
|
||||
box-shadow: 0 0 0 white;
|
||||
}
|
||||
to {
|
||||
background-color: #fff0;
|
||||
box-shadow: 0 0 100px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
tr.cleared-line-animation td::before,
|
||||
tr.cleared-line-animation td::after {
|
||||
animation: cleared-line-animation ease-out .3s;
|
||||
}
|
||||
|
||||
@keyframes show-level-animation {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateY(200%);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(0) scaleY(1);
|
||||
line-height: var(--bs-body-line-height);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(-100%) scaleY(0);
|
||||
line-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoom-in-animation {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale3d(0.3, 0.3, 0.3);
|
||||
line-height: var(--bs-body-line-height);
|
||||
}
|
||||
|
||||
30% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
line-height: var(--bs-body-line-height);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale3d(1.5, 0, 1);
|
||||
line-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate-in-animation {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: rotate(200deg);
|
||||
line-height: var(--bs-body-line-height);
|
||||
}
|
||||
|
||||
30% {
|
||||
transform: translateZ(0);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
line-height: var(--bs-body-line-height);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale3d(1.5, 0, 1);
|
||||
line-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes game-over-animation {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateY(200%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scaleY(1);
|
||||
line-height: var(--bs-body-line-height);
|
||||
}
|
||||
}
|
||||
BIN
css/stereo/bg.jpg
Normal file
BIN
css/stereo/bg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
76
css/synthwave.css
Normal file
76
css/synthwave.css
Normal file
@@ -0,0 +1,76 @@
|
||||
body {
|
||||
background-image: url(synthwave/bg.png);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
body[data-bs-theme="dark"] {
|
||||
--bs-body-bg: #2125296b;
|
||||
}
|
||||
|
||||
.btn-dark {
|
||||
--bs-btn-bg: #2125296b;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #25292d66;
|
||||
}
|
||||
|
||||
#matrixCard {
|
||||
background-image: radial-gradient(#2226, #25292d66);
|
||||
}
|
||||
|
||||
.card,
|
||||
#matrixCard {
|
||||
background: repeating-linear-gradient(transparent, #111 1px);
|
||||
backdrop-filter: blur(3px);
|
||||
}
|
||||
|
||||
.minoes-table {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.mino {
|
||||
background: var(--color);
|
||||
border: 3px solid var(--border);
|
||||
box-shadow: 0 0 8px var(--border);
|
||||
}
|
||||
|
||||
.I {
|
||||
--color: #00eaf866;
|
||||
--border: #00eaf5;
|
||||
}
|
||||
|
||||
.J {
|
||||
--color: #00a9f766;
|
||||
--border: #00a9f7;
|
||||
}
|
||||
|
||||
.L {
|
||||
--color: #f9b60066;
|
||||
--border: #f9b600;
|
||||
}
|
||||
|
||||
.O {
|
||||
--color: #e3e04966;
|
||||
--border: #e3e049;
|
||||
}
|
||||
|
||||
.S {
|
||||
--color: #7bd59e66;
|
||||
--border: #7bd59e;
|
||||
}
|
||||
|
||||
.T {
|
||||
--color: #d136e266;
|
||||
--border: #d136e2;
|
||||
}
|
||||
|
||||
.Z {
|
||||
--color: #E67D8666;
|
||||
--border: #E67D86;
|
||||
}
|
||||
|
||||
.ghost {
|
||||
--color: #fff4;
|
||||
--border: #fff5;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 444 KiB After Width: | Height: | Size: 444 KiB |
123
index.html
123
index.html
@@ -4,20 +4,32 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Quatuor</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="dark">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.4/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="css/common.css">
|
||||
<link rel="stylesheet" href="css/classic.css" title="Classique">
|
||||
<link rel="alternate stylesheet" href="css/minimal.css" title="Minimal">
|
||||
<link rel="alternate stylesheet" href="css/electro.css" title="Électro">
|
||||
<link rel="alternate stylesheet" href="css/pop.css" title="Pop">
|
||||
<link rel="alternate stylesheet" href="css/retro.css" title="Rétro">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicons/T-2.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png">
|
||||
<link rel="stylesheet" href="css/classic.css" title="Thème sélectionné" id="selectedStyleSheet">
|
||||
<link rel="alternate stylesheet" href="css/classic.css" title="Classique">
|
||||
<link rel="alternate stylesheet" href="css/minimal.css" title="Minimal">
|
||||
<link rel="alternate stylesheet" href="css/electro.css" title="Électro">
|
||||
<link rel="alternate stylesheet" href="css/synthwave.css" title="Synthwave">
|
||||
<link rel="alternate stylesheet" href="css/retro.css" title="Rétro">
|
||||
<link rel="alternate stylesheet" href="css/opera.css" title="Opéra">
|
||||
<link rel="alternate stylesheet" href="css/stereo.css" title="Stéréo">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicons/T-2.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta property="og:title" content="Quatuor"/>
|
||||
<meta property="og:type" content="game"/>
|
||||
<meta property="og:url" content="https://adrien.malingrey.fr/jeux/quatuor/"/>
|
||||
<meta property="og:image" content="https://adrien.malingrey.fr/jeux/quatuor/thumbnail.png"/>
|
||||
<meta property="og:image:width" content="288"/>
|
||||
<meta property="og:image:height" content="288"/>
|
||||
<meta property="og:description" content="Un jeu avec un quatuor de blocs qui tombent."/>
|
||||
<meta property="og:locale" content="fr_FR"/>
|
||||
<meta property="og:site_name" content="adrien.malingrey.fr"/>
|
||||
</head>
|
||||
|
||||
<body data-bs-theme="dark">
|
||||
@@ -30,47 +42,52 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="settingsForm" class="needs-validation" novalidate>
|
||||
<fieldset id="keyBindFielset" class="row g-2 mb-3 align-items-center text-center">
|
||||
<legend class="text-start">Commandes</legend>
|
||||
<fieldset id="keyBindFielset" class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Commandes</legend>
|
||||
<label for="moveLeftInput" title="Gauche" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-arrow-left"></i></label>
|
||||
<div class="col-4"><input name="moveLeft" id="moveLeftInput" type="text" class="form-control text-center btn btn-dark" value="←" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="moveRight" id="moveRightInput" type="text" class="form-control text-center btn btn-dark" value="→" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="moveLeft" id="moveLeftInput" type="text" class="form-control text-center" value="←" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="moveRight" id="moveRightInput" type="text" class="form-control text-center" value="→" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<label for="moveRightInput" title="Droite" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-arrow-right"></i></label>
|
||||
<label for="rotateCounterclockwiseInput" title="Rotation anti-horaire" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-arrow-counterclockwise"></i></label>
|
||||
<div class="col-4"><input name="rotateCounterclockwise" id="rotateCounterclockwiseInput" type="text" class="form-control text-center btn btn-dark" value="w" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="rotateClockwise" id="rotateClockwiseInput" type="text" class="form-control text-center btn btn-dark" value="↑" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="rotateCounterclockwise" id="rotateCounterclockwiseInput" type="text" class="form-control text-center" value="w" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="rotateClockwise" id="rotateClockwiseInput" type="text" class="form-control text-center" value="↑" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<label for="rotateClockwiseInput" title="Rotation horaire" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-arrow-clockwise"></i></label>
|
||||
<label for="softDropInput" title="Chute lente" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-arrow-down-short"></i></label>
|
||||
<div class="col-4"><input name="softDrop" id="softDropInput" type="text" class="form-control text-center btn btn-dark" value="↓" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="hardDrop" id="hardDropInput" type="text" class="form-control text-center btn btn-dark" value="Espace" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="softDrop" id="softDropInput" type="text" class="form-control text-center" value="↓" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="hardDrop" id="hardDropInput" type="text" class="form-control text-center" value="Espace" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<label for="hardDropInput" title="Chute rapide" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-download"></i></label>
|
||||
<label for="holdInput" title="Échanger la pièce" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-arrow-left-right"></i></label>
|
||||
<div class="col-4"><input name="hold" id="holdInput" type="text" class="form-control text-center btn btn-dark" value="c" onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="pause" id="pauseInput" type="text" class="form-control text-center btn btn-dark" value="Échap." onclick="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="hold" id="holdInput" type="text" class="form-control text-center" value="c" onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<div class="col-4"><input name="pause" id="pauseInput" type="text" class="form-control text-center" value="Échap." onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
|
||||
<label for="pauseInput" title="Pause" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-pause"></i></label>
|
||||
</fieldset>
|
||||
<fieldset id="autorepeatFieldset" class="row g-2 mb-3 align-items-center text-center">
|
||||
<legend class="text-start">Répétition automatique</legend>
|
||||
<fieldset id="autorepeatFieldset" class="row g-2 mb-3 align-items-center text-center"><!--<legend class="text-start">Répétition automatique</legend>-->
|
||||
<label for="arrInput" class="col-2 col-form-label"><abbr title="Automatic Repeat Rate : période de répétition de l'action">ARR</abbr></label>
|
||||
<div class="col-4"><div class="input-group"><input name="arr" id="arrInput" type="number" class="form-control text-center" value="50" min="2" max="200" step="1"><div class="input-group-text">ms</div></div></div>
|
||||
<div class="col-4"><div class="input-group"><input name="das" id="dasInput" type="number" class="form-control text-center" value="300" min="100" max="500" step="5"><div class="input-group-text">ms</div></div></div>
|
||||
<label for="dasInput" class="col-2 col-form-label"><abbr title="Delayed AutoShift : délai initial avant répétition">DAS</abbr></label>
|
||||
</fieldset>
|
||||
<fieldset class="row g-2 mb-3 align-items-center text-center">
|
||||
<legend class="text-start">Interface</legend>
|
||||
<label for="sfxVolumeRange" class="col-2 col-form-label">Volume</label>
|
||||
<div class="col-4 d-flex align-items-baseline"><input id="sfxVolumeRange" class="form-range" type="range" min="0" max="1" step="any" value="0.7"></div>
|
||||
<div class="col-4"><select name="stylesheet" id="stylesheetSelect" class="form-select" oninput="document.selectedStyleSheetSet=this.value">
|
||||
<option selected>Classique</option>
|
||||
<option>Minimal</option>
|
||||
<option>Pop</option>
|
||||
<option>Électro</option>
|
||||
<option>Rétro</option>
|
||||
</select></div>
|
||||
<fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Interface</legend>
|
||||
<label for="stylesheetSelect" class="col-2 col-form-label">Thème</label>
|
||||
<div class="col-4"><select name="stylesheet" id="stylesheetSelect" class="form-select" oninput="selectedStyleSheet.href = this.value">
|
||||
<option value="css/classic.css" selected>Classique</option>
|
||||
<option value="css/minimal.css">Minimal</option>
|
||||
<option value="css/synthwave.css">Synthwave</option>
|
||||
<option value="css/electro.css">Électro</option>
|
||||
<option value="css/retro.css">Rétro</option>
|
||||
<option value="css/opera.css">Opéra</option>
|
||||
<option value="css/stereo.css">Stéréo</option>
|
||||
</select></div>
|
||||
<div class="col-4">
|
||||
<div class="form-check form-switch text-start">
|
||||
<input id="fullscreenCheckbox" type="checkbox" role="switch" class="form-check-input" tabindex="0">
|
||||
<label for="fullscreenCheckbox" class="form-check-label">Plein écran</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2"></div>
|
||||
<label for="sfxVolumeRange" class="col-2 col-form-label">Volume</label>
|
||||
<div class="col-4 d-flex align-items-baseline"><input name="sfxVolumeRange" id="sfxVolumeRange" class="form-range" type="range" min="0" max="1" step="any" value="0.7"></div>
|
||||
</fieldset>
|
||||
<fieldset class="row g-2 mb-3 align-items-center text-center">
|
||||
<legend class="text-start">Partie</legend>
|
||||
<fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Partie</legend>
|
||||
<label for="levelInput" class="col-2 col-form-label text-center">Niveau</label>
|
||||
<div class="col-4">
|
||||
<input name="startLevel" id="levelInput" type="number" class="form-control text-center" value="1" min="1" max="15">
|
||||
@@ -85,14 +102,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid d-flex vh-100 justify-content-center d-flex align-items-center">
|
||||
<div id="sceneDiv" class="container-fluid d-flex vh-100 justify-content-center d-flex align-items-center">
|
||||
|
||||
<div id="screenRow" class="row row-cols-auto align-items-start gap-2">
|
||||
<div class="col d-flex flex-column align-items-end">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header text-center"><strong>HOLD</strong></div>
|
||||
<div class="card shadow mb-4 w-100">
|
||||
<div class="card-header fw-bold text-uppercase text-center">Hold</div>
|
||||
<div class="card-body p-0">
|
||||
<table id="holdTable" class="minoes-table">
|
||||
<table id="holdTable" class="minoes-table m-auto">
|
||||
<tr class="buffer-zone"><td></td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr class="buffer-zone"><td></td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr class="buffer-zone"><td></td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
@@ -103,11 +120,11 @@
|
||||
</div>
|
||||
<div class="card shadow">
|
||||
<table id="statsTable" class="table mb-0">
|
||||
<tr><th>Score</th> <td id="scoreCell">0</td> </tr>
|
||||
<tr class="card-header fw-bold text-uppercase"><th>Score</th><td id="scoreCell">0</td> </tr>
|
||||
<tr><th>Meilleur<br/>score</th><td id="highScoreCell"><script>document.write(Number(localStorage["highScore"]) || 0)</script></td></tr>
|
||||
<tr><th>Niveau</th><td id="levelCell">0</td> </tr>
|
||||
<tr><th>But</th> <td id="goalCell">0</td> </tr>
|
||||
<tr><th>Temps</th> <td id="timeCell">00:00</td> </tr>
|
||||
<tr><th>Niveau</th> <td id="levelCell">0</td> </tr>
|
||||
<tr><th>But</th> <td id="goalCell">0</td> </tr>
|
||||
<tr><th>Temps</th> <td id="timeCell">00:00:00</td> </tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -149,7 +166,7 @@
|
||||
|
||||
<div class="col">
|
||||
<div class="card shadow">
|
||||
<div class="card-header text-center"><strong>NEXT</strong></div>
|
||||
<div class="card-header fw-bold text-uppercase text-center">Next</div>
|
||||
<div class="card-body p-0">
|
||||
<table id="nextTable" class="minoes-table caption-top">
|
||||
<tr class="buffer-zone"><td></td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
@@ -176,21 +193,21 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="statsModal" tabindex="-1">
|
||||
<div class="modal fade" id="statsModal" data-bs-backdrop="static" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title w-100 text-center">Fin</h2>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
<!-- <button type="button" class="btn-close" data-bs-dismiss="modal"></button> -->
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<table class="table mb-0">
|
||||
<tr><th>Score </th><td id="statsModalScoreCell"> </td><th>Niveau </th><td id="statsModalLevelCell"> </td></tr>
|
||||
<tr><th>Meilleur score</th><td id="statsModalHighScoreCell"> </td><th>Temps </th><td id="statsModalTimeCell"> </td></tr>
|
||||
<tr><th>Lignes </th><td id="statsModaltotalClearedLines"></td><th>Lignes par minute </th><td id="statsModaltotalClearedLinesPM"></td></tr>
|
||||
<tr><th>Quatuors </th><td id="statsModalNbQuatuors"> </td><th>Plus long combo </th><td id="statsModalMaxCombo"> </td></tr>
|
||||
<tr><th>Pirouettes </th><td id="statsModalNbTSpin"> </td><th>Plus long bout en bout</th><td id="statsModalMaxB2B"> </td></tr>
|
||||
<tr><th>Score</th> <td id="statsModalScoreCell"></td> <th>Quatuors</th> <td id="statsModalNbQuatuors"></td> </tr>
|
||||
<tr><th>Meilleur score</th><td id="statsModalHighScoreCell"></td> <th>Pirouettes</th> <td id="statsModalNbTSpin"></td></td> </tr>
|
||||
<tr><th>Temps</th> <td id="statsModalTimeCell"></td> <th>Plus long combo</th> <td id="statsModalMaxCombo"></td> </tr>
|
||||
<tr><th>Niveau</th> <td id="statsModalLevelCell"></td> <th>Plus long bout à bout</th><td id="statsModalMaxB2B"></td> </tr>
|
||||
<tr><th>Lignes</th> <td id="statsModaltotalClearedLines"></td><th>Lignes par minute</th> <td id="statsModaltotalClearedLinesPM"></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -213,7 +230,7 @@
|
||||
<audio id="wallSound" src="sounds/808K_A.wav" preload="auto" type="audio/wav"></audio>
|
||||
<audio id="hardDropSound" src="sounds/909S.wav" preload="auto" type="audio/wav"></audio>
|
||||
<audio id="lineClearSound" src="sounds/808COW.wav" preload="auto" type="audio/wav"></audio>
|
||||
<audio id="tSpinSound" src="sounds/909CHH.wav" preload="auto" type="audio/wav"></audio>
|
||||
<audio id="tSpinSound" src="sounds/78GUIR.wav" preload="auto" type="audio/wav"></audio>
|
||||
<audio id="quatuorSound" src="sounds/BRRDC1.wav" preload="auto" type="audio/wav"></audio>
|
||||
</span>
|
||||
|
||||
@@ -221,8 +238,6 @@
|
||||
<script src="js/game_logic.js" language="Javascript" type="text/javascript"></script>
|
||||
<script src="js/interface.js" language="Javascript" type="text/javascript"></script>
|
||||
<script src="js/app.js" language="Javascript" type="text/javascript"></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
<script>navigator?.serviceWorker.register('js/service-worker.js')</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
155
js/app.js
155
js/app.js
@@ -1,22 +1,45 @@
|
||||
let scheduler = new Scheduler()
|
||||
let settings = new Settings()
|
||||
let stats = new Stats()
|
||||
let holdQueue = new MinoesTable("holdTable")
|
||||
let matrix = new Matrix()
|
||||
let nextQueue = new NextQueue()
|
||||
let playing = false
|
||||
let scheduler = new Scheduler()
|
||||
let settings = new Settings()
|
||||
let stats = new Stats()
|
||||
let holdQueue = new HoldQueue()
|
||||
let matrix = new Matrix()
|
||||
let nextQueue = new NextQueue()
|
||||
let playing = false
|
||||
//let lastActionSucceded = true
|
||||
let favicon
|
||||
|
||||
window.onload = function(event) {
|
||||
document.selectedStyleSheetSet = stylesheetSelect.value
|
||||
document.selectedStyleSheetSet = selectedStyleSheet.title
|
||||
selectedStyleSheet.href = stylesheetSelect.value
|
||||
favicon = document.querySelector("link[rel~='icon']")
|
||||
|
||||
fullscreenCheckbox.onchange = function() {
|
||||
if (this.checked) {
|
||||
document.documentElement.requestFullscreen()
|
||||
} else {
|
||||
document.exitFullscreen()
|
||||
}
|
||||
}
|
||||
|
||||
restart()
|
||||
}
|
||||
|
||||
document.onfullscreenchange = function() {
|
||||
if (document.fullscreenElement) {
|
||||
fullscreenCheckbox.checked = true
|
||||
} else {
|
||||
fullscreenCheckbox.checked = false
|
||||
if (playing) pauseSettings()
|
||||
}
|
||||
}
|
||||
document.onfullscreenerror = function() {
|
||||
fullscreenCheckbox.checked = false
|
||||
}
|
||||
|
||||
function restart() {
|
||||
stats.modal.hide()
|
||||
holdQueue.init()
|
||||
holdQueue.redraw()
|
||||
stats.init()
|
||||
matrix.init()
|
||||
nextQueue.init()
|
||||
@@ -94,6 +117,8 @@ function ticktack() {
|
||||
|
||||
function generate(piece) {
|
||||
matrix.piece = piece || nextQueue.shift()
|
||||
if (!piece && holdQueue.piece) holdQueue.drawPiece()
|
||||
//lastActionSucceded = true
|
||||
favicon.href = matrix.piece.favicon_href
|
||||
|
||||
if (matrix.piece.canMove(TRANSLATION.NONE)) {
|
||||
@@ -112,37 +137,30 @@ let playerActions = {
|
||||
|
||||
rotateCounterclockwise: () => matrix.piece.rotate(ROTATION.CCW),
|
||||
|
||||
softDrop: function() {
|
||||
if (matrix.piece.move(TRANSLATION.DOWN)) {
|
||||
stats.score++
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
softDrop: () => matrix.piece.move(TRANSLATION.DOWN) && ++stats.score,
|
||||
|
||||
hardDrop: function() {
|
||||
scheduler.clearTimeout(lockDown)
|
||||
playSound(hardDropSound)
|
||||
while (matrix.piece.move(TRANSLATION.DOWN, ROTATION.NONE, true)) stats.score +=2
|
||||
// wallSound.currentTime = 0
|
||||
// wallSound.pause()
|
||||
matrix.table.classList.add("hard-dropped-table-animation")
|
||||
while (matrix.piece.move(TRANSLATION.DOWN, ROTATION.NONE, true)) stats.score += 2
|
||||
matrixCard.classList.remove("hard-dropped-table-animation")
|
||||
matrixCard.offsetHeight;
|
||||
matrixCard.classList.add("hard-dropped-table-animation") // restart animation
|
||||
lockDown()
|
||||
return true
|
||||
},
|
||||
|
||||
hold: function() {
|
||||
if (matrix.piece.holdEnabled) {
|
||||
scheduler.clearInterval(fall)
|
||||
scheduler.clearTimeout(lockDown)
|
||||
|
||||
let heldPiece = holdQueue.piece
|
||||
matrix.piece.facing = FACING.NORTH
|
||||
matrix.piece.locked = false
|
||||
holdQueue.piece = matrix.piece
|
||||
holdQueue.piece.holdEnabled = false
|
||||
holdQueue.piece.locked = false
|
||||
generate(heldPiece)
|
||||
|
||||
let piece = matrix.piece
|
||||
piece.facing = FACING.NORTH
|
||||
piece.locked = false
|
||||
generate(holdQueue.piece)
|
||||
matrix.piece.holdEnabled = false
|
||||
holdQueue.piece = piece
|
||||
}
|
||||
},
|
||||
|
||||
@@ -164,6 +182,12 @@ function onkeydown(event) {
|
||||
if (!pressedKeys.has(event.key)) {
|
||||
pressedKeys.add(event.key)
|
||||
action = settings.keyBind[event.key]
|
||||
/*if (action()) {
|
||||
lastActionSucceded = true
|
||||
} else if (lastActionSucceded || !(action in REPEATABLE_ACTIONS)) {
|
||||
playSound(wallSound)
|
||||
lastActionSucceded = false
|
||||
}*/
|
||||
action()
|
||||
if (REPEATABLE_ACTIONS.includes(action)) {
|
||||
actionsQueue.unshift(action)
|
||||
@@ -186,10 +210,15 @@ function repeat() {
|
||||
|
||||
function autorepeat() {
|
||||
if (actionsQueue.length) {
|
||||
/*if (actionsQueue[0]()) {
|
||||
lastActionSucceded = true
|
||||
} else if (lastActionSucceded) {
|
||||
wallSound.play()
|
||||
lastActionSucceded = false
|
||||
}*/
|
||||
actionsQueue[0]()
|
||||
} else {
|
||||
scheduler.clearInterval(autorepeat)
|
||||
}
|
||||
else scheduler.clearInterval(autorepeat)
|
||||
}
|
||||
|
||||
function onkeyup(event) {
|
||||
@@ -199,9 +228,12 @@ function onkeyup(event) {
|
||||
action = settings.keyBind[event.key]
|
||||
if (actionsQueue.includes(action)) {
|
||||
actionsQueue.splice(actionsQueue.indexOf(action), 1)
|
||||
if (!actionsQueue.length) {
|
||||
scheduler.clearTimeout(repeat)
|
||||
scheduler.clearInterval(autorepeat)
|
||||
scheduler.clearTimeout(repeat)
|
||||
scheduler.clearInterval(autorepeat)
|
||||
if (actionsQueue.length) {
|
||||
if (actionsQueue[0] == playerActions.softDrop) scheduler.setInterval(autorepeat, settings.fallPeriod/20)
|
||||
else scheduler.setTimeout(repeat, settings.das)
|
||||
} else {
|
||||
matrix.drawPiece()
|
||||
}
|
||||
}
|
||||
@@ -217,9 +249,7 @@ function lockDown() {
|
||||
scheduler.clearInterval(fall)
|
||||
|
||||
if (matrix.lock()) {
|
||||
let tSpin = matrix.piece.tSpin
|
||||
let nbClearedLines = matrix.clearLines()
|
||||
stats.lockDown(nbClearedLines, tSpin)
|
||||
stats.lockDown(matrix.piece.tSpin, matrix.clearLines())
|
||||
|
||||
generate()
|
||||
} else {
|
||||
@@ -236,7 +266,7 @@ messagesSpan.onanimationend = function(event) {
|
||||
}
|
||||
|
||||
function gameOver() {
|
||||
matrix.piece.locked = false
|
||||
matrix.piece.locked = true
|
||||
matrix.drawPiece()
|
||||
|
||||
document.onkeydown = null
|
||||
@@ -253,7 +283,54 @@ window.onbeforeunload = function(event) {
|
||||
if (playing) return false;
|
||||
}
|
||||
|
||||
// Play with 3D
|
||||
let mousedown = false
|
||||
let rX0 = -15
|
||||
let rY0 = 0
|
||||
let clientX0 = 0
|
||||
let clientY0 = 0
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('service-worker.js');
|
||||
sceneDiv.onmousedown = function(event) {
|
||||
mousedown = true
|
||||
rX0 = parseInt(getComputedStyle(screenRow).getPropertyValue("--rX"))
|
||||
dy0 = parseInt(getComputedStyle(screenRow).getPropertyValue("--rY"))
|
||||
clientX0 = event.clientX
|
||||
clientY0 = event.clientY
|
||||
}
|
||||
|
||||
sceneDiv.onmousemove = function(event) {
|
||||
if (mousedown) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
rX = (rX0 - 0.5 * (event.clientY - clientY0)) % 360
|
||||
screenRow.style.setProperty("--rX", rX)
|
||||
if (rX >= 0) {
|
||||
screenRow.classList.remove("top")
|
||||
screenRow.classList.add("bottom")
|
||||
} else {
|
||||
screenRow.classList.add("top")
|
||||
screenRow.classList.remove("bottom")
|
||||
}
|
||||
rY = (rY0 + 0.5 * (event.clientX - clientX0)) % 360
|
||||
screenRow.style.setProperty("--rY", rY)
|
||||
if (rY <= 0) {
|
||||
screenRow.classList.remove("left")
|
||||
screenRow.classList.add("right")
|
||||
} else {
|
||||
screenRow.classList.add("left")
|
||||
screenRow.classList.remove("right")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sceneDiv.onmouseup = document.onmouseleave = function(event) {
|
||||
mousedown = false
|
||||
}
|
||||
|
||||
sceneDiv.onwheel = function(event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
let tZ = parseInt(getComputedStyle(screenRow).getPropertyValue("--tZ"))
|
||||
tZ -= event.deltaY
|
||||
screenRow.style.setProperty("--tZ", tZ + "px")
|
||||
}
|
||||
@@ -44,29 +44,6 @@ const FACING = {
|
||||
WEST: 3,
|
||||
}
|
||||
|
||||
const KEY_NAMES = new Proxy({
|
||||
["ArrowLeft"] : "←",
|
||||
["←"] : "ArrowLeft",
|
||||
["ArrowRight"] : "→",
|
||||
["→"] : "ArrowRight",
|
||||
["ArrowUp"] : "↑",
|
||||
["↑"] : "ArrowUp",
|
||||
["ArrowDown"] : "↓",
|
||||
["↓"] : "ArrowDown",
|
||||
[" "] : "Espace",
|
||||
["Espace"] : " ",
|
||||
["Escape"] : "Échap.",
|
||||
["Échap."] : "Escape",
|
||||
["Backspace"] : "Ret. arrière",
|
||||
["Ret. arrière"]: "Backspace",
|
||||
["Enter"] : "Entrée",
|
||||
["Entrée"] : "Enter",
|
||||
}, {
|
||||
get(obj, keyName) {
|
||||
return keyName in obj? obj[keyName] : keyName
|
||||
}
|
||||
})
|
||||
|
||||
/* Customize Array to be use as position */
|
||||
Object.defineProperties(Array.prototype, {
|
||||
"x": {
|
||||
@@ -103,17 +80,32 @@ class Scheduler {
|
||||
}
|
||||
|
||||
setInterval(func, delay, ...args) {
|
||||
this.intervalTasks.set(func, window.setInterval(func, delay, ...args))
|
||||
if (this.intervalTasks.has(func)) {
|
||||
console.warn(`$func already in intervalTasks`)
|
||||
return false
|
||||
} else {
|
||||
this.intervalTasks.set(func, window.setInterval(func, delay, ...args))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(func, delay, ...args) {
|
||||
this.timeoutTasks.set(func, window.setTimeout(func, delay, ...args))
|
||||
if (this.timeoutTasks.has(func)) {
|
||||
console.warn(`$func already in timeoutTasks`)
|
||||
return false
|
||||
} else {
|
||||
this.timeoutTasks.set(func, window.setTimeout(func, delay, ...args))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
clearInterval(func) {
|
||||
if (this.intervalTasks.has(func)) {
|
||||
window.clearInterval(this.intervalTasks.get(func))
|
||||
this.intervalTasks.delete(func)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +113,9 @@ class Scheduler {
|
||||
if (this.timeoutTasks.has(func)) {
|
||||
window.clearTimeout(this.timeoutTasks.get(func))
|
||||
this.timeoutTasks.delete(func)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +171,20 @@ class MinoesTable {
|
||||
MinoesTable.prototype.init_center = [2, 2]
|
||||
|
||||
|
||||
class HoldQueue extends MinoesTable {
|
||||
constructor() {
|
||||
super("holdTable")
|
||||
}
|
||||
|
||||
drawPiece(piece=this.piece, className=piece.className) {
|
||||
if (!matrix.piece.holdEnabled) {
|
||||
className += " disabled"
|
||||
}
|
||||
super.drawPiece(piece, className)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NextQueue extends MinoesTable {
|
||||
constructor() {
|
||||
super("nextTable")
|
||||
@@ -242,8 +251,12 @@ class Matrix extends MinoesTable {
|
||||
if (piece.locked) className += " locking"
|
||||
if (piece==this.piece && actionsQueue.length) className += " moving"
|
||||
super.drawPiece(piece, className)
|
||||
matrix.table.style.setProperty('--piece-column', this.piece.center.x)
|
||||
matrix.table.style.setProperty('--piece-row', this.piece.center.y)
|
||||
this.table.style.setProperty('--piece-column', this.piece.center.x)
|
||||
this.table.style.setProperty('--piece-row', this.piece.center.y)
|
||||
}
|
||||
|
||||
clearPiece(piece=this.piece, className="") {
|
||||
super.drawPiece(piece, className)
|
||||
}
|
||||
|
||||
redraw() {
|
||||
@@ -319,7 +332,7 @@ class Tetromino {
|
||||
let success = this.canMove(translation, rotation)
|
||||
if (success) {
|
||||
scheduler.clearTimeout(lockDown)
|
||||
matrix.drawPiece(this, hardDropped? "trail-animation" : "")
|
||||
matrix.clearPiece(this, hardDropped? "trail-animation" : "")
|
||||
this.center = success.center
|
||||
if (rotation) this.facing = success.facing
|
||||
this.lastRotation = rotation
|
||||
@@ -331,14 +344,11 @@ class Tetromino {
|
||||
}
|
||||
matrix.drawPiece()
|
||||
return true
|
||||
} else if (!hardDropped) {
|
||||
wallSound.play()
|
||||
if (translation == TRANSLATION.DOWN) {
|
||||
this.locked = true
|
||||
if (!scheduler.timeoutTasks.has(lockDown))
|
||||
scheduler.setTimeout(lockDown, stats.lockDelay)
|
||||
matrix.drawPiece()
|
||||
}
|
||||
} else if (!hardDropped && translation == TRANSLATION.DOWN) {
|
||||
this.locked = true
|
||||
if (!scheduler.timeoutTasks.has(lockDown))
|
||||
scheduler.setTimeout(lockDown, stats.lockDelay)
|
||||
matrix.drawPiece()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
const KEY_NAMES = new Proxy({
|
||||
["ArrowLeft"] : "←",
|
||||
["←"] : "ArrowLeft",
|
||||
["ArrowRight"] : "→",
|
||||
["→"] : "ArrowRight",
|
||||
["ArrowUp"] : "↑",
|
||||
["↑"] : "ArrowUp",
|
||||
["ArrowDown"] : "↓",
|
||||
["↓"] : "ArrowDown",
|
||||
[" "] : "Espace",
|
||||
["Espace"] : " ",
|
||||
["Escape"] : "Échap.",
|
||||
["Échap."] : "Escape",
|
||||
["Backspace"] : "Ret. arrière",
|
||||
["Ret. arrière"]: "Backspace",
|
||||
["Enter"] : "Entrée",
|
||||
["Entrée"] : "Enter",
|
||||
}, {
|
||||
get(target, key) {
|
||||
return key in target? target[key] : key
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
class Settings {
|
||||
constructor() {
|
||||
this.form = settingsForm
|
||||
@@ -7,20 +31,15 @@ class Settings {
|
||||
}
|
||||
|
||||
load() {
|
||||
for (let element of settingsForm.elements) {
|
||||
if (element.name) {
|
||||
if (localStorage[element.name]) element.value = localStorage[element.name]
|
||||
}
|
||||
}
|
||||
this.form.querySelectorAll("[name]").forEach(element => {
|
||||
if (element.name in localStorage)
|
||||
element.value = localStorage[element.name]
|
||||
})
|
||||
window.document.selectedStyleSheetSet = stylesheetSelect.value
|
||||
}
|
||||
|
||||
save() {
|
||||
for (let element of settingsForm.elements) {
|
||||
if (element.name) {
|
||||
localStorage[element.name] = element.value
|
||||
}
|
||||
}
|
||||
this.form.querySelectorAll("[name]").forEach(element => localStorage[element.name] = element.value)
|
||||
}
|
||||
|
||||
init() {
|
||||
@@ -49,7 +68,12 @@ class Settings {
|
||||
this[input.name] = input.checked == true
|
||||
}
|
||||
|
||||
this.keyBind = {}
|
||||
this.keyBind = new Proxy({}, {
|
||||
get: (target, key) => target[key.toLowerCase()],
|
||||
set: (target, key, value) => target[key.toLowerCase()] = value,
|
||||
has: (target, key) => key.toLowerCase() in target
|
||||
|
||||
})
|
||||
for (let actionName in playerActions) {
|
||||
this.keyBind[settings[actionName]] = playerActions[actionName]
|
||||
}
|
||||
@@ -59,13 +83,29 @@ class Settings {
|
||||
function changeKey(input) {
|
||||
prevValue = input.value
|
||||
input.value = ""
|
||||
keyInputs = Array.from(input.form.querySelectorAll("input[type='text']"))
|
||||
input.onkeydown = function (event) {
|
||||
event.preventDefault()
|
||||
input.value = KEY_NAMES[event.key]
|
||||
input.blur()
|
||||
keyInputs.forEach(input => {
|
||||
input.setCustomValidity("")
|
||||
input.classList.remove("is-invalid")
|
||||
})
|
||||
keyInputs.sort((input1, input2) => {
|
||||
if(input1.value == input2.value) {
|
||||
input1.setCustomValidity("Touche déjà utilisée")
|
||||
input1.classList.add("is-invalid")
|
||||
input2.setCustomValidity("Touche déjà utilisée")
|
||||
input2.classList.add("is-invalid")
|
||||
}
|
||||
return input1.value > input2.value
|
||||
})
|
||||
if (input.checkValidity()) {
|
||||
input.blur()
|
||||
}
|
||||
}
|
||||
input.onblur = function (event) {
|
||||
if (input.value == "") input.value = prevValue
|
||||
if (!input.value) input.value = prevValue
|
||||
input.onkeydown = null
|
||||
input.onblur = null
|
||||
}
|
||||
@@ -171,7 +211,7 @@ class Stats {
|
||||
return new Date() - this.startTime
|
||||
}
|
||||
|
||||
lockDown(nbClearedLines, tSpin) {
|
||||
lockDown(tSpin, nbClearedLines) {
|
||||
this.totalClearedLines += nbClearedLines
|
||||
if (nbClearedLines == 4) this.nbQuatuors++
|
||||
if (tSpin == T_SPIN.T_SPIN) this.nbTSpin++
|
||||
@@ -229,13 +269,13 @@ class Stats {
|
||||
messagesSpan.addNewChild("div", {
|
||||
className: "zoom-in-animation",
|
||||
style: "animation-delay: .4s",
|
||||
innerHTML: `BOUT EN BOUT<br/>${b2bScore}`
|
||||
innerHTML: `BOUT À BOUT<br/>${b2bScore}`
|
||||
})
|
||||
} else {
|
||||
messagesSpan.addNewChild("div", {
|
||||
className: "zoom-in-animation",
|
||||
style: "animation-delay: .4s",
|
||||
innerHTML: `BOUT EN BOUT x${this.b2b}<br/>${b2bScore}`
|
||||
innerHTML: `BOUT À BOUT x${this.b2b}<br/>${b2bScore}`
|
||||
})
|
||||
}
|
||||
this.score += b2bScore
|
||||
@@ -245,7 +285,7 @@ class Stats {
|
||||
messagesSpan.addNewChild("div", {
|
||||
className: "zoom-in-animation",
|
||||
style: "animation-delay: .4s",
|
||||
innerHTML: `FIN DU BOUT EN BOUT`
|
||||
innerHTML: `FIN DU BOUT À BOUT`
|
||||
})
|
||||
}
|
||||
this.b2b = -1
|
||||
|
||||
@@ -16,7 +16,7 @@ Copyright 2015, 2019, 2020 Google LLC. All Rights Reserved.
|
||||
const OFFLINE_VERSION = 1;
|
||||
const CACHE_NAME = "offline";
|
||||
// Customize this with a different URL if needed.
|
||||
const OFFLINE_URL = "index.html";
|
||||
const OFFLINE_URL = "../index.html";
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
BIN
sounds/78GUIR.wav
Normal file
BIN
sounds/78GUIR.wav
Normal file
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user