Skip to content

Commit 033f7a6

Browse files
committed
deploy: 1479ba8
1 parent c6ac83c commit 033f7a6

1 file changed

Lines changed: 95 additions & 8 deletions

File tree

human-ping.html

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,25 @@
3333
position: absolute;
3434
left: 8px;
3535
bottom: 8px;
36+
z-index: 10;
37+
}
38+
39+
.circle {
40+
position: absolute;
41+
width: 80px;
42+
height: 80px;
43+
border-radius: 50%;
44+
border: 4px solid rgba(255, 255, 255, 0.5);
45+
display: flex;
46+
align-items: center;
47+
justify-content: center;
48+
font-size: 24px;
49+
font-weight: bold;
50+
color: white;
51+
transform: translate(-50%, -50%);
52+
pointer-events: none;
53+
transition: opacity 0.5s;
54+
text-shadow: 0 1px 2px rgba(0,0,0,0.5);
3655
}
3756
</style>
3857
</head>
@@ -47,14 +66,37 @@
4766
class App extends webfx.View {
4867
constructor() {
4968
super();
69+
this.state = 'INIT';
70+
this.rounds = 0;
71+
this.clicksInThisRound = 0;
72+
this.firstClickMs = 0;
5073
this.onclick = (e) => {
51-
if (e.target === this.history.value) return;
52-
e.preventDefault();
53-
this.clickEvent.set();
74+
if (this.history.value && e.target === this.history.value) return;
75+
if (e.preventDefault) e.preventDefault();
76+
77+
if (this.state === 'CLICK') {
78+
let x = e.clientX ?? e.touches?.[0]?.clientX;
79+
let y = e.clientY ?? e.touches?.[0]?.clientY;
80+
if (x === undefined) {
81+
x = window.innerWidth / 2;
82+
y = window.innerHeight / 2;
83+
}
84+
const ms = Math.round(performance.now() - this.startTime);
85+
this.addCircle(x, y, ms);
86+
this.history.value.textContent += `${ms} `;
87+
this.clicksInThisRound++;
88+
if (this.clicksInThisRound === 1) {
89+
this.firstClickMs = ms;
90+
}
91+
this.clickEvent.set();
92+
} else {
93+
this.clickEvent.set();
94+
}
5495
};
5596
this.clickEvent = new webfx.AutoResetEvent();
5697
this.text = new webfx.Ref();
5798
this.history = new webfx.Ref();
99+
this.circleContainer = new webfx.Ref();
58100
this.routine();
59101
}
60102
createDom() {
@@ -71,31 +113,76 @@
71113
ref: this.history,
72114
tag: 'div.history'
73115
},
116+
{
117+
ref: this.circleContainer,
118+
tag: 'div',
119+
style: 'position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:hidden;'
120+
}
74121
],
75122
}
76123
}
77124
set(color, str) {
78125
this.dom.style.backgroundColor = color;
79126
this.text.value.textContent = str || '';
80127
}
128+
addCircle(x, y, ms) {
129+
const el = webfx.buildDOM({
130+
tag: 'div.circle',
131+
style: {
132+
left: x + 'px',
133+
top: y + 'px',
134+
},
135+
text: ms.toString(),
136+
});
137+
el.dataset.round = this.rounds;
138+
this.circleContainer.value.appendChild(el);
139+
}
140+
updateCircles() {
141+
if (!this.circleContainer.value) return;
142+
const circles = Array.from(this.circleContainer.value.children);
143+
for (const c of circles) {
144+
const age = this.rounds - parseInt(c.dataset.round);
145+
if (age >= 3) {
146+
c.remove();
147+
} else {
148+
c.style.opacity = (1 / age).toFixed(2);
149+
}
150+
}
151+
}
81152
async routine() {
82153
this.set(READY, "Click to start");
154+
this.state = 'READY';
83155
while (true) {
84156
await this.clickEvent.wait();
157+
85158
this.set(WAIT, "Wait for green...");
159+
this.state = 'WAIT';
160+
86161
const action = await Promise.race([
87-
new Promise(r => setTimeout(r, 1000 + Math.random() * 3000, "timer")),
162+
new Promise(r => setTimeout(r, 1000 + Math.random() * 5000, "timer")),
88163
this.clickEvent.wait(),
89164
]);
165+
90166
if (action == "timer") {
91167
this.set(CLICK, "CLICK NOW!");
92-
const startTime = Date.now();
168+
this.state = 'CLICK';
169+
this.startTime = performance.now();
170+
this.clicksInThisRound = 0;
171+
this.firstClickMs = 0;
172+
173+
// Wait for at least one click
93174
await this.clickEvent.wait();
94-
const ms = Date.now() - startTime;
95-
this.set(READY, `${ms} ms`);
96-
this.history.value.textContent += `${ms} `;
175+
this.set(READY, `${this.firstClickMs} ms`);
176+
177+
// Wait for multiplayer clicks
178+
await new Promise(r => setTimeout(r, 1000));
179+
180+
this.rounds++;
181+
this.updateCircles();
182+
this.state = 'READY';
97183
} else {
98184
this.set(READY, `Too early!`);
185+
this.state = 'READY';
99186
this.history.value.textContent += `(early!) `;
100187
}
101188
}

0 commit comments

Comments
 (0)