Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

fix: smoother canvas scroll + adjacent page peek previews

- Wheel events during animations now queue instead of being dropped,
enabling continuous fluid browsing through pages
- Wheel-initiated transitions use faster animation speed
- Static view shows ghost edges of prev/next cards peeking above/below
the current card (35% opacity, 24px) so users know there's more content

+49 -2
+49 -2
system/netlify/functions/sotce-net.mjs
··· 6489 6489 let dragDelta = 0; 6490 6490 let wasDragging = false; // Persists until click event, prevents tap-on-release 6491 6491 6492 + // Pending wheel direction — tracks scroll intent during animations 6493 + // so continuous scrolling isn't lost when a transition is playing 6494 + let pendingWheelDirection = 0; // -1, 0, or 1 6495 + 6492 6496 // Hover state for debug boxes 6493 6497 let hoverEar = false; 6494 6498 let hoverPageNum = false; ··· 7184 7188 } 7185 7189 } else { 7186 7190 // Static - show current page with text (fade in if just arrived) 7191 + // Also render adjacent page edges peeking from above/below 7192 + // to hint that there's more content to scroll through. 7193 + const peekAmount = 24; // px of adjacent card visible 7194 + const slideDistance = cardHeight + 40; 7195 + const peekOffset = slideDistance - peekAmount; 7196 + const peekAlpha = 0.35; 7197 + 7198 + // Previous page peek (above) 7199 + if (displayedPageIndex > 1) { 7200 + const prevData = pageCache.get(displayedPageIndex - 1) || null; 7201 + ctx.save(); 7202 + ctx.globalAlpha = peekAlpha; 7203 + renderPage(prevData, displayedPageIndex - 1, -peekOffset, true, 0); 7204 + ctx.restore(); 7205 + } 7206 + 7207 + // Next page peek (below) 7208 + if (displayedPageIndex < loadedFeedCount) { 7209 + const nextData = pageCache.get(displayedPageIndex + 1) || null; 7210 + ctx.save(); 7211 + ctx.globalAlpha = peekAlpha; 7212 + renderPage(nextData, displayedPageIndex + 1, peekOffset, true, 0); 7213 + ctx.restore(); 7214 + } 7215 + 7216 + // Current page (main, on top) 7187 7217 renderPage(pageData, displayedPageIndex, 0, false, textFadeIn); 7188 7218 } 7189 7219 ··· 7215 7245 updatePath("/page/" + pNum); 7216 7246 } 7217 7247 prefetchPages(currentPageIndex); 7248 + 7249 + // If user kept scrolling during the animation, continue 7250 + // to the next page immediately for fluid browsing. 7251 + if (pendingWheelDirection !== 0) { 7252 + const nextIdx = currentPageIndex + pendingWheelDirection; 7253 + pendingWheelDirection = 0; 7254 + if (nextIdx >= 1 && nextIdx <= loadedFeedCount) { 7255 + goToPage(nextIdx); 7256 + } 7257 + } 7218 7258 } 7219 7259 } 7220 7260 ··· 7275 7315 // Cancel any pending wheel scroll 7276 7316 isWheelScrolling = false; 7277 7317 wheelDelta = 0; 7318 + pendingWheelDirection = 0; 7278 7319 clearTimeout(wheelIdleTimer); 7279 7320 7280 7321 canvas.setPointerCapture(e.pointerId); ··· 7352 7393 let isWheelScrolling = false; 7353 7394 canvas.addEventListener("wheel", (e) => { 7354 7395 if (!document.body.contains(canvas)) return; 7355 - if (transitionDirection !== 0) return; 7356 7396 if (isFlipping || showingBack) return; 7357 7397 e.preventDefault(); 7398 + 7399 + // During animation, track scroll direction so we can 7400 + // continue to the next page when the transition finishes. 7401 + if (transitionDirection !== 0) { 7402 + pendingWheelDirection = e.deltaY > 0 ? 1 : -1; 7403 + return; 7404 + } 7358 7405 7359 7406 // Accumulate wheel delta into dragDelta (like pointer drag) 7360 7407 const sensitivity = 1.5; ··· 7397 7444 const nextIdx = wheelDelta > 0 ? displayedPageIndex + 1 : displayedPageIndex - 1; 7398 7445 if (nextIdx >= 1 && nextIdx <= loadedFeedCount) { 7399 7446 dragDelta = 0; 7400 - goToPage(nextIdx, currentProgress, true); 7447 + goToPage(nextIdx, currentProgress); 7401 7448 } 7402 7449 } 7403 7450