Back to Projects
Stars: 2Language: HTMLUpdated: 9/1/2026
README
# uzex-time
Server vaqti sinxronizatori va **bosish vaqtini oldindan hisoblab beruvchi**
signal tizimi. Kim qo'lda bid qo'yadi - shu odam uchun.
## ⚠️ Eng muhim g'oya
Soat aniqligi muammo emas edi. Soat **±5 ms** aniqlikda ishlaydi, lekin oxirgi
sinovda bid **1-2 sekund** kech tushdi. Farq 200-400 barobar - demak xato
soatda emas, **signal va serverga yozilish orasidagi yo'lda**.
Bu yo'l quyidagilardan iborat:
| Bosqich | Odatda | Nazorat qilinadimi |
|---|---|---|
| Signalni eshitish → bosish | 200-300 ms (±100 ms tarqoqlik) | **Ha - sanoq bilan** |
| Auktsion sahifasi → so'rov | 5-50 ms | Qisman |
| LAN | 1-5 ms | Yo'q (kichik) |
| **Server navbati (yuzlab bid bir vaqtda)** | **100 ms - bir necha sekund** | **Qisman - zaxira bilan** |
Eski versiyada signal `59.750s` da chalinardi, ya'ni target'dan **250 ms
oldin**. Odamning reaksiyasi ham ~250 ms. Natijada bosish aynan `10:00:00.000`
ga - ya'ni **muddat tugagan lahzaga** tushardi, navbat esa uni yana 1-2 sekund
orqaga surardi. Bu versiya shu xatoni tuzatadi.
## 🎯 Yechim: reaksiya emas, oldindan his qilish
1. **Sanoq (3-2-1).** Signal endi bitta zarba emas. Undan oldin har sekundda
qisqa "tik" chalinadi va ekranda chiziq to'ladi. Ovozga *reaksiya qilish*
~250 ms va ±100 ms tarqoqlik beradi; ritmni *oldindan his qilib* bosish
tarqoqlikni bir necha o'n ms gacha tushiradi. Bu tayyorlangan musiqachi
bilan cho'chib ketgan odam orasidagi farq.
2. **Oldinga surish (lead).** Signal endi target'da emas, `target - lead` da
chalinadi:
* **Reaksiya (ms)** - shaxsiy kechikishingiz. Taxmin qilinmaydi, **mashq
rejimida o'lchanadi**.
* **Navbat zaxirasi (ms)** - server navbati uchun. Bu **kuzatilgan** son
bo'lishi kerak: bid qo'yib, auktsion ro'yxatida serverning o'zi qo'ygan
vaqtni ko'ring va farqni yozing.
3. **Soat hech qachon siljitilmaydi.** Faqat signal oldinga suriladi, shuning
uchun ekrandagi vaqt haqiqiy bo'lib qoladi va auktsion ekrani bilan
solishtirsa bo'ladi.
## 🧪 Mashq (kalibrovka)
Sanoq davomida oxirgi zarbaga mos ravishda **PROBEL** bosing (yoki panel'dagi
tugmani). Har urinish uchun belgili xato yoziladi:
* **O'rtacha** - sizning doimiy kechikishingiz. `O'lchovni qo'llash` tugmasi
uni to'g'ridan-to'g'ri "Reaksiya" maydoniga qo'yadi.
* **Tarqoqlik** - ishonchlilik. Agar ± 100 ms bo'lsa, siz hali reaksiya
qilyapsiz; ± 30 ms atrofida bo'lsa, ritmni his qilyapsiz. **Tarqoqlik
tushmaguncha mashq qiling** - o'rtachani tuzatib bo'ladi, tarqoqlikni yo'q.
Sozlamalar `localStorage` da saqlanadi: joyida sahifani qayta ochsangiz,
shoshilinch ravishda qaytadan o'lchash shart emas.
## 🔌 LAN (internetsiz) rejimi
Eng katta yashirin xavf: **auktsion serverining soati** - bid o'z vaqtida
tushdimi yoki yo'qmi, shuni faqat **o'sha** soat hal qiladi. `time.uzex.uz`
bilan mukammal sinxron bo'lib, ayni paytda noto'g'ri soatga qarab turgan
bo'lishingiz mumkin.
Shuning uchun manba sozlanadigan qilindi:
```bash
TIME_UPSTREAM=http://10.0.0.5/ node server.js # bash
$env:TIME_UPSTREAM='http://10.0.0.5/'; node server.js # PowerShell
```
Manba **istalgan HTTP server** bo'lishi mumkin. Agar javob tanasi epoch-ms son
bo'lmasa, `Date` sarlavhasiga o'tiladi - uni har qanday server yuboradi.
`Date` faqat sekund aniqligida, shuning uchun mijoz **qirra (edge) qidirish**
rejimiga o'tadi: tez-tez so'rov yuborib, sekund **almashgan lahzani** ikki
o'lchov orasiga qisib oladi. Shu yo'l bilan sekundlik sarlavhadan LAN'da
**±30 ms** aniqlik chiqadi (sinovda: mahalliy soatga nisbatan 11 ms xato).
## 📋 Joyidagi tartib
1. Noutbukni **simli** ulang (Wi-Fi 5-50 ms tebranish qo'shadi).
2. `TIME_UPSTREAM` ni auktsion serveriga qaratib `node server.js` ni ishga
tushiring; holat qatorida qaysi manbaga qulflanganini tekshiring.
3. **Target** ni bosish tushishi kerak bo'lgan lahzaga qo'ying.
4. Bir necha daqiqa **mashq qiling**, keyin `O'lchovni qo'llash`.
5. **Navbat zaxirasi** ni o'tgan auktsionlardagi kuzatuvingizdan kiriting.
Ma'lumot bo'lmasa, birinchi marta ehtiyotkorlik bilan katta oling: kech
tushgan bid umuman hisobga olinmaydi, erta tushgani esa hisobga olinadi.
6. Sanoqni kuting, `HOZIR BOSING` da bosing.
7. **Har safar yozib boring**: qachon bosdingiz va server qaysi vaqtni qo'ydi.
Farq - keyingi safar uchun navbat zaxirasi.
## 🖥️ Lokal ishga tushirish
```bash
npm run dev # yoki: node server.js
# -> http://localhost:3000
```
`server.js` statik sahifani va Vercel'dagi bilan **bir xil** `/api/time`
funksiyasini yuritadi.
> `index.html` ni fayl sifatida ochish tavsiya etilmaydi: proksi (`/api/time`)
> shart, chunki manba CORS sarlavhalarini bermaydi.
## ⚙️ Aniqlik haqida
Proksi o'zining ichki vaqtini qaytaradi (`innerRtt`, `postFetchMs`,
`handlerMs`), brauzer esa buni umumiy kechikishdan ayiradi - shunda faqat sof
tarmoq vaqti simmetrik deb hisoblanadi:
```
netRtt = clientRtt - handlerMs
serverAtRecv = serverTimestamp + innerRtt/2 + postFetchMs + netRtt/2
```
Boshqa xossalar: har 2 sekundda avtomatik sinxronizatsiya (`:10` va `:40`),
30 sekundlik oynada NTP uslubidagi mediana + og'irlikli o'rtacha, soat
**hech qachon orqaga sakramaydi** (slew), sinxron bo'lmaganda signal
**butunlay o'chiriladi**.
**Muhim:** target lahzasida endi "zaxira" signal chalinmaydi. Lead sozlangan
holda bunday signal aynan **allaqachon kech bo'lgan** lahzada "bos" deb
turgan bo'lardi - ya'ni tuzatilayotgan xatoning o'zi. Ovoz rejalashtirilmasa,
dastur signal bermay, buni yozib ko'rsatadi.
## 📦 Vercel
Konfiguratsiya nol-sozlamali. `TIME_UPSTREAM` ni Vercel env o'zgaruvchisi
sifatida ham berish mumkin, lekin joyidagi LAN uchun lokal `server.js`
ishonchliroq - internetga bog'liq emas.