feat(themes): animated-background sliders (density / speed / opacity)

Port the boolab FX controls: localStorage-backed Density, Speed, and
Opacity sliders in the theme settings, shown when a canvas-background
theme is active (Density is matrix-rain-only). Speed is a multiplier over
each field's native base; values feed MatrixRain / NeonField live.
This commit is contained in:
2026-06-03 14:59:01 +00:00
parent 37e0428312
commit ef3b998826
3 changed files with 204 additions and 26 deletions

View File

@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useTheme } from '@/lib/theme';
import { useAnimBg } from '@/lib/anim';
import { useAnimBg, useAnimParams } from '@/lib/anim';
import { MatrixRain } from './MatrixRain';
import { NeonField } from './NeonField';
@@ -28,9 +28,14 @@ function useAnimGate(): boolean {
// Mounted once in AppShell. Manages:
// 1. The bc-anim-on class on <html> (gate for all theme animation CSS).
// 2. The per-theme canvas component (MatrixRain / NeonField / null).
// Native base speeds for each canvas; the user's `speed` slider is a multiplier.
const RAIN_BASE_SPEED = 0.7;
const FIELD_BASE_SPEED = 0.18;
export function ThemeFx() {
const { id } = useTheme();
const gateOn = useAnimGate();
const { density, speed, opacity } = useAnimParams();
// Sync bc-anim-on class. Effect runs whenever gateOn changes; cleanup
// removes the class so a stale gate never persists across unmount.
@@ -45,7 +50,18 @@ export function ThemeFx() {
};
}, [gateOn]);
if (id === 'boocode-classic') return <MatrixRain enabled={gateOn} />;
if (id === 'boocode-override') return <NeonField enabled={gateOn} />;
if (id === 'boocode-classic') {
return (
<MatrixRain
enabled={gateOn}
density={density}
speed={RAIN_BASE_SPEED * speed}
opacity={opacity}
/>
);
}
if (id === 'boocode-override') {
return <NeonField enabled={gateOn} speed={FIELD_BASE_SPEED * speed} opacity={opacity} />;
}
return null;
}