feat: 4 new bg modes (pulse/stars/rain/rays), vivid orbs & aurora
Orbs: bigger radius, opacity 0.14+, 4th orb added. Aurora: 6 bands with opacity 0.22+, more movement. New: Пульс (expanding rings on beat), Звёзды (twinkling starfield), Дождь (falling streaks), Лучи (rotating sunburst rays). Settings page shows 9 bg options with static SVG previews. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,27 +7,20 @@ import { useThemeStore, ACCENT_PRESETS } from '@/store/themeStore'
|
||||
import { useBgStore, BG_PRESETS, type BgMode } from '@/store/bgStore'
|
||||
import Header from '@/components/Header'
|
||||
|
||||
// ── Preview SVGs ─────────────────────────────────────────────────────────────
|
||||
|
||||
function OrbsPreview() {
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68" preserveAspectRatio="xMidYMid slice">
|
||||
<defs>
|
||||
<radialGradient id="s-o1" cx="22%" cy="18%" r="55%">
|
||||
<stop offset="0%" stopColor="var(--accent)" stopOpacity="0.5"/>
|
||||
<stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="s-o2" cx="82%" cy="85%" r="50%">
|
||||
<stop offset="0%" stopColor="rgb(255,60,172)" stopOpacity="0.4"/>
|
||||
<stop offset="100%" stopColor="rgb(255,60,172)" stopOpacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="s-o3" cx="55%" cy="55%" r="35%">
|
||||
<stop offset="0%" stopColor="rgb(140,100,255)" stopOpacity="0.22"/>
|
||||
<stop offset="100%" stopColor="rgb(140,100,255)" stopOpacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="p-o1" cx="12%" cy="6%" r="60%"><stop offset="0%" stopColor="var(--accent)" stopOpacity="0.65"/><stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/></radialGradient>
|
||||
<radialGradient id="p-o2" cx="90%" cy="96%" r="55%"><stop offset="0%" stopColor="rgb(255,60,172)" stopOpacity="0.55"/><stop offset="100%" stopColor="rgb(255,60,172)" stopOpacity="0"/></radialGradient>
|
||||
<radialGradient id="p-o3" cx="50%" cy="50%" r="40%"><stop offset="0%" stopColor="rgb(140,100,255)" stopOpacity="0.35"/><stop offset="100%" stopColor="rgb(140,100,255)" stopOpacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
<ellipse cx="26" cy="12" rx="58" ry="58" fill="url(#s-o1)"/>
|
||||
<ellipse cx="98" cy="58" rx="48" ry="48" fill="url(#s-o2)"/>
|
||||
<ellipse cx="66" cy="37" rx="32" ry="32" fill="url(#s-o3)"/>
|
||||
<ellipse cx="14" cy="4" rx="72" ry="72" fill="url(#p-o1)"/>
|
||||
<ellipse cx="108" cy="65" rx="58" ry="58" fill="url(#p-o2)"/>
|
||||
<ellipse cx="60" cy="34" rx="36" ry="36" fill="url(#p-o3)"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -36,31 +29,22 @@ function WavesPreview() {
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68" preserveAspectRatio="xMidYMid slice">
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
<path d="M0 46 Q15 40 30 46 Q45 52 60 46 Q75 40 90 46 Q105 52 120 46 L120 68 L0 68Z"
|
||||
fill="var(--accent)" opacity="0.14"/>
|
||||
<path d="M0 54 Q15 48 30 54 Q45 60 60 54 Q75 48 90 54 Q105 60 120 54 L120 68 L0 68Z"
|
||||
fill="var(--accent)" opacity="0.2"/>
|
||||
<path d="M0 40 Q20 34 40 40 Q60 46 80 40 Q100 34 120 40 L120 68 L0 68Z"
|
||||
fill="rgb(255,60,172)" opacity="0.09"/>
|
||||
<path d="M0 60 Q20 56 40 60 Q60 64 80 60 Q100 56 120 60 L120 68 L0 68Z"
|
||||
fill="rgb(140,100,255)" opacity="0.12"/>
|
||||
<path d="M0 47 Q15 41 30 47 Q45 53 60 47 Q75 41 90 47 Q105 53 120 47 L120 68 L0 68Z" fill="var(--accent)" opacity="0.16"/>
|
||||
<path d="M0 55 Q15 49 30 55 Q45 61 60 55 Q75 49 90 55 Q105 61 120 55 L120 68 L0 68Z" fill="var(--accent)" opacity="0.22"/>
|
||||
<path d="M0 41 Q20 35 40 41 Q60 47 80 41 Q100 35 120 41 L120 68 L0 68Z" fill="rgb(255,60,172)" opacity="0.10"/>
|
||||
<path d="M0 61 Q20 57 40 61 Q60 65 80 61 Q100 57 120 61 L120 68 L0 68Z" fill="rgb(140,100,255)" opacity="0.14"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function ParticlesPreview() {
|
||||
const dots: [number, number][] = [[18,14],[52,10],[88,22],[32,38],[72,48],[14,54],[86,56],[50,28],[68,8],[30,20]]
|
||||
const lines: [number,number][] = [[0,1],[1,2],[0,3],[1,7],[3,5],[2,4],[4,6],[3,7],[7,8],[1,8],[9,0],[9,3]]
|
||||
const d: [number,number][] = [[18,14],[52,10],[88,22],[32,38],[72,48],[14,54],[86,56],[50,28],[68,8],[30,20]]
|
||||
const ln: [number,number][] = [[0,1],[1,2],[0,3],[1,7],[3,5],[2,4],[4,6],[3,7],[7,8],[1,8],[9,0],[9,3]]
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68">
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
{lines.map(([a, b], i) => (
|
||||
<line key={i} x1={dots[a][0]} y1={dots[a][1]} x2={dots[b][0]} y2={dots[b][1]}
|
||||
stroke="var(--accent)" strokeWidth="0.6" opacity="0.18"/>
|
||||
))}
|
||||
{dots.map(([x, y], i) => (
|
||||
<circle key={i} cx={x} cy={y} r={i % 3 === 0 ? 2 : 1.3} fill="var(--accent)" opacity={i % 2 === 0 ? 0.65 : 0.45}/>
|
||||
))}
|
||||
{ln.map(([a,b],i) => <line key={i} x1={d[a][0]} y1={d[a][1]} x2={d[b][0]} y2={d[b][1]} stroke="var(--accent)" strokeWidth="0.6" opacity="0.2"/>)}
|
||||
{d.map(([x,y],i) => <circle key={i} cx={x} cy={y} r={i%3===0?2:1.3} fill="var(--accent)" opacity={i%2===0?0.7:0.45}/>)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -69,24 +53,95 @@ function AuroraPreview() {
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68" preserveAspectRatio="xMidYMid slice">
|
||||
<defs>
|
||||
<radialGradient id="s-a1" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stopColor="var(--accent)" stopOpacity="0.38"/>
|
||||
<stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="s-a2" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stopColor="rgb(140,100,255)" stopOpacity="0.3"/>
|
||||
<stop offset="100%" stopColor="rgb(140,100,255)" stopOpacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="s-a3" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stopColor="rgb(255,60,172)" stopOpacity="0.25"/>
|
||||
<stop offset="100%" stopColor="rgb(255,60,172)" stopOpacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="p-a1" cx="50%" cy="50%" r="50%"><stop offset="0%" stopColor="var(--accent)" stopOpacity="0.55"/><stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/></radialGradient>
|
||||
<radialGradient id="p-a2" cx="50%" cy="50%" r="50%"><stop offset="0%" stopColor="rgb(140,100,255)" stopOpacity="0.45"/><stop offset="100%" stopColor="rgb(140,100,255)" stopOpacity="0"/></radialGradient>
|
||||
<radialGradient id="p-a3" cx="50%" cy="50%" r="50%"><stop offset="0%" stopColor="rgb(255,60,172)" stopOpacity="0.40"/><stop offset="100%" stopColor="rgb(255,60,172)" stopOpacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
<ellipse cx="18" cy="17" rx="66" ry="20" fill="url(#s-a1)"/>
|
||||
<ellipse cx="60" cy="10" rx="80" ry="16" fill="url(#s-a2)"/>
|
||||
<ellipse cx="96" cy="24" rx="55" ry="18" fill="url(#s-a3)"/>
|
||||
<ellipse cx="42" cy="38" rx="70" ry="14" fill="url(#s-a1)" opacity="0.5"/>
|
||||
<ellipse cx="10" cy="10" rx="80" ry="22" fill="url(#p-a1)"/>
|
||||
<ellipse cx="66" cy="6" rx="90" ry="16" fill="url(#p-a2)"/>
|
||||
<ellipse cx="106" cy="19" rx="66" ry="20" fill="url(#p-a3)"/>
|
||||
<ellipse cx="34" cy="32" rx="85" ry="15" fill="url(#p-a1)" opacity="0.5"/>
|
||||
<ellipse cx="86" cy="44" rx="60" ry="16" fill="url(#p-a2)" opacity="0.45"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function PulsePreview() {
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68">
|
||||
<defs>
|
||||
<radialGradient id="p-pg" cx="50%" cy="50%" r="50%"><stop offset="0%" stopColor="var(--accent)" stopOpacity="0.35"/><stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
<circle cx="60" cy="34" r="12" fill="url(#p-pg)"/>
|
||||
<circle cx="60" cy="34" r="9" fill="none" stroke="var(--accent)" strokeWidth="1.8" opacity="0.75"/>
|
||||
<circle cx="60" cy="34" r="20" fill="none" stroke="var(--accent)" strokeWidth="1.2" opacity="0.5"/>
|
||||
<circle cx="60" cy="34" r="30" fill="none" stroke="var(--accent)" strokeWidth="0.9" opacity="0.32"/>
|
||||
<circle cx="60" cy="34" r="42" fill="none" stroke="var(--accent)" strokeWidth="0.6" opacity="0.18"/>
|
||||
<circle cx="60" cy="34" r="55" fill="none" stroke="var(--accent)" strokeWidth="0.4" opacity="0.1"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function StarsPreview() {
|
||||
const stars: [number,number,number][] = [
|
||||
[12,8,1.4],[34,5,0.9],[58,12,1.1],[80,4,1.5],[102,9,0.8],[18,22,1.0],[45,18,1.3],[72,20,0.9],[96,25,1.2],
|
||||
[8,38,0.8],[28,42,1.1],[55,35,1.4],[78,40,0.9],[108,36,1.0],[22,56,1.2],[50,58,0.8],[75,54,1.3],[100,60,1.0],
|
||||
[40,28,0.7],[88,14,1.1],[15,48,0.9],[64,48,0.8]
|
||||
]
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68">
|
||||
<defs>
|
||||
<radialGradient id="p-neb" cx="35%" cy="45%" r="50%"><stop offset="0%" stopColor="var(--accent)" stopOpacity="0.12"/><stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
<rect width="120" height="68" fill="url(#p-neb)"/>
|
||||
{stars.map(([x,y,r],i) => (
|
||||
<circle key={i} cx={x} cy={y} r={r} fill="var(--accent)" opacity={0.4 + (i % 5) * 0.12}/>
|
||||
))}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function RainPreview() {
|
||||
const drops: [number,number,number][] = [
|
||||
[10,8,20],[25,0,28],[40,15,22],[55,5,25],[70,10,18],[85,2,30],[100,12,24],[112,6,20],
|
||||
[18,35,22],[33,28,26],[48,40,19],[63,30,24],[78,38,21],[93,25,28],[108,34,20],
|
||||
]
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68">
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
{drops.map(([x,y,len],i) => (
|
||||
<g key={i}>
|
||||
<line x1={x} y1={y} x2={x} y2={y+len} stroke="var(--accent)" strokeWidth="1.5" opacity={0.15 + (i%4)*0.08}
|
||||
style={{background: `linear-gradient(to bottom, transparent, var(--accent))`}}/>
|
||||
<circle cx={x} cy={y+len} r="1.5" fill="var(--accent)" opacity={0.5 + (i%3)*0.15}/>
|
||||
</g>
|
||||
))}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function RaysPreview() {
|
||||
const rays = Array.from({length: 9}, (_,i) => (i/9)*360)
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68" preserveAspectRatio="xMidYMid slice">
|
||||
<defs>
|
||||
<radialGradient id="p-rg" cx="50%" cy="60%" r="55%"><stop offset="0%" stopColor="var(--accent)" stopOpacity="0.5"/><stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
{rays.map((deg, i) => {
|
||||
const rad = (deg * Math.PI) / 180
|
||||
const x2 = 60 + Math.cos(rad) * 90
|
||||
const y2 = 41 + Math.sin(rad) * 90
|
||||
return (
|
||||
<line key={i} x1="60" y1="41" x2={x2} y2={y2}
|
||||
stroke="var(--accent)" strokeWidth={i%2===0?2.5:1.5} opacity={i%2===0?0.18:0.10}/>
|
||||
)
|
||||
})}
|
||||
<circle cx="60" cy="41" r="14" fill="url(#p-rg)"/>
|
||||
<circle cx="60" cy="41" r="3" fill="var(--accent)" opacity="0.7"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -95,8 +150,8 @@ function NonePreview() {
|
||||
return (
|
||||
<svg width="100%" height="100%" viewBox="0 0 120 68">
|
||||
<rect width="120" height="68" fill="#0a0a0f"/>
|
||||
<line x1="50" y1="34" x2="70" y2="34" stroke="#333" strokeWidth="1.5" strokeLinecap="round"/>
|
||||
<line x1="60" y1="24" x2="60" y2="44" stroke="#333" strokeWidth="1.5" strokeLinecap="round"/>
|
||||
<line x1="48" y1="34" x2="72" y2="34" stroke="#2a2a35" strokeWidth="1.5" strokeLinecap="round"/>
|
||||
<line x1="60" y1="22" x2="60" y2="46" stroke="#2a2a35" strokeWidth="1.5" strokeLinecap="round"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -106,9 +161,15 @@ const BG_PREVIEWS: Record<BgMode, React.ReactNode> = {
|
||||
waves: <WavesPreview />,
|
||||
particles: <ParticlesPreview />,
|
||||
aurora: <AuroraPreview />,
|
||||
pulse: <PulsePreview />,
|
||||
stars: <StarsPreview />,
|
||||
rain: <RainPreview />,
|
||||
rays: <RaysPreview />,
|
||||
none: <NonePreview />,
|
||||
}
|
||||
|
||||
// ── Page ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { user } = useAuthStore()
|
||||
const { accentIdx, setAccent } = useThemeStore()
|
||||
@@ -128,14 +189,14 @@ export default function SettingsPage() {
|
||||
<div className="animate-fadeUp">
|
||||
<h2 className="font-display text-xl font-extrabold tracking-tight text-app-text mb-5">Настройки</h2>
|
||||
|
||||
{/* Appearance */}
|
||||
<section className="bg-surface border border-white/[0.07] rounded-app p-5 mb-3">
|
||||
<p className="text-[11px] font-display font-semibold tracking-[1.2px] uppercase text-muted mb-4">
|
||||
Внешний вид
|
||||
</p>
|
||||
|
||||
{/* Accent color */}
|
||||
<p className="text-[12px] text-muted mb-2.5">Акцентный цвет</p>
|
||||
<div className="flex flex-wrap gap-2 mb-5">
|
||||
<div className="flex flex-wrap gap-2 mb-6">
|
||||
{ACCENT_PRESETS.map((preset, i) => (
|
||||
<button
|
||||
key={i}
|
||||
@@ -146,15 +207,14 @@ export default function SettingsPage() {
|
||||
: { background: 'rgba(255,255,255,0.03)', color: '#666', borderColor: 'rgba(255,255,255,0.07)' }
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="w-3 h-3 rounded-full shrink-0"
|
||||
style={{ background: preset.accent, boxShadow: accentIdx === i ? `0 0 7px ${preset.accent}90` : 'none' }}
|
||||
/>
|
||||
<span className="w-3 h-3 rounded-full shrink-0"
|
||||
style={{ background: preset.accent, boxShadow: accentIdx === i ? `0 0 7px ${preset.accent}90` : 'none' }}/>
|
||||
{preset.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Live background */}
|
||||
<p className="text-[12px] text-muted mb-2.5">Живой фон</p>
|
||||
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
|
||||
{BG_PRESETS.map((preset) => {
|
||||
|
||||
@@ -5,6 +5,9 @@ import { audioState } from '@/lib/audioState'
|
||||
import { useBgStore } from '@/store/bgStore'
|
||||
|
||||
type Pt = { x: number; y: number; vx: number; vy: number; r: number; a: number }
|
||||
type Ring = { r: number; alpha: number; speed: number }
|
||||
type Star = { x: number; y: number; r: number; ba: number; ph: number; sp: number }
|
||||
type Drop = { x: number; y: number; speed: number; len: number; alpha: number }
|
||||
|
||||
export default function AudioBackground() {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||
@@ -23,10 +26,7 @@ export default function AudioBackground() {
|
||||
let smoothMid = 0
|
||||
let dataBuf: Uint8Array<ArrayBuffer> | null = null
|
||||
|
||||
const resize = () => {
|
||||
canvas.width = window.innerWidth
|
||||
canvas.height = window.innerHeight
|
||||
}
|
||||
const resize = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight }
|
||||
resize()
|
||||
window.addEventListener('resize', resize)
|
||||
|
||||
@@ -47,69 +47,66 @@ export default function AudioBackground() {
|
||||
smoothMid += (rM - smoothMid) * 0.07
|
||||
}
|
||||
|
||||
const acRgb = () =>
|
||||
document.documentElement.style.getPropertyValue('--accent-rgb') || '200,255,0'
|
||||
const ar = () => document.documentElement.style.getPropertyValue('--accent-rgb') || '200,255,0'
|
||||
|
||||
// ── ORBS ─────────────────────────────────────────────────────────────────
|
||||
// ── ORBS (vivid) ──────────────────────────────────────────────────────────
|
||||
const drawOrbs = () => {
|
||||
const W = canvas.width, H = canvas.height
|
||||
const ar = acRgb()
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
const t = Date.now() / 4500
|
||||
const b = Math.sin(t) * 0.03 + Math.cos(t * 0.7) * 0.015
|
||||
const diag = Math.hypot(W, H), base = diag * 0.55
|
||||
const br = Math.sin(t) * 0.05 + Math.cos(t * 0.7) * 0.025
|
||||
const diag = Math.hypot(W, H), base = diag * 0.68
|
||||
|
||||
ctx.clearRect(0, 0, W, H)
|
||||
ctx.fillStyle = '#0a0a0f'
|
||||
ctx.fillRect(0, 0, W, H)
|
||||
|
||||
const r1 = base * (0.75 + smoothBass * 0.55 + b)
|
||||
const a1 = 0.055 + smoothBass * 0.07
|
||||
const g1 = ctx.createRadialGradient(W * 0.18, H * 0.08, 0, W * 0.18, H * 0.08, r1)
|
||||
g1.addColorStop(0, `rgba(${ar},${a1})`); g1.addColorStop(0.45, `rgba(${ar},${a1 * 0.28})`); g1.addColorStop(1, `rgba(${ar},0)`)
|
||||
// Top-left — accent, bass-driven
|
||||
const r1 = base * (0.82 + smoothBass * 0.7 + br)
|
||||
const a1 = 0.14 + smoothBass * 0.18
|
||||
const g1 = ctx.createRadialGradient(W * 0.10, H * 0.04, 0, W * 0.10, H * 0.04, r1)
|
||||
g1.addColorStop(0, `rgba(${a},${a1})`); g1.addColorStop(0.38, `rgba(${a},${a1 * 0.4})`); g1.addColorStop(1, `rgba(${a},0)`)
|
||||
ctx.fillStyle = g1; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
const r2 = base * (0.65 + smoothMid * 0.45 - b * 0.6)
|
||||
const a2 = 0.045 + smoothMid * 0.055
|
||||
const g2 = ctx.createRadialGradient(W * 0.82, H * 0.92, 0, W * 0.82, H * 0.92, r2)
|
||||
g2.addColorStop(0, `rgba(255,60,172,${a2})`); g2.addColorStop(0.45, `rgba(255,60,172,${a2 * 0.28})`); g2.addColorStop(1, 'rgba(255,60,172,0)')
|
||||
// Bottom-right — pink, mid-driven
|
||||
const r2 = base * (0.75 + smoothMid * 0.60 - br * 0.6)
|
||||
const a2 = 0.13 + smoothMid * 0.16
|
||||
const g2 = ctx.createRadialGradient(W * 0.90, H * 0.96, 0, W * 0.90, H * 0.96, r2)
|
||||
g2.addColorStop(0, `rgba(255,60,172,${a2})`); g2.addColorStop(0.38, `rgba(255,60,172,${a2 * 0.4})`); g2.addColorStop(1, 'rgba(255,60,172,0)')
|
||||
ctx.fillStyle = g2; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
// Center — purple
|
||||
const c = smoothBass * 0.55 + smoothMid * 0.45
|
||||
if (c > 0.005) {
|
||||
const r3 = base * (0.38 + c * 0.32)
|
||||
const g3 = ctx.createRadialGradient(W * 0.5, H * 0.52, 0, W * 0.5, H * 0.52, r3)
|
||||
g3.addColorStop(0, `rgba(140,100,255,${c * 0.035})`); g3.addColorStop(1, 'rgba(140,100,255,0)')
|
||||
const r3 = base * (0.48 + c * 0.45)
|
||||
const a3 = 0.06 + c * 0.10
|
||||
const g3 = ctx.createRadialGradient(W * 0.5, H * 0.5, 0, W * 0.5, H * 0.5, r3)
|
||||
g3.addColorStop(0, `rgba(140,100,255,${a3})`); g3.addColorStop(1, 'rgba(140,100,255,0)')
|
||||
ctx.fillStyle = g3; ctx.fillRect(0, 0, W, H)
|
||||
}
|
||||
|
||||
// Bottom-left — accent, extra depth
|
||||
const r4 = base * (0.58 + smoothBass * 0.5 + br * 0.5)
|
||||
const a4 = 0.08 + smoothBass * 0.10
|
||||
const g4 = ctx.createRadialGradient(W * 0.04, H * 0.94, 0, W * 0.04, H * 0.94, r4)
|
||||
g4.addColorStop(0, `rgba(${a},${a4})`); g4.addColorStop(0.5, `rgba(${a},${a4 * 0.2})`); g4.addColorStop(1, `rgba(${a},0)`)
|
||||
ctx.fillStyle = g4; ctx.fillRect(0, 0, W, H)
|
||||
}
|
||||
|
||||
// ── WAVES ─────────────────────────────────────────────────────────────────
|
||||
const drawWaves = () => {
|
||||
const W = canvas.width, H = canvas.height
|
||||
const ar = acRgb()
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
const t = Date.now() / 1000
|
||||
|
||||
ctx.clearRect(0, 0, W, H)
|
||||
ctx.fillStyle = '#0a0a0f'
|
||||
ctx.fillRect(0, 0, W, H)
|
||||
|
||||
ctx.clearRect(0, 0, W, H); ctx.fillStyle = '#0a0a0f'; ctx.fillRect(0, 0, W, H)
|
||||
const layers = [
|
||||
{ y: 0.70, amp: 20 + smoothBass * 60, freq: 0.007, ph: t * 0.35, al: 0.12, c: `rgba(${ar},` },
|
||||
{ y: 0.70, amp: 20 + smoothBass * 60, freq: 0.007, ph: t * 0.35, al: 0.12, c: `rgba(${a},` },
|
||||
{ y: 0.76, amp: 16 + smoothMid * 45, freq: 0.011, ph: -t * 0.5, al: 0.09, c: 'rgba(255,60,172,' },
|
||||
{ y: 0.81, amp: 24 + smoothBass * 75, freq: 0.005, ph: t * 0.28, al: 0.14, c: `rgba(${ar},` },
|
||||
{ y: 0.81, amp: 24 + smoothBass * 75, freq: 0.005, ph: t * 0.28, al: 0.14, c: `rgba(${a},` },
|
||||
{ y: 0.87, amp: 12 + smoothMid * 35, freq: 0.013, ph: -t * 0.62, al: 0.08, c: 'rgba(140,100,255,' },
|
||||
{ y: 0.93, amp: 30 + smoothBass * 90, freq: 0.004, ph: t * 0.18, al: 0.18, c: `rgba(${ar},` },
|
||||
{ y: 0.93, amp: 30 + smoothBass * 90, freq: 0.004, ph: t * 0.18, al: 0.18, c: `rgba(${a},` },
|
||||
]
|
||||
|
||||
for (const l of layers) {
|
||||
const baseY = H * l.y
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(-2, baseY)
|
||||
for (let x = 0; x <= W + 3; x += 3) {
|
||||
ctx.lineTo(x, baseY
|
||||
+ Math.sin(x * l.freq + l.ph) * l.amp
|
||||
+ Math.sin(x * l.freq * 2.4 + l.ph * 1.6) * l.amp * 0.25)
|
||||
}
|
||||
ctx.beginPath(); ctx.moveTo(-2, baseY)
|
||||
for (let x = 0; x <= W + 3; x += 3)
|
||||
ctx.lineTo(x, baseY + Math.sin(x * l.freq + l.ph) * l.amp + Math.sin(x * l.freq * 2.4 + l.ph * 1.6) * l.amp * 0.25)
|
||||
ctx.lineTo(W + 2, H + 2); ctx.lineTo(-2, H + 2); ctx.closePath()
|
||||
const g = ctx.createLinearGradient(0, baseY - l.amp * 1.5, 0, H)
|
||||
g.addColorStop(0, `${l.c}${l.al})`); g.addColorStop(1, `${l.c}0)`)
|
||||
@@ -120,111 +117,210 @@ export default function AudioBackground() {
|
||||
// ── PARTICLES ─────────────────────────────────────────────────────────────
|
||||
const PTS: Pt[] = Array.from({ length: 55 }, () => ({
|
||||
x: Math.random(), y: Math.random(),
|
||||
vx: (Math.random() - 0.5) * 0.00025,
|
||||
vy: (Math.random() - 0.5) * 0.00025,
|
||||
r: Math.random() * 1.5 + 0.6,
|
||||
a: Math.random() * 0.35 + 0.1,
|
||||
vx: (Math.random() - 0.5) * 0.00025, vy: (Math.random() - 0.5) * 0.00025,
|
||||
r: Math.random() * 1.5 + 0.6, a: Math.random() * 0.35 + 0.1,
|
||||
}))
|
||||
|
||||
const drawParticles = () => {
|
||||
const W = canvas.width, H = canvas.height
|
||||
const ar = acRgb()
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
ctx.fillStyle = 'rgba(10,10,15,0.2)'; ctx.fillRect(0, 0, W, H)
|
||||
const spd = 1 + smoothBass * 3
|
||||
|
||||
ctx.fillStyle = 'rgba(10,10,15,0.2)'
|
||||
ctx.fillRect(0, 0, W, H)
|
||||
|
||||
for (const p of PTS) {
|
||||
p.x += p.vx * spd; p.y += p.vy * spd
|
||||
if (p.x < 0) p.x += 1; if (p.x > 1) p.x -= 1
|
||||
if (p.y < 0) p.y += 1; if (p.y > 1) p.y -= 1
|
||||
if (smoothBass > 0.35 && Math.random() < 0.07) {
|
||||
p.vx += (Math.random() - 0.5) * 0.0006
|
||||
p.vy += (Math.random() - 0.5) * 0.0006
|
||||
p.vx += (Math.random() - 0.5) * 0.0006; p.vy += (Math.random() - 0.5) * 0.0006
|
||||
const mv = 0.0012
|
||||
p.vx = Math.max(-mv, Math.min(mv, p.vx))
|
||||
p.vy = Math.max(-mv, Math.min(mv, p.vy))
|
||||
p.vx = Math.max(-mv, Math.min(mv, p.vx)); p.vy = Math.max(-mv, Math.min(mv, p.vy))
|
||||
}
|
||||
ctx.beginPath()
|
||||
ctx.arc(p.x * W, p.y * H, p.r * (1 + smoothBass * 1.2), 0, Math.PI * 2)
|
||||
ctx.fillStyle = `rgba(${ar},${p.a * (0.7 + smoothMid * 0.3)})`
|
||||
ctx.fill()
|
||||
ctx.beginPath(); ctx.arc(p.x * W, p.y * H, p.r * (1 + smoothBass * 1.2), 0, Math.PI * 2)
|
||||
ctx.fillStyle = `rgba(${a},${p.a * (0.7 + smoothMid * 0.3)})`; ctx.fill()
|
||||
}
|
||||
|
||||
const maxD = Math.min(W, H) * 0.12
|
||||
ctx.lineWidth = 0.5
|
||||
for (let i = 0; i < PTS.length; i++) {
|
||||
for (let i = 0; i < PTS.length; i++)
|
||||
for (let j = i + 1; j < PTS.length; j++) {
|
||||
const dx = (PTS[i].x - PTS[j].x) * W
|
||||
const dy = (PTS[i].y - PTS[j].y) * H
|
||||
const dx = (PTS[i].x - PTS[j].x) * W, dy = (PTS[i].y - PTS[j].y) * H
|
||||
const d = Math.sqrt(dx * dx + dy * dy)
|
||||
if (d < maxD) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(PTS[i].x * W, PTS[i].y * H)
|
||||
ctx.lineTo(PTS[j].x * W, PTS[j].y * H)
|
||||
ctx.strokeStyle = `rgba(${ar},${(1 - d / maxD) * 0.07 * (1 + smoothMid)})`
|
||||
ctx.stroke()
|
||||
}
|
||||
ctx.beginPath(); ctx.moveTo(PTS[i].x * W, PTS[i].y * H); ctx.lineTo(PTS[j].x * W, PTS[j].y * H)
|
||||
ctx.strokeStyle = `rgba(${a},${(1 - d / maxD) * 0.07 * (1 + smoothMid)})`; ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── AURORA ────────────────────────────────────────────────────────────────
|
||||
// ── AURORA (vivid) ────────────────────────────────────────────────────────
|
||||
const drawAurora = () => {
|
||||
const W = canvas.width, H = canvas.height
|
||||
const ar = acRgb()
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
const t = Date.now() / 3000
|
||||
|
||||
ctx.clearRect(0, 0, W, H)
|
||||
ctx.fillStyle = '#0a0a0f'
|
||||
ctx.fillRect(0, 0, W, H)
|
||||
ctx.clearRect(0, 0, W, H); ctx.fillStyle = '#0a0a0f'; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
const bands = [
|
||||
{ cx: 0.15, cy: 0.25, w: 0.55, h: 0.30, phase: t * 0.6, al: 0.08 + smoothBass * 0.06, c: ar },
|
||||
{ cx: 0.50, cy: 0.15, w: 0.70, h: 0.22, phase: -t * 0.4, al: 0.06 + smoothMid * 0.05, c: '140,100,255' },
|
||||
{ cx: 0.80, cy: 0.35, w: 0.50, h: 0.28, phase: t * 0.5, al: 0.07 + smoothBass * 0.04, c: '255,60,172' },
|
||||
{ cx: 0.35, cy: 0.55, w: 0.60, h: 0.20, phase: -t * 0.7, al: 0.05 + smoothMid * 0.04, c: ar },
|
||||
{ cx: 0.08, cy: 0.15, w: 0.75, h: 0.30, ph: t * 0.8, al: 0.22 + smoothBass * 0.18, c: a },
|
||||
{ cx: 0.55, cy: 0.08, w: 0.90, h: 0.22, ph: -t * 0.6, al: 0.18 + smoothMid * 0.15, c: '140,100,255' },
|
||||
{ cx: 0.88, cy: 0.28, w: 0.65, h: 0.28, ph: t * 0.7, al: 0.20 + smoothBass * 0.14, c: '255,60,172' },
|
||||
{ cx: 0.28, cy: 0.48, w: 0.80, h: 0.20, ph: -t * 0.9, al: 0.14 + smoothMid * 0.12, c: a },
|
||||
{ cx: 0.72, cy: 0.62, w: 0.60, h: 0.24, ph: t * 0.55, al: 0.12 + smoothBass * 0.10, c: '140,100,255' },
|
||||
{ cx: 0.18, cy: 0.78, w: 0.70, h: 0.22, ph: -t * 0.7, al: 0.10 + smoothMid * 0.08, c: '255,60,172' },
|
||||
]
|
||||
|
||||
for (const band of bands) {
|
||||
const cx = band.cx * W
|
||||
const cy = (band.cy + Math.sin(band.phase) * 0.06) * H
|
||||
const cy = (band.cy + Math.sin(band.ph) * 0.10) * H
|
||||
const rw = band.w * W
|
||||
const rh = band.h * H * (1 + smoothBass * 0.3)
|
||||
|
||||
ctx.save()
|
||||
ctx.translate(cx, cy)
|
||||
ctx.scale(1, rh / rw)
|
||||
|
||||
const rh = band.h * H * (1 + smoothBass * 0.45)
|
||||
ctx.save(); ctx.translate(cx, cy); ctx.scale(1, rh / rw)
|
||||
const g = ctx.createRadialGradient(0, 0, 0, 0, 0, rw)
|
||||
g.addColorStop(0, `rgba(${band.c},${band.al})`)
|
||||
g.addColorStop(0.35, `rgba(${band.c},${band.al * 0.5})`)
|
||||
g.addColorStop(1, `rgba(${band.c},0)`)
|
||||
ctx.fillStyle = g
|
||||
ctx.beginPath()
|
||||
ctx.arc(0, 0, rw, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
ctx.restore()
|
||||
g.addColorStop(0, `rgba(${band.c},${band.al})`); g.addColorStop(0.4, `rgba(${band.c},${band.al * 0.5})`); g.addColorStop(1, `rgba(${band.c},0)`)
|
||||
ctx.fillStyle = g; ctx.beginPath(); ctx.arc(0, 0, rw, 0, Math.PI * 2); ctx.fill(); ctx.restore()
|
||||
}
|
||||
}
|
||||
|
||||
// ── PULSE ─────────────────────────────────────────────────────────────────
|
||||
const RINGS: Ring[] = []
|
||||
let prevBass = 0
|
||||
|
||||
const drawPulse = () => {
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
const cx = W * 0.5, cy = H * 0.5
|
||||
const maxR = Math.hypot(W, H) * 0.8
|
||||
|
||||
ctx.fillStyle = 'rgba(10,10,15,0.14)'; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
if (smoothBass > prevBass + 0.07 && smoothBass > 0.18)
|
||||
RINGS.push({ r: 12, alpha: 0.6 + smoothBass * 0.35, speed: 3 + smoothBass * 8 })
|
||||
prevBass = smoothBass
|
||||
|
||||
if (Math.random() < 0.014)
|
||||
RINGS.push({ r: 5, alpha: 0.16, speed: 1.4 })
|
||||
|
||||
for (let i = RINGS.length - 1; i >= 0; i--) {
|
||||
const ring = RINGS[i]
|
||||
ring.r += ring.speed; ring.alpha -= 0.006
|
||||
if (ring.alpha <= 0 || ring.r > maxR) { RINGS.splice(i, 1); continue }
|
||||
ctx.beginPath(); ctx.arc(cx, cy, ring.r, 0, Math.PI * 2)
|
||||
ctx.strokeStyle = `rgba(${a},${ring.alpha})`
|
||||
ctx.lineWidth = 1.5 + ring.alpha * 3; ctx.stroke()
|
||||
if (ring.r > 30 && ring.alpha > 0.12) {
|
||||
ctx.beginPath(); ctx.arc(cx, cy, ring.r * 0.82, 0, Math.PI * 2)
|
||||
ctx.strokeStyle = `rgba(255,60,172,${ring.alpha * 0.45})`
|
||||
ctx.lineWidth = 0.8; ctx.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, 90 + smoothBass * 130)
|
||||
g.addColorStop(0, `rgba(${a},${0.06 + smoothBass * 0.12})`); g.addColorStop(1, `rgba(${a},0)`)
|
||||
ctx.fillStyle = g; ctx.fillRect(0, 0, W, H)
|
||||
}
|
||||
|
||||
// ── STARS ─────────────────────────────────────────────────────────────────
|
||||
const STARS: Star[] = Array.from({ length: 180 }, () => ({
|
||||
x: Math.random(), y: Math.random(),
|
||||
r: Math.random() * 1.4 + 0.3,
|
||||
ba: Math.random() * 0.55 + 0.15,
|
||||
ph: Math.random() * Math.PI * 2,
|
||||
sp: Math.random() * 1.5 + 0.4,
|
||||
}))
|
||||
|
||||
const drawStars = () => {
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
const t = Date.now() / 1000
|
||||
ctx.clearRect(0, 0, W, H); ctx.fillStyle = '#0a0a0f'; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
const n1 = ctx.createRadialGradient(W * 0.30, H * 0.35, 0, W * 0.30, H * 0.35, W * 0.55)
|
||||
n1.addColorStop(0, `rgba(${a},${0.05 + smoothMid * 0.05})`); n1.addColorStop(1, `rgba(${a},0)`)
|
||||
ctx.fillStyle = n1; ctx.fillRect(0, 0, W, H)
|
||||
const n2 = ctx.createRadialGradient(W * 0.72, H * 0.62, 0, W * 0.72, H * 0.62, W * 0.45)
|
||||
n2.addColorStop(0, `rgba(140,100,255,${0.04 + smoothBass * 0.05})`); n2.addColorStop(1, 'rgba(140,100,255,0)')
|
||||
ctx.fillStyle = n2; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
for (const s of STARS) {
|
||||
const tw = (Math.sin(t * s.sp + s.ph) + 1) * 0.5
|
||||
const alpha = s.ba * (0.35 + tw * 0.65) * (1 + smoothMid * 0.45)
|
||||
const r = s.r * (1 + smoothBass * tw * 1.0)
|
||||
if (s.r > 1.1) {
|
||||
ctx.beginPath(); ctx.arc(s.x * W, s.y * H, r * 2.8, 0, Math.PI * 2)
|
||||
ctx.fillStyle = `rgba(${a},${alpha * 0.18})`; ctx.fill()
|
||||
}
|
||||
ctx.beginPath(); ctx.arc(s.x * W, s.y * H, r, 0, Math.PI * 2)
|
||||
ctx.fillStyle = `rgba(${a},${alpha})`; ctx.fill()
|
||||
}
|
||||
}
|
||||
|
||||
// ── RAIN ──────────────────────────────────────────────────────────────────
|
||||
const DROPS: Drop[] = Array.from({ length: 65 }, () => ({
|
||||
x: Math.random(), y: Math.random(),
|
||||
speed: Math.random() * 0.003 + 0.0015,
|
||||
len: Math.random() * 0.07 + 0.04,
|
||||
alpha: Math.random() * 0.5 + 0.2,
|
||||
}))
|
||||
|
||||
const drawRain = () => {
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
ctx.fillStyle = 'rgba(10,10,15,0.1)'; ctx.fillRect(0, 0, W, H)
|
||||
const spd = 1 + smoothBass * 4.5
|
||||
for (const d of DROPS) {
|
||||
d.y += d.speed * spd
|
||||
if (d.y > 1.1) { d.y = -d.len; d.x = Math.random() }
|
||||
const x = d.x * W, y = d.y * H
|
||||
const len = d.len * H * (1 + smoothBass * 0.6)
|
||||
const g = ctx.createLinearGradient(x, y - len, x, y)
|
||||
g.addColorStop(0, `rgba(${a},0)`); g.addColorStop(0.6, `rgba(${a},${d.alpha * 0.5})`); g.addColorStop(1, `rgba(${a},${d.alpha})`)
|
||||
ctx.fillStyle = g; ctx.fillRect(x - 1, y - len, 2, len)
|
||||
ctx.beginPath(); ctx.arc(x, y, 2, 0, Math.PI * 2)
|
||||
ctx.fillStyle = `rgba(${a},${d.alpha})`; ctx.fill()
|
||||
}
|
||||
}
|
||||
|
||||
// ── RAYS ──────────────────────────────────────────────────────────────────
|
||||
const NUM_RAYS = 9
|
||||
const RAY_OFF = Array.from({ length: NUM_RAYS }, (_, i) => (i / NUM_RAYS) * Math.PI * 2)
|
||||
|
||||
const drawRays = () => {
|
||||
const W = canvas.width, H = canvas.height, a = ar()
|
||||
const t = Date.now() / 10000
|
||||
const cx = W * 0.5, cy = H * 0.58
|
||||
const maxR = Math.hypot(W, H)
|
||||
|
||||
ctx.clearRect(0, 0, W, H); ctx.fillStyle = '#0a0a0f'; ctx.fillRect(0, 0, W, H)
|
||||
|
||||
for (let i = 0; i < NUM_RAYS; i++) {
|
||||
const angle = RAY_OFF[i] + t
|
||||
const hw = 0.065 + smoothBass * 0.055
|
||||
const al = (i % 2 === 0 ? 0.08 : 0.05) + smoothBass * 0.09 + smoothMid * 0.02
|
||||
ctx.beginPath(); ctx.moveTo(cx, cy); ctx.arc(cx, cy, maxR, angle - hw, angle + hw); ctx.closePath()
|
||||
const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, maxR * 0.65)
|
||||
g.addColorStop(0, `rgba(${a},${al * 2.8})`); g.addColorStop(0.25, `rgba(${a},${al})`); g.addColorStop(1, `rgba(${a},0)`)
|
||||
ctx.fillStyle = g; ctx.fill()
|
||||
}
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const angle = RAY_OFF[i * 2] + t * 1.4 + Math.PI * 0.28
|
||||
const hw = 0.04 + smoothMid * 0.035
|
||||
const al = 0.04 + smoothMid * 0.05
|
||||
ctx.beginPath(); ctx.moveTo(cx, cy); ctx.arc(cx, cy, maxR, angle - hw, angle + hw); ctx.closePath()
|
||||
const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, maxR * 0.5)
|
||||
g.addColorStop(0, `rgba(255,60,172,${al * 2.5})`); g.addColorStop(1, 'rgba(255,60,172,0)')
|
||||
ctx.fillStyle = g; ctx.fill()
|
||||
}
|
||||
const cg = ctx.createRadialGradient(cx, cy, 0, cx, cy, 120 + smoothBass * 160)
|
||||
cg.addColorStop(0, `rgba(${a},${0.12 + smoothBass * 0.18})`); cg.addColorStop(1, `rgba(${a},0)`)
|
||||
ctx.fillStyle = cg; ctx.fillRect(0, 0, W, H)
|
||||
}
|
||||
|
||||
// ── LOOP ──────────────────────────────────────────────────────────────────
|
||||
const drawFn = { orbs: drawOrbs, waves: drawWaves, particles: drawParticles, aurora: drawAurora }[bgMode] ?? drawOrbs
|
||||
const drawFn = ({
|
||||
orbs: drawOrbs, waves: drawWaves, particles: drawParticles,
|
||||
aurora: drawAurora, pulse: drawPulse, stars: drawStars,
|
||||
rain: drawRain, rays: drawRays,
|
||||
} as Record<string, () => void>)[bgMode] ?? drawOrbs
|
||||
|
||||
// Clear once to avoid bleed from previous mode
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
const loop = () => {
|
||||
tick()
|
||||
drawFn()
|
||||
rafId = requestAnimationFrame(loop)
|
||||
}
|
||||
const loop = () => { tick(); drawFn(); rafId = requestAnimationFrame(loop) }
|
||||
loop()
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(rafId)
|
||||
window.removeEventListener('resize', resize)
|
||||
}
|
||||
return () => { cancelAnimationFrame(rafId); window.removeEventListener('resize', resize) }
|
||||
}, [bgMode])
|
||||
|
||||
if (bgMode === 'none') return null
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { create } from 'zustand'
|
||||
|
||||
export type BgMode = 'orbs' | 'waves' | 'particles' | 'aurora' | 'none'
|
||||
export type BgMode = 'orbs' | 'waves' | 'particles' | 'aurora' | 'pulse' | 'stars' | 'rain' | 'rays' | 'none'
|
||||
|
||||
export interface BgPreset {
|
||||
id: BgMode
|
||||
@@ -11,10 +11,14 @@ export interface BgPreset {
|
||||
}
|
||||
|
||||
export const BG_PRESETS: BgPreset[] = [
|
||||
{ id: 'orbs', name: 'Орбы', desc: 'Мягкие цветовые пятна' },
|
||||
{ id: 'waves', name: 'Волны', desc: 'Звуковые волны снизу' },
|
||||
{ id: 'particles', name: 'Частицы', desc: 'Плавающая сеть точек' },
|
||||
{ id: 'orbs', name: 'Орбы', desc: 'Цветовые пятна' },
|
||||
{ id: 'waves', name: 'Волны', desc: 'Звуковые волны' },
|
||||
{ id: 'particles', name: 'Частицы', desc: 'Сеть точек' },
|
||||
{ id: 'aurora', name: 'Аврора', desc: 'Северное сияние' },
|
||||
{ id: 'pulse', name: 'Пульс', desc: 'Расходящиеся кольца' },
|
||||
{ id: 'stars', name: 'Звёзды', desc: 'Звёздное небо' },
|
||||
{ id: 'rain', name: 'Дождь', desc: 'Световые капли' },
|
||||
{ id: 'rays', name: 'Лучи', desc: 'Лучи из центра' },
|
||||
{ id: 'none', name: 'Нет', desc: 'Чистый фон' },
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user