Migrate WebGL themes to vividgl package
parent
61bea1b774
commit
a381f92d14
@ -1,47 +1,89 @@
|
||||
import { defineComponent, computed, h } from 'vue'
|
||||
import { defineComponent, ref, watch, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { VividGL } from 'vividgl'
|
||||
import type { ParamValues } from 'vividgl'
|
||||
import { useThemeStore } from '@/store/theme'
|
||||
import type { AppInputTheme } from '@/models/app'
|
||||
|
||||
import flow from '@/components/themes/flow'
|
||||
import sphere from '@/components/themes/sphere'
|
||||
import rings from '@/components/themes/rings'
|
||||
import plasma from '@/components/themes/plasma'
|
||||
import destruction from '@/components/themes/destruction'
|
||||
import tenderness from '@/components/themes/tenderness'
|
||||
import planet from '@/components/themes/planet'
|
||||
import random from '@/components/themes/random'
|
||||
import tunnel from '@/components/themes/tunnel'
|
||||
import contour from '@/components/themes/contour'
|
||||
import rings3d from '@/components/themes/rings3d'
|
||||
import zappy from '@/components/themes/zappy'
|
||||
|
||||
const themeMap: Record<string, any> = {
|
||||
flow,
|
||||
sphere,
|
||||
rings,
|
||||
plasma,
|
||||
destruction,
|
||||
tenderness,
|
||||
planet,
|
||||
random,
|
||||
tunnel,
|
||||
contour,
|
||||
rings3d,
|
||||
zappy,
|
||||
// Maps osmos setting names (kebab-case) → VividGL param names (camelCase)
|
||||
// Auto-converts kebab to camelCase; explicit overrides for renames
|
||||
const PARAM_MAP: Record<string, string> = {
|
||||
'animation-speed': 'speed',
|
||||
'color-glow': 'glowColor',
|
||||
'color-fog': 'fogColor',
|
||||
}
|
||||
|
||||
function toVividParam(name: string): string {
|
||||
return PARAM_MAP[name] ?? name.replace(/-([a-z])/g, (_, c) => c.toUpperCase())
|
||||
}
|
||||
|
||||
function buildParams(settings: AppInputTheme[] | undefined): ParamValues {
|
||||
const params: ParamValues = {}
|
||||
for (const input of settings ?? []) {
|
||||
if (input.type === 'button') continue
|
||||
const key = toVividParam(input.name)
|
||||
if (key !== 'pxratio' && !Array.isArray(input.value))
|
||||
params[key] = input.value as string | number | boolean
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
function getPxratio(settings: AppInputTheme[] | undefined): number {
|
||||
return (settings?.find(i => i.name === 'pxratio')?.value as number) ?? 0.8
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BackgroundImage',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const theme = computed(() => themeStore.activeTheme)
|
||||
|
||||
return () => {
|
||||
const component = themeMap[theme.value.component ?? 'random'] ?? themeMap.random
|
||||
return (
|
||||
<div class="background-image">
|
||||
{h(component)}
|
||||
</div>
|
||||
)
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
let bg: VividGL | null = null
|
||||
|
||||
const init = (themeName: string) => {
|
||||
bg?.destroy()
|
||||
bg = null
|
||||
if (!canvasRef.value) return
|
||||
|
||||
const knownThemes = VividGL.themes()
|
||||
const name = knownThemes.includes(themeName) ? themeName : knownThemes[0]!
|
||||
const params = buildParams(themeStore.activeTheme.settings)
|
||||
|
||||
try {
|
||||
bg = new VividGL(canvasRef.value, name, params)
|
||||
bg.pxratio = getPxratio(themeStore.activeTheme.settings)
|
||||
bg.start()
|
||||
} catch (e) {
|
||||
console.warn('[BackgroundImage] VividGL error:', e)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => init(themeStore.activeTheme.component ?? 'random'))
|
||||
|
||||
// Switch theme when selection changes
|
||||
watch(() => themeStore.currentTheme, () => {
|
||||
init(themeStore.activeTheme.component ?? 'random')
|
||||
})
|
||||
|
||||
// Sync individual param updates in real time
|
||||
watch(
|
||||
() => themeStore.activeTheme.settings,
|
||||
(settings) => {
|
||||
if (!bg) return
|
||||
for (const input of settings ?? []) {
|
||||
if (input.type === 'button') continue
|
||||
if (input.name === 'pxratio') { bg.pxratio = input.value as number; continue }
|
||||
if (!Array.isArray(input.value))
|
||||
bg.setParam(toVividParam(input.name), input.value as string | number | boolean)
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => bg?.destroy())
|
||||
|
||||
return () => (
|
||||
<div class="background-image">
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
#version 300 es
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
|
||||
// Zoom/scale of the noise pattern — higher values zoom in, revealing more detail
|
||||
uniform float uScale;
|
||||
|
||||
// Number of stripes/contour lines across the noise field
|
||||
uniform float uScaleContour;
|
||||
|
||||
// Line width: controls how much of the contour field is visible (0 = thin hairlines, 1 = wide bands)
|
||||
uniform float uWidth;
|
||||
|
||||
|
||||
// Max line band: caps the upper visible threshold so all lines have similar spatial width
|
||||
// smaller = more uniform thin lines, larger = allows wide bands
|
||||
uniform float uMaxLine;
|
||||
|
||||
// First gradient color (RGB)
|
||||
uniform vec3 uColor1;
|
||||
|
||||
// Second gradient color (RGB)
|
||||
uniform vec3 uColor2;
|
||||
|
||||
// Background color — shown where lines and glow are absent
|
||||
uniform vec3 uBackground;
|
||||
|
||||
const float M_PI = 3.14159265;
|
||||
const int NUM_OCTAVES = 2;
|
||||
|
||||
// Hash functions — map domain to pseudo-random [0, 1)
|
||||
float hash11(float t) {
|
||||
return fract(sin(t * 56789.0) * 56789.0);
|
||||
}
|
||||
|
||||
float hash21(vec2 uv) {
|
||||
return hash11(hash11(uv[0]) + 2.0 * hash11(uv[1]));
|
||||
}
|
||||
|
||||
// Returns a unit-length gradient vector for a given grid cell
|
||||
vec2 hashGradient2(vec2 uv) {
|
||||
float t = hash21(uv);
|
||||
return vec2(cos(2.0 * M_PI * t), sin(2.0 * M_PI * t));
|
||||
}
|
||||
|
||||
// Bilinear mix helper
|
||||
float mix2(float f00, float f10, float f01, float f11, vec2 uv) {
|
||||
return mix(mix(f00, f10, uv[0]), mix(f01, f11, uv[0]), uv[1]);
|
||||
}
|
||||
|
||||
// Rotate a 2D vector by angle r (radians)
|
||||
vec2 rotate2(vec2 uv, float r) {
|
||||
mat2 R = mat2(cos(r), sin(r), -sin(r), cos(r));
|
||||
return R * uv;
|
||||
}
|
||||
|
||||
// Gradient (Perlin) noise with optional gradient rotation for animation
|
||||
float gradientNoise(vec2 uv, float r) {
|
||||
vec2 uvi = floor(uv);
|
||||
vec2 uvf = uv - uvi;
|
||||
vec2 g00 = rotate2(hashGradient2(uvi + vec2(0.0, 0.0)), r);
|
||||
vec2 g10 = rotate2(hashGradient2(uvi + vec2(1.0, 0.0)), r);
|
||||
vec2 g01 = rotate2(hashGradient2(uvi + vec2(0.0, 1.0)), r);
|
||||
vec2 g11 = rotate2(hashGradient2(uvi + vec2(1.0, 1.0)), r);
|
||||
float f00 = dot(g00, uvf - vec2(0.0, 0.0));
|
||||
float f10 = dot(g10, uvf - vec2(1.0, 0.0));
|
||||
float f01 = dot(g01, uvf - vec2(0.0, 1.0));
|
||||
float f11 = dot(g11, uvf - vec2(1.0, 1.0));
|
||||
float t = mix2(f00, f10, f01, f11, smoothstep(vec2(0.0), vec2(1.0), uvf));
|
||||
// Normalize: theoretical bounds are +-1/sqrt(2) ≈ +-0.7
|
||||
return (t / 0.7 + 1.0) * 0.5;
|
||||
}
|
||||
|
||||
// Fractional Brownian Motion — stacks octaves for richer noise detail
|
||||
float noise(vec2 uv, float r) {
|
||||
float result = 0.0;
|
||||
for (int i = 0; i < NUM_OCTAVES; i++) {
|
||||
float p = pow(2.0, float(i));
|
||||
result += gradientNoise(uv * p, r) / p;
|
||||
}
|
||||
// Normalize result back to [0, 1]
|
||||
result /= (pow(2.0, float(NUM_OCTAVES)) - 1.0) / pow(2.0, float(NUM_OCTAVES - 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Maps noise value to a periodic wave that creates the contour bands
|
||||
float wave(float t) {
|
||||
return 0.5 * (1.0 - cos(uScaleContour * M_PI * t));
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec2 uv = uScale * gl_FragCoord.xy / uResolution.y;
|
||||
|
||||
// Animate by rotating noise gradients over time (0.628 ≈ 0.1 * 2π)
|
||||
float r = 0.628 * uTime;
|
||||
|
||||
float noise_fac = noise(uv, r);
|
||||
float contour_fac = wave(noise_fac);
|
||||
vec3 color = mix(uColor1, uColor2, noise_fac);
|
||||
|
||||
float lo = 1.0 - uWidth;
|
||||
float hi = lo + uMaxLine;
|
||||
float fw = fwidth(contour_fac);
|
||||
|
||||
// Crisp anti-aliased line: only pixels in the [lo, hi] band are visible,
|
||||
// bounding maximum spatial width so all lines appear roughly equal-sized
|
||||
float line = smoothstep(lo - fw, lo + fw, contour_fac)
|
||||
- smoothstep(hi - fw, hi + fw, contour_fac);
|
||||
|
||||
float brightness = line;
|
||||
fragColor = vec4(mix(uBackground, color, brightness), 1.0);
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
import { defineComponent, ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import GL from '@/utils/gl'
|
||||
import PostProcessGL from '@/utils/postprocess'
|
||||
import { useThemeStore } from '@/store/theme'
|
||||
import { hexToRgb } from '@/utils/color'
|
||||
import fragmentShader from './fragment.glsl'
|
||||
import vertexShader from './vertex.glsl'
|
||||
|
||||
let render: PostProcessGL
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ContourTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 0.7)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
const scale = computed(() => themeStore.getThemeInput('scale')?.value as number || 3.0)
|
||||
const contour = computed(() => themeStore.getThemeInput('contour')?.value as number || 32.0)
|
||||
const width = computed(() => themeStore.getThemeInput('width')?.value as number || 0.7)
|
||||
|
||||
const maxLine = computed(() => themeStore.getThemeInput('max-line')?.value as number || 0.3)
|
||||
const color1 = computed(() => themeStore.getThemeInput('color-active')?.value as string || '#FF00FF')
|
||||
const color2 = computed(() => themeStore.getThemeInput('color-second')?.value as string || '#00FFFF')
|
||||
const background = computed(() => themeStore.getThemeInput('color-bg')?.value as string || '#000000')
|
||||
|
||||
onMounted(() => {
|
||||
render = new PostProcessGL(
|
||||
canvasRef.value!,
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
window.innerWidth,
|
||||
window.innerHeight,
|
||||
{
|
||||
renderOptions: { externalTimeUse: true },
|
||||
renderHook() {
|
||||
const gl = this as unknown as GL
|
||||
|
||||
if (!gl.programInfo.uniforms.scale) {
|
||||
gl.programInfo.uniforms.scale = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uScale')
|
||||
gl.programInfo.uniforms.contour = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uScaleContour')
|
||||
gl.programInfo.uniforms.width = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uWidth')
|
||||
|
||||
gl.programInfo.uniforms.maxLine = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uMaxLine')
|
||||
gl.programInfo.uniforms.color1 = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uColor1')
|
||||
gl.programInfo.uniforms.color2 = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uColor2')
|
||||
gl.programInfo.uniforms.background = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uBackground')
|
||||
}
|
||||
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
|
||||
const c1 = hexToRgb(color1.value)
|
||||
const c2 = hexToRgb(color2.value)
|
||||
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.scale, scale.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.contour, contour.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.width, width.value)
|
||||
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.maxLine, maxLine.value)
|
||||
const bg = hexToRgb(background.value)
|
||||
gl.ctx.uniform3f(gl.programInfo.uniforms.color1, c1[0] / 255, c1[1] / 255, c1[2] / 255)
|
||||
gl.ctx.uniform3f(gl.programInfo.uniforms.color2, c2[0] / 255, c2[1] / 255, c2[2] / 255)
|
||||
gl.ctx.uniform3f(gl.programInfo.uniforms.background, bg[0] / 255, bg[1] / 255, bg[2] / 255)
|
||||
}
|
||||
},
|
||||
{
|
||||
radiusB: .5, intensityB: 1.0,
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
#version 300 es
|
||||
/*
|
||||
* Original shader from: https://www.shadertoy.com/view/ldyyWm
|
||||
*/
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float uTime;
|
||||
uniform float position;
|
||||
uniform float perspective;
|
||||
uniform vec2 uResolution;
|
||||
|
||||
float burn;
|
||||
float time;
|
||||
|
||||
mat2 rot(float a) {
|
||||
float s=sin(a), c=cos(a);
|
||||
return mat2(s, c, -c, s);
|
||||
}
|
||||
|
||||
float map(vec3 p) {
|
||||
float d = max(max(abs(p.x), abs(p.y)), abs(p.z)) - perspective;
|
||||
burn = d;
|
||||
|
||||
mat2 rm = rot(-time/3. + length(p));
|
||||
p.xy *= rm, p.zy *= rm;
|
||||
|
||||
vec3 q = abs(p) - time;
|
||||
q = abs(q - round(q));
|
||||
|
||||
rm = rot(time);
|
||||
q.xy *= rm, q.xz *= rm;
|
||||
|
||||
d = min(d, min(min(length(q.xy), length(q.yz)), length(q.xz)) + .01);
|
||||
|
||||
burn = pow(d - burn, 2.);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 col, in vec2 fragCoord ) {
|
||||
vec3 rd = normalize(vec3(2. * fragCoord - uResolution.xy, uResolution.y * position)), ro = vec2(0, -2).xxy;
|
||||
|
||||
mat2 r1 = rot(time/4.), r2 = rot(time/2.);
|
||||
rd.xz *= r1, ro.xz *= r1, rd.yz *= r2, ro.yz *= r2;
|
||||
|
||||
float t = 0.0, i = 24.0 * (1.0 - exp(-0.2 * time - 0.1));
|
||||
for (int ii = 0; ii < 100; ++ii) {
|
||||
if (i <= 0.0) break;
|
||||
t += map(ro + rd * t) / 2.0;
|
||||
i -= 1.0;
|
||||
}
|
||||
|
||||
col = vec4(1.1 - burn, exp(-t), exp(-t/2.), 1);
|
||||
// col = vec4(exp(-t) * 4.1, exp(-t/2.) * 0.9, 0.4 - burn * 2.9, 1);
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main(void) {
|
||||
time = uTime + 200.0;
|
||||
mainImage(fragColor, gl_FragCoord.xy);
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
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: 'DestructionTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const perspective = computed(() => themeStore.getThemeInput('perspective')?.value as number || 0.2)
|
||||
const position = computed(() => themeStore.getThemeInput('position')?.value as number || 0.2)
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
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.position) {
|
||||
gl.programInfo.uniforms.position = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'position')
|
||||
gl.programInfo.uniforms.perspective = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'perspective')
|
||||
}
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.position, position.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.perspective, perspective.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
uniform vec2 uResolution;
|
||||
uniform float uTime;
|
||||
uniform float size;
|
||||
|
||||
float random (in vec2 point) {
|
||||
return fract(100.0 * sin(point.x + fract(100.0 * sin(point.y)))); // http://www.matteo-basei.it/noise
|
||||
}
|
||||
|
||||
float noise (in vec2 st) {
|
||||
vec2 i = floor(st);
|
||||
vec2 f = fract(st);
|
||||
|
||||
float a = random(i);
|
||||
float b = random(i + vec2(1., 0.));
|
||||
float c = random(i + vec2(0., 1.));
|
||||
float d = random(i + vec2(1., 1.));
|
||||
|
||||
vec2 u = f * f * (3. - 2. * f);
|
||||
|
||||
return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
||||
}
|
||||
|
||||
#define octaves 10
|
||||
|
||||
float fbm (in vec2 p) {
|
||||
float value = 0.;
|
||||
float freq = size;
|
||||
float amp = .5;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
value += amp * (noise((p - vec2(1.)) * freq));
|
||||
freq *= 1.9;
|
||||
amp *= .6;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float pattern(in vec2 p) {
|
||||
vec2 offset = vec2(-.5);
|
||||
|
||||
vec2 aPos = vec2(sin(uTime * .05), sin(uTime * .1)) * 6.;
|
||||
vec2 aScale = vec2(3.);
|
||||
float a = fbm(p * aScale + aPos);
|
||||
|
||||
vec2 bPos = vec2(sin(uTime * .1), sin(uTime * .1)) * 1.;
|
||||
vec2 bScale = vec2(.5);
|
||||
float b = fbm((p + a) * bScale + bPos);
|
||||
|
||||
vec2 cPos = vec2(-.6, -.5) + vec2(sin(-uTime * .01), sin(uTime * .1)) * 2.;
|
||||
vec2 cScale = vec2(2.);
|
||||
float c = fbm((p + b) * cScale + cPos);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3 palette(in float t) {
|
||||
vec3 a = vec3(.5, .5, .5);
|
||||
vec3 b = vec3(.45, .25, .14);
|
||||
vec3 c = vec3(1. ,1., 1.);
|
||||
vec3 d = vec3(0., .1, .2);
|
||||
|
||||
return a + b * cos(6.28318 * (c * t + d));
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec2 p = gl_FragCoord.xy / uResolution.xy;
|
||||
p.x *= uResolution.x / uResolution.y;
|
||||
|
||||
float value = pow(pattern(p), 2.);
|
||||
vec3 color = palette(value);
|
||||
|
||||
fragColor = vec4(color, 1.);
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
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: 'FlowTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const hue = computed(() => themeStore.getThemeInput('hue')?.value as number || 0)
|
||||
const brightness = computed(() => themeStore.getThemeInput('brightness')?.value as number || 0)
|
||||
const invert = computed(() => themeStore.getThemeInput('invert')?.value as boolean || false)
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const size = computed(() => themeStore.getThemeInput('size')?.value as number || 0.2)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
const styleCanvas = computed(() => ({
|
||||
filter: `hue-rotate(${hue.value}deg) invert(${Number(invert.value)}) brightness(${brightness.value})`
|
||||
}))
|
||||
|
||||
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.size) {
|
||||
gl.programInfo.uniforms.size = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'size')
|
||||
}
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.size, size.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} style={styleCanvas.value} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,186 +0,0 @@
|
||||
#version 300 es
|
||||
/*
|
||||
* Original shader from: https://www.shadertoy.com/view/ttKBDd
|
||||
*/
|
||||
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float camR;
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
uniform vec2 iMouse;
|
||||
|
||||
#define texture(s, uv) vec4(0.0)
|
||||
|
||||
#define R uResolution.xy
|
||||
|
||||
#define m vec2(R.x/R.y*(iMouse.x/R.x-.5),iMouse.y/R.y-.5)
|
||||
#define ss(a, b, t) smoothstep(a, b, t)
|
||||
#define rot(a) mat2(cos(a), -sin(a), sin(a), cos(a))
|
||||
const float pi = 3.14159;
|
||||
|
||||
float hsh(vec2 p) {
|
||||
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||
p3 += dot(p3, p3.yzx + 33.33);
|
||||
return fract((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
|
||||
float perlin(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
|
||||
float a = hsh(i);
|
||||
float b = hsh(i+vec2(1., .0));
|
||||
float c = hsh(i+vec2(0. ,1 ));
|
||||
float d = hsh(i+vec2(1., 1. ));
|
||||
|
||||
vec2 u = smoothstep(0., 1., f);
|
||||
|
||||
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
||||
}
|
||||
|
||||
float octnse(vec2 p, int oct, float t) {
|
||||
float a = 1.;
|
||||
float n = 0.;
|
||||
|
||||
for(int i = 0; i < 10; i++){
|
||||
if (i >= oct) break;
|
||||
p.x += t;
|
||||
n += perlin(p) * a *.5;
|
||||
p*=2.;
|
||||
a *= .5;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
// 3D simplex noise stuff from: https://www.shadertoy.com/view/XsX3zB
|
||||
const float F3 = .3333333;
|
||||
const float G3 = .1666667;
|
||||
|
||||
vec3 random3(vec3 c) {
|
||||
float j = 4096.*sin(dot(c,vec3(17., 59.4, 15.)));
|
||||
vec3 r;
|
||||
r.z = fract(512.*j);
|
||||
j *= .125;
|
||||
r.x = fract(512.*j);
|
||||
j *= .125;
|
||||
r.y = fract(512.*j);
|
||||
return r-.5;
|
||||
}
|
||||
|
||||
float simplex3d(vec3 p) {
|
||||
vec3 s = floor(p + dot(p, vec3(F3)));
|
||||
vec3 x = p - s + dot(s, vec3(G3));
|
||||
vec3 e = step(vec3(0.), x - x.yzx);
|
||||
vec3 i1 = e*(1. - e.zxy);
|
||||
vec3 i2 = 1. - e.zxy*(1. - e);
|
||||
vec3 x1 = x - i1 + G3;
|
||||
vec3 x2 = x - i2 + 2.*G3;
|
||||
vec3 x3 = x - 1. + 3.*G3;
|
||||
vec4 w, d;
|
||||
w.x = dot(x, x);
|
||||
w.y = dot(x1, x1);
|
||||
w.z = dot(x2, x2);
|
||||
w.w = dot(x3, x3);
|
||||
w = max(.6 - w, 0.);
|
||||
d.x = dot(random3(s), x);
|
||||
d.y = dot(random3(s + i1), x1);
|
||||
d.z = dot(random3(s + i2), x2);
|
||||
d.w = dot(random3(s + 1.), x3);
|
||||
w *= w;
|
||||
w *= w;
|
||||
d *= w;
|
||||
|
||||
float nse = dot(d, vec4(52.));
|
||||
|
||||
return 1.-exp(-(nse+1.)*.5);
|
||||
}
|
||||
|
||||
vec4 sphere(vec3 ro, vec3 rd, vec3 cn, float r) {
|
||||
float b = 2.*dot(rd, ro - cn);
|
||||
float c = dot(ro - cn, ro - cn) - (r*r);
|
||||
float d = (b*b) - (4.*c);
|
||||
|
||||
if (d < 0.) {
|
||||
return vec4(0);
|
||||
} else {
|
||||
float t = .5*(-b - sqrt(d));
|
||||
return vec4(ro+rd*t, t);
|
||||
}
|
||||
}
|
||||
|
||||
const float rad = 2.7;
|
||||
|
||||
void mainImage( out vec4 f, in vec2 u ) {
|
||||
vec2 uv = vec2(u.xy - 0.5*R.xy)/R.y;
|
||||
float ux = uv.x;
|
||||
uv *= rot(-uTime*.12 + 2.2);
|
||||
|
||||
vec3 ro = vec3(0., 0., 0.);
|
||||
vec3 rd = normalize(vec3(uv, 1.));
|
||||
float camP = camR;
|
||||
|
||||
float ang = uTime*.12 + 7.;
|
||||
|
||||
if (iMouse.y > 0.){
|
||||
camP -= m.y * 6.;
|
||||
ang += m.x;
|
||||
}
|
||||
|
||||
ro.x += camP * cos(ang);
|
||||
ro.z += camP * sin(ang);
|
||||
|
||||
rd.xz *= rot(ang + pi/2. + .04);
|
||||
|
||||
vec3 ld = normalize(vec3(0.4, 0.3, -0.5));
|
||||
|
||||
float ts = .5;
|
||||
|
||||
vec3 pp = vec3(0);
|
||||
vec3 n = vec3(0);
|
||||
|
||||
vec3 cntr = vec3(0., 0., 0.);
|
||||
vec4 p = sphere(ro, rd, cntr, rad);
|
||||
|
||||
vec3 col = vec3(0);
|
||||
|
||||
pp = p.xyz;
|
||||
n = pp - cntr;
|
||||
n = normalize(n);
|
||||
|
||||
vec2 cuv = abs(vec2(atan(n.z, n.x), acos(p.y / rad)));
|
||||
cuv *= rot(-uTime*.05 * ts);
|
||||
|
||||
float n1 = 2.*octnse(cuv, 10, -uTime*.08 * ts) - 1.;
|
||||
float n2 = 2.*octnse((cuv+3.), 10, -uTime*.03 * ts) - 1.;
|
||||
|
||||
vec2 os = vec2(n1, n2);
|
||||
|
||||
float val = octnse((cuv + vec2(n1, n2)*3.6), 8, -uTime*.1 * ts);
|
||||
|
||||
col += .35+.35*cos(vec3(1.4, .7, 0.9)* n1 * 10. + uTime * .35);
|
||||
col += .48+.37*sin(vec3(2.2, .1, 0.3)* n2 * 20. + vec3(.7, 1.2, .7));
|
||||
col += .48+.23*cos(vec3(1.4, .7, 0.9)* val * 30. + vec3(.2, 0.8, 4.7)+ uTime*.25);
|
||||
col*=.38;
|
||||
|
||||
vec3 ref = reflect(n, rd);
|
||||
float val2 = octnse((ref.xy + os*10. + val*5.), 8, -uTime*.1 * ts);
|
||||
|
||||
col *= val2*3. * vec3(.9, .8, .8);
|
||||
col *= max(dot(n, -rd), 0.0)*vec3(.9, .8, .7);
|
||||
|
||||
col = col*col*1.7;
|
||||
|
||||
col = 1.-exp(-col);
|
||||
|
||||
f = vec4(col, 1.0);
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main(void) {
|
||||
mainImage(fragColor, gl_FragCoord.xy);
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
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: 'PlanetTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const position = computed(() => themeStore.getThemeInput('position')?.value as number || 2.14)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
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.position) {
|
||||
gl.programInfo.uniforms.position = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'camR')
|
||||
}
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time + (gl.time * animationSpeed.value / 10))
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.position, position.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
#version 300 es
|
||||
/**
|
||||
* Original shader: https://www.shadertoy.com/view/MsjSW3
|
||||
*/
|
||||
precision highp float;
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
|
||||
#define t uTime
|
||||
|
||||
mat2 m(float a){float c=cos(a), s=sin(a);return mat2(c,-s,s,c);}
|
||||
|
||||
float map(vec3 p){
|
||||
p.xz*= m(t * 0.4);
|
||||
p.xy*= m(t * 0.3);
|
||||
|
||||
float complexity = 2.;
|
||||
vec3 q = p * complexity + t;
|
||||
|
||||
float zoom = 0.1;
|
||||
float size = .01;
|
||||
return length(p + vec3(sin(t * .7))) * log(length(p) + size) + sin(q.x + sin(q.z + sin(q.y))) * 0.5 - zoom;
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec2 p = gl_FragCoord.xy / uResolution.y - vec2(0.9,.5);
|
||||
vec3 cl = vec3(0.);
|
||||
float saturation = 4.;
|
||||
float scale = -1.0;
|
||||
|
||||
for (int i=0; i <= 5; i++) {
|
||||
vec3 p = vec3(0, 0, 5.) + normalize(vec3(p, scale)) * saturation;
|
||||
float rz = map(p);
|
||||
float glow = 0.5;
|
||||
float varietyOfColors = 0.1;
|
||||
float f = clamp((rz - map(p + varietyOfColors)) * glow, - .1, 1.);
|
||||
vec3 l = vec3(0.102, 0.1059, 0.4) + vec3(5., 2.5, 3.) * f;
|
||||
|
||||
float contrast = 0.2;
|
||||
float hue = 0.;
|
||||
cl = cl * l + smoothstep(2.5, .0, rz) * .7 * l;
|
||||
|
||||
float smoothness = .9;
|
||||
saturation += min(rz, smoothness);
|
||||
}
|
||||
|
||||
fragColor = vec4(cl, 1.);
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
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: 'PlasmaTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const hue = computed(() => themeStore.getThemeInput('hue')?.value as number || 0)
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
const styleCanvas = computed(() => ({
|
||||
filter: `hue-rotate(${hue.value}deg)`
|
||||
}))
|
||||
|
||||
onMounted(() => {
|
||||
render = new GL(
|
||||
canvasRef.value!,
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
window.innerWidth,
|
||||
window.innerHeight,
|
||||
{
|
||||
renderOptions: { externalTimeUse: true },
|
||||
renderHook() {
|
||||
const gl = this as unknown as GL
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} style={styleCanvas.value} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
#version 300 es
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
uniform float symmetry;
|
||||
uniform float thickness;
|
||||
|
||||
float f(vec3 x) {
|
||||
x.z -= uTime;
|
||||
float a = x.z * symmetry;
|
||||
x.xy *= mat2(cos(a), sin(a), -sin(a), cos(a));
|
||||
return thickness - length(cos(x.xy) + sin(x.yz));
|
||||
}
|
||||
|
||||
vec3 lambda_0(vec3 x) {
|
||||
return x + f(x) * (0.5 - (vec3(gl_FragCoord.xy, 1.0) / uResolution.x));
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec3 i_0 = vec3(0.0,0.0,0.0);
|
||||
|
||||
for (float i_1 = 0.0; i_1 < 32.; i_1++) i_0 = lambda_0(i_0);
|
||||
|
||||
vec3 p = i_0;
|
||||
fragColor = vec4(((vec3(2.0,5.0,9.0) + sin(p)) / length(p)),1.0);
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
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: 'RandomTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const hue = computed(() => themeStore.getThemeInput('hue')?.value as number || 0)
|
||||
const brightness = computed(() => themeStore.getThemeInput('brightness')?.value as number || 0)
|
||||
const invert = computed(() => themeStore.getThemeInput('invert')?.value as boolean || false)
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const symmetry = computed(() => themeStore.getThemeInput('symmetry')?.value as number || 64)
|
||||
const thickness = computed(() => themeStore.getThemeInput('thickness')?.value as number || 64)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
const styleCanvas = computed(() => ({
|
||||
filter: `hue-rotate(${hue.value}deg) invert(${Number(invert.value)}) brightness(${brightness.value})`
|
||||
}))
|
||||
|
||||
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.symmetry) {
|
||||
gl.programInfo.uniforms.symmetry = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'symmetry')
|
||||
gl.programInfo.uniforms.thickness = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'thickness')
|
||||
}
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.symmetry, symmetry.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.thickness, thickness.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time + (gl.time * animationSpeed.value / 10))
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} style={styleCanvas.value} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
uniform float uTime;
|
||||
uniform float hue;
|
||||
uniform float zoom; // 32.415
|
||||
uniform vec2 uResolution;
|
||||
float linearity = 2.; // 2.
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
float mx = max( uResolution.x, uResolution.y );
|
||||
vec2 uv = (gl_FragCoord.xy - uResolution.xy * 0.5) / mx;
|
||||
uv.x += sin(uTime + uv.y * linearity) * .2;
|
||||
|
||||
uv.y -= cos(uTime) * 0.1;
|
||||
|
||||
uv.x = dot(uv,uv)*2.0;
|
||||
|
||||
float angle = .4;
|
||||
uv *= mat2(cos(angle), sin(angle), sin(angle), cos(angle));
|
||||
|
||||
float fineness = mx * 0.4; // 0 + 0.4
|
||||
// float fineness = mx * (abs(hue) + 0.2); // 0 + 0.4
|
||||
float sy = uv.y * fineness;
|
||||
float c = fract(-sin(floor(sy) / fineness * 14.) * 437.);
|
||||
|
||||
float f = fract(sy);
|
||||
c *= min(f, 1. - f) * 3.;
|
||||
|
||||
// float zoom = 32.415;
|
||||
float intensity = 2.5;
|
||||
// highlights
|
||||
c += cos(uv.y * zoom - uTime) * intensity;
|
||||
|
||||
// background
|
||||
float r = -uv.y + (.5 + hue);
|
||||
float b = uv.y + (.5 - hue);
|
||||
|
||||
fragColor = vec4(mix(vec3(r, r*.3, b), vec3(c), .3), 1.0);
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
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: 'RingsTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const hue = computed(() => themeStore.getThemeInput('hue')?.value as number || 0)
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const zoom = computed(() => themeStore.getThemeInput('zoom')?.value as number || 32)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
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.hue) {
|
||||
gl.programInfo.uniforms.hue = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'hue')
|
||||
gl.programInfo.uniforms.zoom = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'zoom')
|
||||
}
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.pxratio = pxratio.value
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.hue, hue.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.zoom, zoom.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
#version 300 es
|
||||
/*
|
||||
* Original shader from: https://www.shadertoy.com/view/lslcWj
|
||||
*/
|
||||
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
uniform float size;
|
||||
|
||||
#define R(p, a) p = p * cos(a) + vec2(-p.y, p.x) * sin(a)
|
||||
|
||||
float Sin01(float t) {
|
||||
return 0.5 + 0.5 * sin(6.28319 * t);
|
||||
}
|
||||
|
||||
float SineEggCarton(vec3 p) {
|
||||
return 1.0 - abs(sin(p.x) + sin(p.y) + sin(p.z)) / 3.0;
|
||||
}
|
||||
|
||||
float Map(vec3 p, float scale) {
|
||||
float dSphere = length(p) - 1.0;
|
||||
return max(dSphere, (0.95 - SineEggCarton(scale * p)) / scale);
|
||||
}
|
||||
|
||||
vec3 GetColor(vec3 p) {
|
||||
float amount = clamp((1.5 - length(p)) / 2.0, 0.0, 1.0);
|
||||
vec3 col = 0.5 + 0.5 * cos(6.28319 * (vec3(0.2, 0.0, 0.0) + amount * vec3(1.0, 1.0, 0.5)));
|
||||
return col * amount;
|
||||
}
|
||||
|
||||
void mainImage(out vec4 col, in vec2 fragCoord) {
|
||||
vec3 rd = normalize(vec3(2.0 * fragCoord.xy - uResolution.xy, -uResolution.y));
|
||||
vec3 ro = vec3(0.0, 0.0, size);
|
||||
|
||||
R(rd.xz, 0.5 * uTime);
|
||||
R(ro.xz, 0.5 * uTime);
|
||||
R(rd.yz, 0.5 * uTime);
|
||||
R(ro.yz, 0.5 * uTime);
|
||||
|
||||
float t = 0.0;
|
||||
col.rgb = vec3(0.0353, 0.0275, 0.1255);
|
||||
float scale = mix(3.5, 9.0, Sin01(0.068 * uTime));
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
vec3 p = ro + t * rd;
|
||||
float d = Map(p, scale);
|
||||
if (t > 5.0 || d < 0.001) {
|
||||
break;
|
||||
}
|
||||
t += .9 * d;
|
||||
col.rgb += 0.05 * GetColor(p);
|
||||
}
|
||||
}
|
||||
|
||||
out vec4 fragColor;
|
||||
void main(void) {
|
||||
mainImage(fragColor, gl_FragCoord.xy);
|
||||
fragColor.a = 1.0;
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
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: 'SphereTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const hue = computed(() => themeStore.getThemeInput('hue')?.value as number || 0)
|
||||
const brightness = computed(() => themeStore.getThemeInput('brightness')?.value as number || 0)
|
||||
const invert = computed(() => themeStore.getThemeInput('invert')?.value as boolean || false)
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const size = computed(() => themeStore.getThemeInput('size')?.value as number || 0.2)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
const styleCanvas = computed(() => ({
|
||||
filter: `hue-rotate(${hue.value}deg) invert(${Number(invert.value)}) brightness(${brightness.value})`
|
||||
}))
|
||||
|
||||
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.size) {
|
||||
gl.programInfo.uniforms.size = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'size')
|
||||
}
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.size, size.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} style={styleCanvas.value} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
#version 300 es
|
||||
// Modified so it doesn't really move. Very childish and easy fix.
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec2 uResolution;
|
||||
uniform float uTime;
|
||||
|
||||
const int complexity = 30; // More points of color.
|
||||
const float fluidSpeed = 60.0; // Drives speed, higher number will make it slower.
|
||||
const float color_intensity = 0.5;
|
||||
const float position = 1.0;
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec2 p= (position * gl_FragCoord.xy - uResolution) / max(uResolution.x, uResolution.y);
|
||||
|
||||
for(int i = 1; i < complexity;i++) {
|
||||
vec2 newp= p + uTime * 0.005;
|
||||
newp.x+=0.6/float(i)*sin(float(i)*p.y+uTime/fluidSpeed+20.3*float(i)) + 0.5; // + mouse.y/mouse_factor+mouse_offset;
|
||||
newp.y+=0.6/float(i)*sin(float(i)*p.x+uTime/fluidSpeed+0.3*float(i+10)) - 0.5; // - mouse.x/mouse_factor+mouse_offset;
|
||||
p=newp;
|
||||
}
|
||||
|
||||
vec3 col=vec3(color_intensity*sin(5.0*p.x)+color_intensity,color_intensity*sin(3.0*p.y)+color_intensity,color_intensity*sin(p.x+p.y)+color_intensity);
|
||||
fragColor=vec4(col, 1.0);
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
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: 'TendernessTheme',
|
||||
setup() {
|
||||
const themeStore = useThemeStore()
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const animationSpeed = computed(() => themeStore.getThemeInput('animation-speed')?.value as number || 45)
|
||||
const pxratio = computed(() => themeStore.getThemeInput('pxratio')?.value as number || 0.8)
|
||||
|
||||
onMounted(() => {
|
||||
render = new GL(
|
||||
canvasRef.value!,
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
window.innerWidth,
|
||||
window.innerHeight,
|
||||
{
|
||||
renderOptions: { externalTimeUse: true },
|
||||
renderHook() {
|
||||
const gl = this as unknown as GL
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.pxratio = pxratio.value
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
#version 300 es
|
||||
// Original: http://www.pouet.net/prod.php?which=57245
|
||||
// Credits: Danilo Guanabara
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec2 uResolution;
|
||||
|
||||
// Per-iteration z offset — controls how far apart the RGB channels are in time.
|
||||
// Higher values spread colors into wider rainbow bands; lower values keep it monochromatic.
|
||||
uniform float uStep;
|
||||
|
||||
// Frequency of the radial sine wave — controls ring/wave density.
|
||||
// Higher values produce tighter, more numerous rings; lower values produce broad sweeping waves.
|
||||
uniform float uFrequency;
|
||||
|
||||
// Tunnel pull strength — scales the UV distortion toward the center.
|
||||
// 0.0 = flat pattern with no perspective; higher values create a deeper vortex effect.
|
||||
uniform float uAmplitude;
|
||||
|
||||
// Color channel intensity — inversely controls brightness (smaller = brighter).
|
||||
// Too high darkens the image; too low causes overexposure / color clipping.
|
||||
uniform float uBrightness;
|
||||
|
||||
#define t uTime
|
||||
#define r uResolution
|
||||
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec3 c;
|
||||
float l, z = t;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vec2 uv, p = gl_FragCoord.xy / r;
|
||||
uv = p;
|
||||
p -= .5;
|
||||
p.x *= r.x / r.y;
|
||||
z += uStep;
|
||||
l = length(p);
|
||||
uv += p / l * (sin(z) + 1.) * uAmplitude * abs(sin(l * uFrequency - z - z));
|
||||
c[i] = uBrightness / length(mod(uv, 1.) - .5);
|
||||
}
|
||||
fragColor = vec4(c / l, 1.0);
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
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: 'TunnelTheme',
|
||||
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 step = computed(() => themeStore.getThemeInput('step')?.value as number || 0.07)
|
||||
const frequency = computed(() => themeStore.getThemeInput('frequency')?.value as number || 9.0)
|
||||
const amplitude = computed(() => themeStore.getThemeInput('amplitude')?.value as number || 1.0)
|
||||
const brightness = computed(() => themeStore.getThemeInput('brightness')?.value as number || 0.01)
|
||||
|
||||
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.step) {
|
||||
gl.programInfo.uniforms.step = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uStep')
|
||||
gl.programInfo.uniforms.frequency = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uFrequency')
|
||||
gl.programInfo.uniforms.amplitude = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uAmplitude')
|
||||
gl.programInfo.uniforms.brightness = gl.ctx.getUniformLocation(gl.program as WebGLProgram, 'uBrightness')
|
||||
}
|
||||
|
||||
gl.pxratio = pxratio.value
|
||||
gl.time += animationSpeed.value / 500
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.time, gl.time)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.step, step.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.frequency, frequency.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.amplitude, amplitude.value)
|
||||
gl.ctx.uniform1f(gl.programInfo.uniforms.brightness, brightness.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
render.running = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
render.running = false
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
@ -1,71 +0,0 @@
|
||||
#version 300 es
|
||||
// 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;
|
||||
|
||||
|
||||
out vec4 fragColor;
|
||||
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;
|
||||
|
||||
fragColor = vec4(o);
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1,6 +0,0 @@
|
||||
#version 300 es
|
||||
in vec2 aVertexPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
Loading…
Reference in New Issue