Initial commit: game development

This commit is contained in:
robi committed 2026-09-23 16:31:05 +03:00
commit 176d7cc300
5 files changed
+1084

No files matched your search

+431
View File
@@ -0,0 +1,431 @@
:root {
--bg-1: #0d0f24;
--bg-2: #1c1140;
--cyan: #22d3ee;
--pink: #f472b6;
--glass: rgba(255, 255, 255, 0.06);
--glass-strong: rgba(255, 255, 255, 0.1);
--glass-border: rgba(255, 255, 255, 0.14);
--text: #ffffff;
--muted: rgba(255, 255, 255, 0.55);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
background: linear-gradient(180deg, var(--bg-1) 0%, var(--bg-2) 100%);
background-attachment: fixed;
color: var(--text);
min-height: 100dvh;
display: flex;
justify-content: center;
overflow-x: hidden;
}
/* ---------- background blobs ---------- */
.bg-blob {
position: fixed;
border-radius: 50%;
filter: blur(70px);
pointer-events: none;
z-index: 0;
}
.blob-cyan {
width: 340px;
height: 340px;
left: -120px;
top: 8%;
background: var(--cyan);
opacity: 0.2;
}
.blob-magenta {
width: 380px;
height: 380px;
right: -140px;
bottom: 4%;
background: var(--pink);
opacity: 0.16;
}
/* ---------- layout ---------- */
.app {
position: relative;
z-index: 1;
width: 100%;
max-width: 420px;
min-height: 100dvh;
display: flex;
flex-direction: column;
align-items: center;
gap: 18px;
padding:
calc(28px + env(safe-area-inset-top))
16px
calc(28px + env(safe-area-inset-bottom));
}
.title {
font-size: clamp(28px, 8vw, 34px);
font-weight: 800;
letter-spacing: 0.5px;
background: linear-gradient(90deg, var(--cyan), var(--pink));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
/* ---------- scoreboard ---------- */
.scoreboard {
display: flex;
gap: 10px;
width: 100%;
}
.chip {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
padding: 12px 8px;
background: var(--glass);
border: 1px solid var(--glass-border);
border-radius: 16px;
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.chip-label {
font-size: 10px;
font-weight: 600;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--muted);
}
.chip-value {
font-size: 22px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.chip-x { color: var(--cyan); }
.chip-o { color: var(--pink); }
.chip-value.pop {
animation: score-pop 320ms ease;
}
@keyframes score-pop {
0% { transform: scale(1); }
40% { transform: scale(1.35); }
100% { transform: scale(1); }
}
/* ---------- status ---------- */
.status {
height: 20px;
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
transition: opacity 150ms ease;
}
.status.fading { opacity: 0; }
.status.thinking .status-text {
animation: status-pulse 900ms ease-in-out infinite;
}
@keyframes status-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* ---------- board ---------- */
.board-wrap {
position: relative;
}
.board {
width: min(88vw, 340px);
aspect-ratio: 1;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 10px;
padding: 14px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 24px;
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
user-select: none;
-webkit-user-select: none;
}
.board.shake {
animation: shake 450ms ease;
border-color: rgba(244, 63, 94, 0.5);
box-shadow: 0 0 34px rgba(244, 63, 94, 0.3);
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
20% { transform: translateX(-7px); }
40% { transform: translateX(6px); }
60% { transform: translateX(-4px); }
80% { transform: translateX(3px); }
}
.board.pulse {
animation: board-pulse 600ms ease;
}
@keyframes board-pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.03); }
}
.cell {
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
cursor: pointer;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
transition: background 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
}
.cell.empty:active {
background: var(--glass-strong);
border-color: rgba(255, 255, 255, 0.25);
}
@media (hover: hover) {
.cell.empty:hover {
background: var(--glass-strong);
border-color: rgba(255, 255, 255, 0.25);
box-shadow: 0 0 18px rgba(34, 211, 238, 0.15);
}
}
/* ---------- marks ---------- */
.mark {
width: 58%;
height: 58%;
animation: mark-pop 150ms ease-out;
}
@keyframes mark-pop {
0% { transform: scale(0.3); opacity: 0; }
60% { transform: scale(1.12); opacity: 1; }
100% { transform: scale(1); opacity: 1; }
}
.mark-x {
filter: drop-shadow(0 0 7px rgba(34, 211, 238, 0.65));
}
.mark-o {
filter: drop-shadow(0 0 7px rgba(244, 114, 182, 0.65));
}
.mark line {
stroke: var(--cyan);
stroke-width: 9;
stroke-linecap: round;
}
.mark circle {
fill: none;
stroke: var(--pink);
stroke-width: 9;
}
/* ---------- win line ---------- */
.win-line {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: visible;
z-index: 5;
}
#win-line-el {
filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.45));
}
/* ---------- buttons ---------- */
.buttons {
display: flex;
flex-direction: column;
gap: 12px;
width: 100%;
max-width: 300px;
}
.btn {
border: none;
border-radius: 27px;
height: 54px;
font-family: inherit;
font-size: 16px;
font-weight: 700;
cursor: pointer;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
transition: transform 100ms ease, filter 150ms ease;
}
.btn:active {
transform: scale(0.97);
}
.btn.primary {
background: linear-gradient(90deg, var(--cyan), var(--pink));
color: #0d1025;
box-shadow: 0 6px 24px rgba(34, 211, 238, 0.25);
}
.btn.primary:hover {
filter: brightness(1.1);
}
.btn.ghost {
height: 48px;
font-size: 14px;
font-weight: 500;
border-radius: 24px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.18);
color: rgba(255, 255, 255, 0.7);
}
.btn.ghost:hover {
background: rgba(255, 255, 255, 0.09);
}
/* ---------- overlay ---------- */
.overlay {
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
background: rgba(13, 15, 36, 0.55);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
opacity: 0;
pointer-events: none;
transition: opacity 200ms ease;
padding: 24px;
}
.overlay.show {
opacity: 1;
pointer-events: auto;
}
.modal {
width: 100%;
max-width: 300px;
display: flex;
flex-direction: column;
align-items: center;
gap: 22px;
padding: 34px 28px;
background: var(--glass);
border: 1px solid var(--glass-border);
border-radius: 24px;
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
transform: scale(0.85);
transition: transform 250ms cubic-bezier(0.2, 1.4, 0.4, 1);
}
.overlay.show .modal {
transform: scale(1);
}
.modal-title {
font-size: 24px;
font-weight: 800;
}
.modal .btn {
width: 100%;
}
/* ---------- confetti ---------- */
#confetti-layer {
position: fixed;
inset: 0;
overflow: hidden;
pointer-events: none;
z-index: 100;
}
.confetti {
position: absolute;
top: -24px;
border-radius: 2px;
animation-name: confetti-fall;
animation-timing-function: linear;
animation-fill-mode: forwards;
}
@keyframes confetti-fall {
from {
transform: translate3d(0, 0, 0) rotate(0deg);
opacity: 1;
}
to {
transform: translate3d(var(--drift), 108vh, 0) rotate(var(--spin));
opacity: 0.85;
}
}
/* ---------- toast ---------- */
.toast {
position: fixed;
bottom: calc(24px + env(safe-area-inset-bottom));
left: 50%;
transform: translateX(-50%) translateY(8px);
z-index: 90;
padding: 10px 20px;
font-size: 14px;
background: var(--glass-strong);
border: 1px solid var(--glass-border);
border-radius: 999px;
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
opacity: 0;
pointer-events: none;
transition: opacity 200ms ease, transform 200ms ease;
}
.toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}