diff --git a/src/components/layout/AppShell/Aurora.tsx b/src/components/layout/AppShell/Aurora.tsx index 31e9578..415f7d5 100644 --- a/src/components/layout/AppShell/Aurora.tsx +++ b/src/components/layout/AppShell/Aurora.tsx @@ -1,9 +1,10 @@ import { useEffect, useRef } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { Renderer, Program, Mesh, Color, Triangle } from 'ogl'; import { brandingApi } from '@/api/branding'; +import { themeColorsApi } from '@/api/themeColors'; import { useTheme } from '@/hooks/useTheme'; -import { ThemeSettings, DEFAULT_THEME_COLORS } from '@/types/theme'; +import { DEFAULT_THEME_COLORS } from '@/types/theme'; const VERT = /* glsl */ `#version 300 es in vec2 position; @@ -132,8 +133,6 @@ export function Aurora() { const rendererRef = useRef(null); const programRef = useRef(null); - const queryClient = useQueryClient(); - // Fetch animation setting const { data: animationSetting } = useQuery({ queryKey: ['animation-enabled'], @@ -143,15 +142,19 @@ export function Aurora() { const isEnabled = animationSetting?.enabled ?? false; - // Get theme colors from cache (already fetched by ThemeColorsProvider) - const themeColors = - queryClient.getQueryData(['theme-colors']) || DEFAULT_THEME_COLORS; + // Subscribe reactively to theme-colors cache so Aurora re-renders on setQueryData + const { data: themeColors = DEFAULT_THEME_COLORS } = useQuery({ + queryKey: ['theme-colors'], + queryFn: themeColorsApi.getColors, + staleTime: 5 * 60 * 1000, + }); // Pick background and surface based on current theme const { isDark } = useTheme(); const background = isDark ? themeColors.darkBackground : themeColors.lightBackground; const surface = isDark ? themeColors.darkSurface : themeColors.lightSurface; + // Initialize WebGL context once (only depends on isEnabled) useEffect(() => { if (!isEnabled || !containerRef.current) return; @@ -235,7 +238,20 @@ export function Aurora() { rendererRef.current = null; programRef.current = null; }; - }, [isEnabled, themeColors.accent, background, surface]); + }, [isEnabled]); // eslint-disable-line react-hooks/exhaustive-deps + + // Update color uniforms reactively without recreating WebGL context + useEffect(() => { + if (!programRef.current) return; + const colorStops = generateColorStops(background, surface, themeColors.accent); + const colorStopsArray = colorStops + .map((hex) => { + const c = new Color(hex); + return [c.r, c.g, c.b]; + }) + .flat(); + programRef.current.uniforms.uColorStops.value = colorStopsArray; + }, [themeColors.accent, background, surface]); if (!isEnabled) { return null;