Register Tunnel and Contour themes, add locale keys
parent
b137b3438e
commit
ae4208ff81
@ -0,0 +1,75 @@
|
||||
import { defineComponent, ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import GL from '@/utils/gl'
|
||||
import { useThemeStore } from '@/store/theme'
|
||||
import { hexToRgb } from '@/utils/color'
|
||||
import fragmentShader from './fragment.glsl'
|
||||
import vertexShader from './vertex.glsl'
|
||||
|
||||
let render: GL
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Rings3dTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 5)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
const tubeSize = computed(() => themeStore.getThemeInput('tube-size')?.value as number || 0.2)
|
||||
const bubbleSize = computed(() => themeStore.getThemeInput('bubble-size')?.value as number || 1.85)
|
||||
const fogDensity = computed(() => themeStore.getThemeInput('fog-density')?.value as number || 0.8)
|
||||
const spectrumSpeed = computed(() => themeStore.getThemeInput('spectrum-speed')?.value as number || 6.0)
|
||||
const glowColor = computed(() => themeStore.getThemeInput('color-glow')?.value as string || '#AAFFCE')
|
||||
const fogColor = computed(() => themeStore.getThemeInput('color-fog')?.value as string || '#9940B3')
|
||||
|
||||
onMounted(() => {
|
||||
render = new GL(
|
||||
canvasRef.value!,
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
window.innerWidth,
|
||||
window.innerHeight,
|
||||
{
|
||||
renderOptions: { externalTimeUse: true },
|
||||
renderHook() {
|
||||
const gl = this as unknown as GL
|
||||
|
||||
if (!gl.programInfo.uniforms.tubeSize) {
|
||||
gl.programInfo.uniforms.tubeSize = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uTubeSize')
|
||||
gl.programInfo.uniforms.bubbleSize = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uBubbleSize')
|
||||
gl.programInfo.uniforms.fogDensity = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uFogDensity')
|
||||
gl.programInfo.uniforms.spectrumSpeed = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uSpectrumSpeed')
|
||||
gl.programInfo.uniforms.glowColor = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uGlowColor')
|
||||
gl.programInfo.uniforms.fogColor = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uFogColor')
|
||||
}
|
||||
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
|
||||
const gc = hexToRgb(glowColor.value)
|
||||
const fc = hexToRgb(fogColor.value)
|
||||
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.tubeSize, tubeSize.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.bubbleSize, bubbleSize.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.fogDensity, fogDensity.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.spectrumSpeed, spectrumSpeed.value)
|
||||
gl.ctx.uniform3f(gl.programInfo.uniforms.glowColor, gc[0] / 255, gc[1] / 255, gc[2] / 255)
|
||||
gl.ctx.uniform3f(gl.programInfo.uniforms.fogColor, fc[0] / 255, fc[1] / 255, fc[2] / 255)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,5 @@
|
||||
attribute vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
// Inspiration: https://www.shadertoy.com/view/cfjGzV — Zippy Zaps
|
||||
// Credits: -13 thanks to Nguyen2007 ⚡
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
|
||||
// Overall zoom / scale of the electric pattern
|
||||
uniform float uZoom;
|
||||
|
||||
// Shifts the base colour phase vector, cycling through hue combinations
|
||||
uniform float uColorShift;
|
||||
|
||||
// tanh is GLSL ES 3.00+ only — not available in WebGL 1.0.
|
||||
// Implemented via the identity tanh(x) = (e^2x - 1)/(e^2x + 1).
|
||||
// Input clamped to ±15 to prevent exp() overflow on large inputs.
|
||||
vec2 tanh(vec2 x) {
|
||||
x = clamp(x, -15.0, 15.0);
|
||||
vec2 e = exp(2.0 * x);
|
||||
return (e - 1.0) / (e + 1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 res = uResolution;
|
||||
vec2 u = gl_FragCoord.xy;
|
||||
|
||||
// Centre and normalise to screen height; uZoom replaces the hardcoded 0.2
|
||||
u = uZoom * (u + u - res) / res.y;
|
||||
|
||||
// Base colour phase vector — uColorShift scrolls through hue space
|
||||
// z.wxzw swizzle = vec4(z.w, z.x, z.z, z.w) = vec4(0,1,3,0) used in mat2 rotation
|
||||
vec4 z = vec4(1.0 + uColorShift, 2.0 + uColorShift, 3.0 + uColorShift, 0.0);
|
||||
vec4 o = z;
|
||||
|
||||
float a = 0.5;
|
||||
float t = uTime;
|
||||
float i = 0.0;
|
||||
|
||||
// Original: for (float a=.5, t=iTime, i; ++i<19.; o+=...) v=..., u+=...
|
||||
// Rewritten: float i counts 1..18 (pre-increment in condition);
|
||||
// ++t and a+=.03 moved to explicit statements preserving order;
|
||||
// comma-operator body split into sequential statements.
|
||||
vec2 v = res;
|
||||
|
||||
for (int iter = 0; iter < 18; iter++) {
|
||||
i += 1.0; // pre-increment: matches ++i in original condition
|
||||
|
||||
// ++t happens inside the v= expression (pre-increment before the rhs is evaluated)
|
||||
t += 1.0;
|
||||
a += 0.03;
|
||||
|
||||
v = cos(t - 7.0 * u * pow(a, i)) - 5.0 * u;
|
||||
|
||||
// mat2 from explicit components avoids mat2(vec4) constructor rejection on ANGLE/Mesa
|
||||
// vec4(scalar) - vec4 ensures float-vec4 subtraction is unambiguous
|
||||
vec4 r = cos(vec4(i + 0.02 * t) - z.wxzw * 11.0);
|
||||
u *= mat2(r.x, r.y, r.z, r.w);
|
||||
|
||||
// If black/NaN artifacts appear, replace tanh with stanh (smoothstep-tanh approximation)
|
||||
u += tanh(40.0 * dot(u, u) * cos(100.0 * u.yx + t)) / 200.0
|
||||
+ 0.2 * a * u
|
||||
+ cos(4.0 / exp(dot(o, o) / 100.0) + t) / 300.0;
|
||||
|
||||
// for-increment: accumulate glow using the freshly updated v and u
|
||||
o += (1.0 + cos(z + t))
|
||||
/ length((1.0 + i * dot(v, v))
|
||||
* sin(1.5 * u / (0.5 - dot(u, u)) - 9.0 * u.yx + t));
|
||||
}
|
||||
|
||||
// Tonemapping: multiply numerator/denominator by o to avoid float/vec4 division
|
||||
// Equivalent to: 25.6 / (min(o,13.) + 164./o)
|
||||
o = 25.6 * o / (min(o, 13.0) * o + 164.0) - dot(u, u) / 250.0;
|
||||
|
||||
gl_FragColor = vec4(o);
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
import { defineComponent, ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import GL from '@/utils/gl'
|
||||
import { useThemeStore } from '@/store/theme'
|
||||
import fragmentShader from './fragment.glsl'
|
||||
import vertexShader from './vertex.glsl'
|
||||
|
||||
let render: GL
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ZappyTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 5)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
const zoom = computed(() => themeStore.getThemeInput('zoom')?.value as number || 0.2)
|
||||
const colorShift = computed(() => themeStore.getThemeInput('color-shift')?.value as number || 0.0)
|
||||
|
||||
onMounted(() => {
|
||||
render = new GL(
|
||||
canvasRef.value!,
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
window.innerWidth,
|
||||
window.innerHeight,
|
||||
{
|
||||
renderOptions: { externalTimeUse: true },
|
||||
renderHook() {
|
||||
const gl = this as unknown as GL
|
||||
|
||||
if (!gl.programInfo.uniforms.zoom) {
|
||||
gl.programInfo.uniforms.zoom = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uZoom')
|
||||
gl.programInfo.uniforms.colorShift = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uColorShift')
|
||||
}
|
||||
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.zoom, zoom.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.colorShift, colorShift.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,5 @@
|
||||
attribute vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
Loading…
Reference in New Issue