fix: update Aurora colors reactively without recreating WebGL context

Split the monolithic useEffect into two: one for WebGL init (depends
only on isEnabled) and one for updating color uniforms (depends on
theme colors). Previously the entire WebGL context was torn down and
rebuilt on every color change, causing updates to not apply until
page refresh or navigation.
This commit is contained in:
c0mrade
2026-02-04 16:00:05 +03:00
parent 3a042473f0
commit 59a251cb8c

View File

@@ -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<Renderer | null>(null);
const programRef = useRef<Program | null>(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<ThemeSettings>(['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;