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.

Handle missing screenshots in debrief rendering

- Skip non-renderable screens and show targeted fallback messages
- Shrink fallback cards when no heatmap can be drawn
- Remove unused tracker mouse position field

+44 -14
+1 -1
index.css
··· 413 413 } 414 414 415 415 .screen-card-fallback { 416 - min-height: 320px; 416 + min-height: 140px; 417 417 display: grid; 418 418 place-items: center; 419 419 padding: 24px;
+43 -12
js/debriefRenderer.js
··· 85 85 return canvas; 86 86 } 87 87 88 + function getUsablePoints(screen) { 89 + const width = screen.screenshot.width || screen.document.width || 1200; 90 + const height = screen.screenshot.height || screen.document.height || 800; 91 + return screen.gazePoints 92 + .filter((point) => point.inIframe) 93 + .filter((point) => point.docX >= 0 && point.docX <= width && point.docY >= 0 && point.docY <= height); 94 + } 95 + 96 + function buildFallback(text) { 97 + const fallback = document.createElement('div'); 98 + fallback.className = 'screen-card-fallback'; 99 + fallback.textContent = text; 100 + return fallback; 101 + } 102 + 88 103 export class DebriefRenderer { 89 104 constructor({ galleryElement, labelElement }) { 90 105 this.galleryElement = galleryElement; ··· 99 114 return; 100 115 } 101 116 117 + const renderableScreens = screens.filter((screen) => { 118 + const hasScreenshot = screen.screenshot.status === 'ready' && screen.screenshot.dataUrl; 119 + const usablePoints = getUsablePoints(screen); 120 + return hasScreenshot || usablePoints.length > 0; 121 + }); 122 + 123 + if (!renderableScreens.length) { 124 + this.labelElement.textContent = 'No renderable screenshots or gaze results were produced for this session.'; 125 + return; 126 + } 127 + 102 128 const totalPoints = screens.reduce((sum, screen) => sum + screen.gazePoints.length, 0); 103 - this.labelElement.textContent = `${screens.length} screens captured · ${totalPoints} gaze points`; 129 + this.labelElement.textContent = `${renderableScreens.length} screens captured · ${totalPoints} gaze points`; 104 130 105 - for (const screen of screens) { 131 + for (const screen of renderableScreens) { 106 132 const card = document.createElement('article'); 107 133 card.className = 'screen-card'; 108 134 ··· 121 147 122 148 const canvasWrap = document.createElement('div'); 123 149 canvasWrap.className = 'screen-card-canvas-wrap'; 150 + const hasScreenshot = screen.screenshot.status === 'ready' && screen.screenshot.dataUrl; 151 + const usablePoints = getUsablePoints(screen); 124 152 125 - try { 126 - const canvas = await renderHeatmapCanvas(screen); 127 - canvasWrap.appendChild(canvas); 128 - } catch (error) { 129 - const fallback = document.createElement('div'); 130 - fallback.className = 'screen-card-fallback'; 131 - fallback.textContent = screen.screenshot.status === 'failed' 132 - ? 'Screenshot capture failed for this screen.' 133 - : `Unable to render screen: ${error.message}`; 134 - canvasWrap.appendChild(fallback); 153 + if (hasScreenshot) { 154 + try { 155 + const canvas = await renderHeatmapCanvas(screen); 156 + canvasWrap.appendChild(canvas); 157 + } catch (error) { 158 + canvasWrap.appendChild(buildFallback(`Unable to render screen: ${error.message}`)); 159 + } 160 + } else if (usablePoints.length > 0) { 161 + canvasWrap.appendChild(buildFallback('Screenshot capture failed for this screen.')); 162 + } else if (screen.gazePoints.length > 0) { 163 + canvasWrap.appendChild(buildFallback('No renderable heatmap data for this screen.')); 164 + } else { 165 + canvasWrap.appendChild(buildFallback('No gaze points were recorded for this screen.')); 135 166 } 136 167 137 168 card.appendChild(header);
-1
js/tracker.js
··· 81 81 this.lastMousePos = null; 82 82 this.lastMouseTime = null; 83 83 this.velocities = []; 84 - this.onMousePosition = null; 85 84 } 86 85 87 86 handleMouseMove(event) {