Compare commits

...

20 Commits

Author SHA1 Message Date
051fc223e9 Add README 2025-05-21 10:22:42 +02:00
9feaa3c098 meta 2025-05-20 17:01:49 +02:00
3175e7b7ad mouse event only on sceneDiv 2025-04-24 20:41:33 +02:00
4281bf1735 grab 2025-04-21 05:03:50 +02:00
ff37cb7823 jpg background 2025-04-14 08:40:52 +02:00
2a8df78d22 background 2025-04-14 08:30:40 +02:00
344575bdc4 center background 2025-04-13 23:28:06 +02:00
2453b2f6b6 background 2025-04-13 17:19:29 +02:00
25a98bf42d little tweaks 2025-04-10 00:52:43 +02:00
022512a5e6 perspective 2025-04-09 08:29:19 +02:00
d56af40362 clear animation 2025-04-09 01:14:39 +02:00
f33723a786 ghost border 2025-04-09 00:57:53 +02:00
df95139650 ghost 2025-04-09 00:51:34 +02:00
d3b527570c radial gradient 2025-04-08 03:42:07 +02:00
a1722a700d floatting text 2025-04-08 03:30:01 +02:00
6cc8a9e645 fix zoom 2025-04-08 00:46:47 +02:00
9023252822 remove log 2025-04-08 00:29:00 +02:00
9bf3c0de0c zoom on wheel 2025-04-07 23:51:13 +02:00
09f4785ef4 3D 2025-04-07 23:37:24 +02:00
bf9554d917 no need block 2025-04-07 09:36:51 +02:00
8 changed files with 282 additions and 64 deletions

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Quatuor
Falling blocks
![screenshot](https://git.malingrey.fr/adrien/quatuor/raw/branch/master/thumbnail.png)

View File

@ -1,132 +1,276 @@
body * { body {
perspective: 1000px; background-image: url(binaural/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: round;
}
#sceneDiv {
perspective: 500px;
}
#sceneDiv * {
transform-style: preserve-3d;
} }
#screenRow { #screenRow {
transform: rotate3d(-1, 0, 0, 15deg); display: block;
transform-style: preserve-3d; transform: translateZ(var(--tZ)) rotateX(var(--rX)) rotateY(var(--rY));
cursor: grab;
}
#screenRow:active {
cursor: grabbing;
}
#screenRow * {
display: block;
}
#screenRow .col {
display: inline-block !important;
width: max-content;
height: 100%;
vertical-align: top;
} }
.card { .card {
background-color: #363941; background: #36394180;
} }
.minoes-table { #matrixCard {
display: block; background-image: none;
flex-direction: column; }
transform-style: preserve-3d;
#screenRow .card > * {
transform: translateZ(var(--cell-side)); transform: translateZ(var(--cell-side));
transform: translateZ(0); }
will-change: transform;
#screenRow .card-header {
background-color: transparent;
border: none;
}
.minoes-table th,
.minoes-table td {
display: inline-block !important;
width: max-content;
} }
.minoes-table tr { .minoes-table tr {
display: block;
width: max-content; width: max-content;
height: var(--cell-side); height: var(--cell-side);
transform-style: preserve-3d; }
#statsTable tr {
display: table;
width: 100%;
}
#statsTable th,
#statsTable td {
display: table-cell;
border: 0;
} }
tr.matrix td:not(.mino) { tr.matrix td:not(.mino) {
border: 0; border: 0;
will-change: transform;
transform: translateZ(0);
} }
.minoes-table td { .minoes-table td {
display: inline-block; width: var(--cell-side) !important;
width: var(--cell-side);
height: var(--cell-side); height: var(--cell-side);
padding: 0 !important;
will-change: transform;
} }
.mino { .minoes-table .mino {
background: var(--background-color); background: radial-gradient(circle at -150% -200%, #fffb 0%, var(--background-color) 100%);
transform-style: preserve-3d;
overflow: visible; overflow: visible;
} }
.mino::before, .mino::before,
.mino::after { .mino::after {
content: ""; content: '';
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
left: 0; left: 0;
width: inherit; width: inherit;
height: inherit; height: inherit;
background: var(--light-color);
z-index: -1;
} }
.mino::before { .mino::before {
transform: rotateY(-90deg); background: var(--light-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateY(-90deg);
transform-origin: left; transform-origin: left;
} }
.right .mino::before {
background: var(--dark-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateY(90deg);
transform-origin: right;
}
.mino::after { .mino::after {
transform: rotateX(90deg); background: var(--light-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateX(90deg);
transform-origin: top; transform-origin: top;
} }
.bottom .mino::after {
background: var(--dark-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateX(-90deg);
transform-origin: bottom;
}
.I.mino { .I.mino {
--background-color: #42AFE180; --background-color: #42afe1b0;
--light-color: #6CEAFF80; --light-color: #6ceaff80;
--dark-color: #00a4b0b0;
} }
.J.mino { .J.mino {
--background-color: #1165B5B0; --background-color: #1165b5b0;
--light-color: #339BFF80; --light-color: #339bff80;
--dark-color: #00009db0;
} }
.L.mino { .L.mino {
--background-color: #F38927B0; --background-color: #f38927b0;
--light-color: #FFBA5980; --light-color: #ffba5980;
--dark-color: #c54800b0;
} }
.O.mino { .O.mino {
--background-color: #F6D03CB0; --background-color: #f6d03cb0;
--light-color: #FFFF7F80; --light-color: #ffff7f80;
--dark-color: #ca9501b0;
} }
.S.mino { .S.mino {
--background-color: #51B84DB0; --background-color: #51b84db0;
--light-color: #84F88080; --light-color: #84f88080;
--dark-color: #1cbc02b0;
} }
.T.mino { .T.mino {
--background-color: #9739A2B0; --background-color: #9739a2b0;
--light-color: #D958E980; --light-color: #d958e980;
--dark-color: #6e019ab0;
} }
.Z.mino { .Z.mino {
--background-color: #EB4F65B0; --background-color: #eb4f65b0;
--light-color: #FF7F7980; --light-color: #ff7f7980;
--dark-color: #ad1936b0;
} }
.ghost.mino { .ghost.mino {
--background-color: #8888; --background-color: #8886;
--light-color: #CCC8; --light-color: #ccc6;
--dark-color: #3336;
} }
.locking.mino { .locking.mino {
--background-color: #EEE8; --background-color: #eeeb;
--light-color: #FFF8; --light-color: #fffb;
--dark-color: #dddb;
} }
.disabled.mino { .disabled.mino {
--background-color: #EEE8; --background-color: #888b;
--light-color: #FFF8; --light-color: #cccb;
} --dark-color: #333b;
.hard-dropped-table-animation {
animation: none;
} }
@keyframes cleared-line-animation { @keyframes cleared-line-animation {
from { from {
background-color: #eeeeee; background-color: #ceffff66;
box-shadow: -200px 0 5px white, 200px 0 5px white;
} }
to { to {
background-color: transparent; background-color: transparent;
} }
} }
@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/binaural/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1,5 +1,8 @@
:root { :root {
--cell-side: 24px; --cell-side: 24px;
--rX: -15deg;
--rY: 0;
--tZ: 0;
} }
body { body {
@ -22,7 +25,7 @@ body {
} }
#matrixCard { #matrixCard {
background: radial-gradient(#222, #25292d) background-image: radial-gradient(#222, #25292d)
} }
.card-header { .card-header {

View File

@ -15,6 +15,11 @@ body[data-bs-theme="dark"] {
background-color: rgba(37, 41, 45, 40%); 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) { .mino:not(.ghost):not(.locking):not(.disabled) {
padding: 1px; padding: 1px;
position: relative; position: relative;
@ -46,8 +51,8 @@ body[data-bs-theme="dark"] {
} }
.ghost.mino { .ghost.mino {
background: transparent; background: rgba(242, 255, 255, 10%);
border: 1px solid rgba(255, 255, 255, 0.3); border : 2px solid rgba(255, 255, 255, 0.3);
border-radius: 3px; border-radius: 3px;
box-shadow: 0px 0px 10px rgba(242, 255, 255, 75%); box-shadow: 0px 0px 10px rgba(242, 255, 255, 75%);
} }

View File

@ -32,42 +32,42 @@ tr.matrix td:not(.mino) {
width: inherit; width: inherit;
height: inherit; height: inherit;
display: block; display: block;
box-shadow: 0 -6px 0 var(--light-color); box-shadow: 0 -6px 0 var(--box-shadow-color);
} }
.I.mino { .I.mino {
--background-color: #42AFE1; --background-color: #42AFE1;
--light-color: #6CEAFF; --box-shadow-color: #6CEAFF;
} }
.J.mino { .J.mino {
--background-color: #1165B5; --background-color: #1165B5;
--light-color: #339BFF; --box-shadow-color: #339BFF;
} }
.L.mino { .L.mino {
--background-color: #F38927; --background-color: #F38927;
--light-color: #FFBA59; --box-shadow-color: #FFBA59;
} }
.O.mino { .O.mino {
--background-color: #F6D03C; --background-color: #F6D03C;
--light-color: #FFFF7F; --box-shadow-color: #FFFF7F;
} }
.S.mino { .S.mino {
--background-color: #51B84D; --background-color: #51B84D;
--light-color: #84F880; --box-shadow-color: #84F880;
} }
.T.mino { .T.mino {
--background-color: #9739A2; --background-color: #9739A2;
--light-color: #D958E9; --box-shadow-color: #D958E9;
} }
.Z.mino { .Z.mino {
--background-color: #EB4F65; --background-color: #EB4F65;
--light-color: #FF7F79; --box-shadow-color: #FF7F79;
} }
.ghost.mino { .ghost.mino {

View File

@ -21,6 +21,15 @@
<link rel="icon" type="image/png" sizes="32x32" href="favicons/T-2.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="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png">
<link rel="manifest" href="manifest.json"> <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> </head>
<body data-bs-theme="dark"> <body data-bs-theme="dark">
@ -86,7 +95,7 @@
</div> </div>
</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 id="screenRow" class="row row-cols-auto align-items-start gap-2">
<div class="col d-flex flex-column align-items-end"> <div class="col d-flex flex-column align-items-end">

View File

@ -244,7 +244,7 @@ messagesSpan.onanimationend = function(event) {
} }
function gameOver() { function gameOver() {
matrix.piece.locked = false matrix.piece.locked = true
matrix.drawPiece() matrix.drawPiece()
document.onkeydown = null document.onkeydown = null
@ -260,3 +260,55 @@ window.onbeforeunload = function(event) {
settings.save() settings.save()
if (playing) return false; if (playing) return false;
} }
// Play with 3D
let mousedown = false
let rX0 = 0
let rY0 = 0
let clientX0 = 0
let clientY0 = 0
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 - event.clientY + clientY0 + 360) % 360
screenRow.style.setProperty("--rX", rX + "deg")
if (rX <= 180) {
screenRow.classList.remove("top")
screenRow.classList.add("bottom")
} else {
screenRow.classList.add("top")
screenRow.classList.remove("bottom")
}
rY = (rY0 + event.clientX - clientX0 + 360) % 360
screenRow.style.setProperty("--rY", rY + "deg")
if (rY >= 180) {
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")
}