Capstone project. I'm ngl it's vibe-coded and it's only here so I can mess around with it
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

More UI improvements

+104 -77
+18 -13
.uxet-server.log
··· 1 - 127.0.0.1 - - [29/Mar/2026 14:21:51] "GET / HTTP/1.1" 200 - 2 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /index.css HTTP/1.1" 200 - 3 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/main.js HTTP/1.1" 200 - 4 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/session.js HTTP/1.1" 200 - 5 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/gazeTracker.js HTTP/1.1" 200 - 6 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/tracker.js HTTP/1.1" 200 - 7 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/calibration.js HTTP/1.1" 200 - 8 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/iframeBridge.js HTTP/1.1" 200 - 9 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/winConditions.js HTTP/1.1" 200 - 10 - 127.0.0.1 - - [29/Mar/2026 14:21:52] "GET /js/debriefRenderer.js HTTP/1.1" 200 - 11 - 127.0.0.1 - - [29/Mar/2026 14:21:53] code 404, message File not found 12 - 127.0.0.1 - - [29/Mar/2026 14:21:53] "GET /favicon.ico HTTP/1.1" 404 - 13 - 127.0.0.1 - - [29/Mar/2026 14:22:07] "GET /testable-apps/shop-app/index.html?theme=dark HTTP/1.1" 200 - 1 + ::ffff:127.0.0.1 - - [29/Mar/2026 14:50:29] "GET / HTTP/1.1" 304 - 2 + ::ffff:127.0.0.1 - - [29/Mar/2026 14:50:29] "GET /js/main.js HTTP/1.1" 304 - 3 + ::ffff:127.0.0.1 - - [29/Mar/2026 14:50:29] "GET /index.css HTTP/1.1" 304 - 4 + ::ffff:127.0.0.1 - - [29/Mar/2026 14:50:29] "GET /testable-apps/shop-app/index.html?theme=dark HTTP/1.1" 304 - 5 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:23] "GET / HTTP/1.1" 200 - 6 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:23] "GET /index.css HTTP/1.1" 304 - 7 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:23] "GET /js/main.js HTTP/1.1" 304 - 8 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:23] "GET /js/tracker.js HTTP/1.1" 304 - 9 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:23] "GET /js/gazeTracker.js HTTP/1.1" 304 - 10 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:23] "GET /testable-apps/shop-app/index.html?theme=dark HTTP/1.1" 304 - 11 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:24] "GET / HTTP/1.1" 304 - 12 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:03:24] "GET /testable-apps/shop-app/index.html?theme=dark HTTP/1.1" 304 - 13 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:04:46] "GET / HTTP/1.1" 304 - 14 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:04:46] "GET /testable-apps/shop-app/index.html?theme=dark HTTP/1.1" 304 - 15 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:07:41] "GET / HTTP/1.1" 200 - 16 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:07:41] "GET /index.css HTTP/1.1" 200 - 17 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:07:41] "GET /js/main.js HTTP/1.1" 200 - 18 + ::ffff:127.0.0.1 - - [29/Mar/2026 15:07:41] "GET /testable-apps/shop-app/index.html?theme=dark HTTP/1.1" 304 -
+50 -14
index.css
··· 164 164 min-height: 100vh; 165 165 padding: var(--space-5); 166 166 gap: var(--space-5); 167 + position: relative; 168 + z-index: 1; 167 169 } 168 170 169 171 #debrief-shell { 170 172 min-height: 100vh; 171 - padding: var(--space-6); 173 + padding: var(--space-4) var(--space-5) var(--space-6); 172 174 max-width: 1400px; 173 175 margin: 0 auto; 176 + position: relative; 174 177 } 175 178 176 179 #controls { ··· 180 183 display: flex; 181 184 flex-direction: column; 182 185 gap: var(--space-5); 186 + position: relative; 187 + z-index: 10; 183 188 } 184 189 185 190 #status-bar { ··· 209 214 .toolbar, 210 215 .control-row { 211 216 display: flex; 212 - align-items: flex-start; 217 + align-items: flex-end; 213 218 justify-content: space-between; 214 219 gap: var(--space-4); 215 220 flex-wrap: wrap; ··· 264 269 width: 100%; 265 270 } 266 271 272 + .global-theme-container { 273 + position: fixed; 274 + inset: 0; 275 + max-width: 1400px; 276 + margin: 0 auto; 277 + pointer-events: none; 278 + z-index: 90; 279 + } 280 + 281 + .global-theme-container .theme-toggle { 282 + pointer-events: auto; 283 + } 284 + 267 285 .theme-toggle { 286 + position: absolute; 287 + top: var(--space-5); 288 + right: var(--space-5); 268 289 display: inline-flex; 269 290 padding: 2px; 270 291 border: 1px solid var(--border); 271 292 border-radius: var(--radius-sm); 272 293 background: var(--surface-2); 294 + z-index: 50; 273 295 } 274 296 275 297 .theme-option { ··· 292 314 flex-direction: column; 293 315 gap: var(--space-3); 294 316 width: 100%; 317 + position: relative; 295 318 } 296 319 297 320 .debug-toggle { 298 321 align-self: flex-start; 299 322 background: transparent; 300 - border-color: transparent; 301 - color: var(--muted); 323 + border-color: var(--border); 324 + color: var(--text); 302 325 } 303 326 304 327 .debug-toggle:hover { 305 328 background: var(--surface-2); 306 - border-color: var(--border); 329 + border-color: var(--primary); 307 330 color: var(--text); 308 331 } 309 332 ··· 316 339 background: var(--surface-2); 317 340 border-radius: var(--radius-md); 318 341 border: 1px solid var(--border); 342 + position: absolute; 343 + top: calc(100% + var(--space-2)); 344 + left: 0; 345 + z-index: 20; 346 + box-shadow: var(--shadow-md); 319 347 } 320 348 321 349 .debug-checkbox { ··· 494 522 495 523 #debrief-screen { 496 524 display: grid; 497 - gap: var(--space-6); 525 + gap: var(--space-4); 498 526 } 499 527 500 528 .debrief-header { ··· 508 536 } 509 537 510 538 #stats-container { 511 - display: grid; 512 - grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); 513 - gap: var(--space-3); 539 + display: flex; 540 + flex-wrap: wrap; 541 + gap: var(--space-4); 542 + justify-content: space-between; 514 543 } 515 544 516 545 .stat-block { 517 - padding: var(--space-4); 518 - border: 1px solid var(--border); 519 - background: var(--surface-2); 520 - border-radius: var(--radius-sm); 521 - box-shadow: inset 0 1px 3px rgba(0,0,0,0.04); 546 + display: flex; 547 + flex-direction: column; 548 + gap: var(--space-1); 549 + padding: 0 var(--space-3); 550 + border-left: 2px solid var(--border); 551 + flex: 1; 552 + min-width: 100px; 553 + } 554 + 555 + .stat-block:first-child { 556 + border-left: none; 557 + padding-left: 0; 522 558 } 523 559 524 560 .stat-block span {
+34 -38
index.html
··· 15 15 16 16 <body> 17 17 <div id="app-container"> 18 + <div class="global-theme-container"> 19 + <div class="theme-toggle" role="group" aria-label="Theme selection"> 20 + <button id="theme-dark-btn" class="theme-option" type="button">Dark</button> 21 + <button id="theme-light-btn" class="theme-option" type="button">Light</button> 22 + </div> 23 + </div> 24 + 25 + <section id="debrief-shell" class="hidden"> 26 + <section id="debrief-screen"> 27 + <header class="debrief-header"> 28 + <div> 29 + <h2>Session Debrief</h2> 30 + <p id="screen-gallery-label">Heatmaps will appear here after a test completes.</p> 31 + </div> 32 + </header> 33 + 34 + <section class="overlay-card debrief-panel"> 35 + <div id="stats-container"> 36 + <div class="stat-block"><span>Time</span><strong id="debrief-time">00:00:00</strong></div> 37 + <div class="stat-block"><span>Clicks</span><strong id="debrief-clicks">0</strong></div> 38 + <div class="stat-block"><span>Keys</span><strong id="debrief-keys">0</strong></div> 39 + <div class="stat-block"><span>Mouse Distance</span><strong id="debrief-distance">0</strong></div> 40 + <div class="stat-block"><span>Scroll Events</span><strong id="debrief-scrolls">0</strong></div> 41 + <div class="stat-block"><span>Avg Velocity</span><strong id="debrief-velocity">0</strong></div> 42 + <div class="stat-block"><span>Gaze Points</span><strong id="debrief-gaze-points">0</strong></div> 43 + <div class="stat-block"><span>Fixations</span><strong id="debrief-fixations">0</strong></div> 44 + <div class="stat-block"><span>Avg Fixation</span><strong id="debrief-fixation-duration">0</strong></div> 45 + </div> 46 + </section> 47 + 48 + <div id="screen-gallery"></div> 49 + </section> 50 + </section> 51 + 18 52 <section id="setup-shell"> 19 53 <header id="controls"> 20 54 <div class="toolbar"> ··· 23 57 <p>Prepare a session, preload the app, and capture gaze data without changing the test flow.</p> 24 58 </div> 25 59 26 - <div class="toolbar-actions"> 27 - <div class="theme-toggle" role="group" aria-label="Theme selection"> 28 - <button id="theme-dark-btn" class="theme-option" type="button">Dark</button> 29 - <button id="theme-light-btn" class="theme-option" type="button">Light</button> 30 - </div> 31 - </div> 32 60 </div> 33 61 34 62 <div class="control-row"> ··· 130 158 <p class="start-note">Keep your head still, look directly at each target, then retry.</p> 131 159 <button id="retry-calibration-btn" type="button">Retry Calibration</button> 132 160 </div> 133 - </section> 134 - </section> 135 - 136 - <section id="debrief-shell" class="hidden"> 137 - <section id="debrief-screen"> 138 - <header class="debrief-header"> 139 - <div> 140 - <h2>Session Debrief</h2> 141 - <p id="screen-gallery-label">Heatmaps will appear here after a test completes.</p> 142 - </div> 143 - 144 - <div class="theme-toggle" role="group" aria-label="Theme selection"> 145 - <button id="debrief-theme-dark-btn" class="theme-option" type="button">Dark</button> 146 - <button id="debrief-theme-light-btn" class="theme-option" type="button">Light</button> 147 - </div> 148 - </header> 149 - 150 - <section class="overlay-card debrief-panel"> 151 - <div id="stats-container"> 152 - <div class="stat-block"><span>Time</span><strong id="debrief-time">00:00:00</strong></div> 153 - <div class="stat-block"><span>Clicks</span><strong id="debrief-clicks">0</strong></div> 154 - <div class="stat-block"><span>Keys</span><strong id="debrief-keys">0</strong></div> 155 - <div class="stat-block"><span>Mouse Distance</span><strong id="debrief-distance">0</strong></div> 156 - <div class="stat-block"><span>Scroll Events</span><strong id="debrief-scrolls">0</strong></div> 157 - <div class="stat-block"><span>Avg Velocity</span><strong id="debrief-velocity">0</strong></div> 158 - <div class="stat-block"><span>Gaze Points</span><strong id="debrief-gaze-points">0</strong></div> 159 - <div class="stat-block"><span>Fixations</span><strong id="debrief-fixations">0</strong></div> 160 - <div class="stat-block"><span>Avg Fixation</span><strong id="debrief-fixation-duration">0</strong></div> 161 - </div> 162 - </section> 163 - 164 - <div id="screen-gallery"></div> 165 161 </section> 166 162 </section> 167 163 </div>
+2 -12
js/main.js
··· 40 40 startCurtain: document.getElementById('start-curtain'), 41 41 themeDarkBtn: document.getElementById('theme-dark-btn'), 42 42 themeLightBtn: document.getElementById('theme-light-btn'), 43 - debriefThemeDarkBtn: document.getElementById('debrief-theme-dark-btn'), 44 - debriefThemeLightBtn: document.getElementById('debrief-theme-light-btn'), 45 43 46 44 debugToggleBtn: document.getElementById('debug-toggle-btn'), 47 45 debugPanel: document.getElementById('debug-panel'), ··· 145 143 this.elements.retryCalibrationBtn.addEventListener('click', () => this.retryCalibration()); 146 144 this.elements.themeDarkBtn.addEventListener('click', () => this.setTheme('dark')); 147 145 this.elements.themeLightBtn.addEventListener('click', () => this.setTheme('light')); 148 - this.elements.debriefThemeDarkBtn.addEventListener('click', () => this.setTheme('dark')); 149 - this.elements.debriefThemeLightBtn.addEventListener('click', () => this.setTheme('light')); 150 146 151 147 this.elements.debugToggleBtn.addEventListener('click', () => { 152 148 this.debugState.setupPanelOpen = !this.debugState.setupPanelOpen; ··· 538 534 this.theme = theme; 539 535 const darkActive = theme === 'dark'; 540 536 541 - [ 542 - this.elements.themeDarkBtn, 543 - this.elements.debriefThemeDarkBtn 544 - ].forEach((button) => button.classList.toggle('active', darkActive)); 545 - [ 546 - this.elements.themeLightBtn, 547 - this.elements.debriefThemeLightBtn 548 - ].forEach((button) => button.classList.toggle('active', !darkActive)); 537 + this.elements.themeDarkBtn.classList.toggle('active', darkActive); 538 + this.elements.themeLightBtn.classList.toggle('active', !darkActive); 549 539 } 550 540 551 541 setTheme(theme) {