Commit graph

3 commits

Author SHA1 Message Date
John Lightner
c9967a17a0 Fix ShaderCanvas scroll-back rendering via canvas element replacement
Root cause: Chromium limits ~16 simultaneous WebGL contexts. When scrolling
through a feed of 20+ shader cards, older contexts get silently evicted.
Once a context is lost on a canvas element, getContext('webgl2') returns null
on that same element forever — even after loseContext()/restore cycles.

Solution: The ShaderCanvas component now renders a container div and creates
canvas elements imperatively. When re-entering viewport:
1. Check if existing GL context is still alive (isContextLost)
2. If alive: just restart the animation loop
3. If dead: remove the old canvas, create a fresh DOM element, get a new
   context, recompile, and start rendering

This means scrolling down creates new contexts and scrolling back up
replaces dead canvases with fresh ones. At any given time only ~9 visible
canvases hold active contexts — well within Chrome's limit.

Also: 200px rootMargin on IntersectionObserver pre-compiles shaders
before cards enter viewport for smoother scroll experience.
2026-03-24 22:28:36 -05:00
John Lightner
164dda4760 Fix shader rendering: visibility-aware WebGL contexts, fix 2 GLSL shaders
ShaderCanvas rewrite:
- IntersectionObserver-driven rendering: WebGL context only created when canvas
  enters viewport, released when it leaves. Prevents context starvation when
  20+ shaders are in the feed simultaneously.
- Graceful fallback UI when WebGL context unavailable (hexagon + 'scroll to load')
- Context loss/restore event handlers
- powerPreference: 'low-power' for feed thumbnails
- Pause animation loop when off-screen (saves GPU even with context alive)
- Separate resize observer (no devicePixelRatio scaling for feed — saves memory)

Fixed shaders:
- Pixel Art Dither: replaced mat4 dynamic indexing with unrolled Bayer lookup
  (some WebGL drivers reject mat4[int_var][int_var])
- Wave Interference 2D: replaced C-style array element assignment with
  individual vec2 variables (GLSL ES 300 compatibility)
2026-03-24 22:12:58 -05:00
John Lightner
c4b8c0fe38 Tracks B+C+D: Auth system, renderer, full frontend shell
Track B — Auth & User System (complete):
- User registration with bcrypt + Turnstile verification
- JWT access/refresh token flow with httpOnly cookie rotation
- Redis refresh token blocklist for logout
- User profile + settings update endpoints (username, email)
- API key generation with bcrypt hashing (ff_key_ prefix)
- BYOK key management with AES-256-GCM encryption at rest
- Free tier rate limiting (5 shaders/month)
- Tier-gated endpoints (Pro/Studio for BYOK, API keys, bounty posting)

Track C — Shader Submission & Renderer (complete):
- GLSL validator: entry point check, banned extensions, infinite loop detection,
  brace balancing, loop bound warnings, code length limits
- Puppeteer/headless Chromium renderer with Shadertoy-compatible uniform injection
  (iTime, iResolution, iMouse), WebGL2 with SwiftShader fallback
- Shader compilation error detection via page title signaling
- Thumbnail capture at t=1s, preview frame at t=duration
- Renderer client service for API→renderer HTTP communication
- Shader submission pipeline: validate GLSL → create record → enqueue render job
- Desire fulfillment linking on shader submit
- Re-validation and re-render on shader code update
- Fork endpoint copies code, tags, metadata, enqueues new render

Track D — Frontend Shell (complete):
- React 18 + Vite + TypeScript + Tailwind CSS + TanStack Query + Zustand
- Dark theme with custom fracta color palette and surface tones
- Responsive layout with sticky navbar, gradient branding
- Auth: Login + Register pages with JWT token management
- API client with automatic 401 refresh interceptor
- ShaderCanvas: Full WebGL2 renderer component with Shadertoy uniforms,
  mouse tracking, ResizeObserver, debounced recompilation, error callbacks
- GLSL Editor: Split pane (code textarea + live preview), 400ms debounced
  preview, metadata panel (description, tags, type), GLSL validation errors,
  shader publish flow, fork-from-existing support
- Feed: Infinite scroll with IntersectionObserver sentinel, dwell time tracking,
  skeleton loading states, empty state with CTA
- Explore: Search + tag filter + sort tabs (trending/new/top), grid layout
- ShaderDetail: Full-screen preview, vote controls, view source toggle, fork button
- Bounties: Desire queue list sorted by heat score, status badges, tip display
- BountyDetail: Single desire view with style hints, fulfill CTA
- Profile: User header with avatar initial, shader grid
- Settings: Account info, API key management (create/revoke/copy), subscription tiers
- Generate: AI generation UI stub with prompt input, style controls, example prompts

76 files, ~5,700 lines of application code.
2026-03-24 20:56:42 -05:00