Skip to content

Commit f058ed7

Browse files
committed
Add lava animation themes
1 parent c904fa9 commit f058ed7

File tree

4 files changed

+84
-7
lines changed

4 files changed

+84
-7
lines changed

src/App.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
11
import { startLavaAnimation } from "./lava/app"
22
import { createEffect } from 'solid-js';
3+
import { useThemeStore, colorSchemes } from './stores/theme';
34

45
function App() {
5-
createEffect(() => startLavaAnimation())
6+
const { currentTheme, cycleTheme } = useThemeStore();
7+
8+
createEffect(() => {
9+
const cleanup = startLavaAnimation(colorSchemes[currentTheme()]);
10+
return cleanup;
11+
});
612

713
return (
814
<>
915
{/* Background. Mounting point for lava animation */}
1016
<canvas id="background" class="fixed inset-0 w-screen h-screen" />
1117

18+
{/* Theme toggle button */}
19+
<button
20+
onClick={cycleTheme}
21+
class="fixed top-4 right-4 z-10 px-4 py-2 bg-white/10 backdrop-blur-sm rounded-lg
22+
hover:bg-white/20 transition-colors text-white font-medium"
23+
>
24+
Theme: {currentTheme()}
25+
</button>
26+
1227
{/* Content */}
1328
<div class="relative min-h-screen text-white">
1429
{/* Hero section */}

src/lava/app.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ import fragmentShader from './glsl/fragment.glsl';
88
* The animation uses spherical coordinates to position the camera and renders
99
* a full-screen quad with custom shaders.
1010
*
11+
* @param {Object} options Configuration options
12+
* @param {number[]} [options.backgroundColor=[0.4, 0.1, 0.4]] Background color as RGB array
13+
* @param {number[]} [options.lavaColor=[2.0, 0.8, -0.6]] Lava color as RGB array
1114
* @returns {Function} A cleanup function that cancels the animation frame when called
1215
* @throws {Error} If WebGL context cannot be obtained or shader compilation fails
1316
*/
14-
export function startLavaAnimation() {
17+
export function startLavaAnimation({
18+
backgroundColor = [0.4, 0.1, 0.4],
19+
lavaColor = [2.0, 0.8, -0.6]
20+
} = {}) {
1521
// Calculate camera position
1622
// based on THREE.Vector3.setFromSphericalCoords(radius, phi, theta)
1723
const DEG_TO_RAD = Math.PI / 180;
@@ -52,6 +58,8 @@ export function startLavaAnimation() {
5258
uTime: time * 0.001,
5359
uResolution: [canvasWidth, canvasHeight],
5460
uCameraPosition: cameraPosition,
61+
uBackgroundColor: backgroundColor,
62+
uLavaColor: lavaColor,
5563
};
5664

5765
gl.useProgram(programInfo.program);

src/lava/glsl/fragment.glsl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ precision mediump float;
33
uniform float uTime;
44
uniform vec2 uResolution;
55
uniform vec3 uCameraPosition;
6-
7-
vec3 backgroundColor = vec3(0.4, 0.1, 0.4);
8-
vec3 lavaColor = vec3(2.0, 0.8, -0.6);
6+
uniform vec3 uBackgroundColor;
7+
uniform vec3 uLavaColor;
98

109
// Based on https://www.shadertoy.com/view/fsKXDm
1110

@@ -119,8 +118,8 @@ void main() {
119118

120119
gl_FragColor = vec4(
121120
mix(
122-
backgroundColor,
123-
lavaColor,
121+
uBackgroundColor,
122+
uLavaColor,
124123
col
125124
),
126125
1.0

src/stores/theme.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { createSignal } from 'solid-js';
2+
3+
type ThemeName = 'Lambda Nix' | 'Nix Blue' | 'Lava' | 'Ocean' | 'Acid';
4+
5+
export const colorSchemes: Record<ThemeName, { backgroundColor: number[], lavaColor: number[] }> = {
6+
'Lambda Nix': {
7+
backgroundColor: [0.15, 0.05, 0.25], // More purple-dominant dark base
8+
lavaColor: [0.72, 0.89, 1.22] // Slightly darker blue tint
9+
},
10+
'Nix Blue': {
11+
backgroundColor: [0.126, 0.194, 0.314], // Darker blue-purple tint (80% of #324D7D)
12+
lavaColor: [0.72, 0.89, 1.22] // Slightly darker blue tint
13+
},
14+
'Lava': {
15+
backgroundColor: [0.4, 0.1, 0.4], // Original purple-tinted background
16+
lavaColor: [2.0, 0.8, -0.6]
17+
},
18+
'Ocean': {
19+
backgroundColor: [0.05, 0.08, 0.25], // Added cyan-blue tint
20+
lavaColor: [0.0, 1.2, 2.0]
21+
},
22+
'Acid': {
23+
backgroundColor: [0.08, 0.15, 0.05], // Added yellowish-green tint
24+
lavaColor: [0.8, 1.5, 0.0]
25+
}
26+
};
27+
28+
const themes: ThemeName[] = ['Lambda Nix', 'Nix Blue', 'Lava', 'Ocean', 'Acid'];
29+
30+
// Get initial theme from localStorage or default to 'Lava'
31+
const savedTheme = localStorage.getItem('theme') as ThemeName;
32+
const initialTheme: ThemeName = themes.includes(savedTheme) ? savedTheme : 'Lava';
33+
34+
const [currentTheme, setCurrentTheme] = createSignal<ThemeName>(initialTheme);
35+
36+
export const useThemeStore = () => {
37+
const cycleTheme = () => {
38+
const current = currentTheme();
39+
const currentIndex = themes.indexOf(current);
40+
const nextIndex = (currentIndex + 1) % themes.length;
41+
const newTheme = themes[nextIndex];
42+
43+
localStorage.setItem('theme', newTheme);
44+
setCurrentTheme(newTheme);
45+
};
46+
47+
return {
48+
currentTheme,
49+
setTheme: (theme: ThemeName) => {
50+
localStorage.setItem('theme', theme);
51+
setCurrentTheme(theme);
52+
},
53+
cycleTheme
54+
};
55+
};

0 commit comments

Comments
 (0)