forked from BRETT/BRETT
Initial Commit
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
<script setup lang="ts">
|
||||
import { hexToRgbTuple } from '@/lib/color'
|
||||
|
||||
// Portiert aus Vue Bits (DavidHDev/vue-bits), vereinfacht auf color-Prop
|
||||
const props = withDefaults(defineProps<{ color?: string }>(), {
|
||||
color: '#6366f1',
|
||||
})
|
||||
|
||||
const VERT = `#version 300 es
|
||||
precision highp float;
|
||||
in vec2 position;
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
`
|
||||
|
||||
const FRAG = `#version 300 es
|
||||
precision highp float;
|
||||
uniform float iTime;
|
||||
uniform vec3 uCustomColor;
|
||||
uniform float uSpeed;
|
||||
uniform float uScale;
|
||||
uniform float uOpacity;
|
||||
uniform vec2 uMouse;
|
||||
uniform float uMouseActive;
|
||||
uniform float uIterations;
|
||||
uniform float uStepScale;
|
||||
uniform vec2 uCardRes;
|
||||
uniform float uRadius;
|
||||
out vec4 fragColor;
|
||||
|
||||
void mainImage(out vec4 o, vec2 C) {
|
||||
// Pixelkonsistent: Koordinatenrahmen auf Referenzhöhe 180px normieren —
|
||||
// r.y ist die Brennweite und würde in flachen Containern die
|
||||
// Perspektive extrem verzerren
|
||||
float pxScale = 180.0 / uCardRes.y;
|
||||
vec2 r = uCardRes * pxScale;
|
||||
C *= pxScale;
|
||||
vec2 center = r * 0.5;
|
||||
C = (C - center) / uScale + center;
|
||||
|
||||
vec2 mouseOffset = (uMouse * pxScale - center) * 0.0002;
|
||||
C += mouseOffset * length(C - center) * uMouseActive;
|
||||
|
||||
float i, d, z, T = iTime * uSpeed;
|
||||
vec3 O, p, S;
|
||||
|
||||
for (vec2 Q; ++i < 60.; O += o.w/d*o.xyz) {
|
||||
p = z*normalize(vec3(C-.5*r,r.y));
|
||||
p.z -= 4.;
|
||||
S = p;
|
||||
d = p.y-T;
|
||||
|
||||
p.x += .4*(1.+p.y)*sin(d + p.x*0.1)*cos(.34*d + p.x*0.05);
|
||||
Q = p.xz *= mat2(cos(p.y+vec4(0,11,33,0)-T));
|
||||
z+= d = (abs(sqrt(length(Q*Q)) - .25*(5.+S.y))/3.+8e-4)*uStepScale;
|
||||
o = 1.+sin(S.y+p.z*.5+S.z-length(S-p)+vec4(2,1,0,8));
|
||||
if (i >= uIterations) break;
|
||||
}
|
||||
|
||||
o.xyz = tanh(O/1e4);
|
||||
}
|
||||
|
||||
bool finite1(float x){ return !(isnan(x) || isinf(x)); }
|
||||
vec3 sanitize(vec3 c){
|
||||
return vec3(
|
||||
finite1(c.r) ? c.r : 0.0,
|
||||
finite1(c.g) ? c.g : 0.0,
|
||||
finite1(c.b) ? c.b : 0.0
|
||||
);
|
||||
}
|
||||
|
||||
float cardMask(vec2 fc) {
|
||||
vec2 p = fc - uCardRes * 0.5;
|
||||
vec2 hb = uCardRes * 0.5 - vec2(uRadius);
|
||||
float rd = length(max(abs(p) - hb, 0.0)) - uRadius;
|
||||
return 1.0 - smoothstep(-0.75, 0.75, rd);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 o = vec4(0.0);
|
||||
mainImage(o, gl_FragCoord.xy);
|
||||
vec3 rgb = sanitize(o.rgb);
|
||||
|
||||
float intensity = (rgb.r + rgb.g + rgb.b) / 3.0;
|
||||
vec3 finalColor = intensity * uCustomColor;
|
||||
|
||||
float a = length(rgb) * uOpacity * cardMask(gl_FragCoord.xy);
|
||||
fragColor = vec4(finalColor * a, a);
|
||||
}`
|
||||
|
||||
const ctnDom = ref<HTMLDivElement | null>(null)
|
||||
|
||||
let elapsed = 0
|
||||
let lastT = 0
|
||||
|
||||
useCardShader(ctnDom, {
|
||||
vertex: VERT,
|
||||
fragment: FRAG,
|
||||
mouse: true,
|
||||
renderScale: 0.55,
|
||||
uniforms: {
|
||||
iTime: { value: 0 },
|
||||
uCustomColor: { value: new Float32Array(hexToRgbTuple(props.color)) },
|
||||
uSpeed: { value: 0.4 },
|
||||
uScale: { value: 1 },
|
||||
uOpacity: { value: 1 },
|
||||
uMouse: { value: new Float32Array([0, 0]) },
|
||||
uMouseActive: { value: 0 },
|
||||
uIterations: { value: 48 },
|
||||
uStepScale: { value: 60 / 48 },
|
||||
},
|
||||
color: () => props.color,
|
||||
colorUniforms: { uCustomColor: 0 },
|
||||
frame: ({ t, program, mouse }) => {
|
||||
const u = program.uniforms
|
||||
// Zeit akkumulieren, damit Pausen (Tab-Wechsel) nicht springen
|
||||
const delta = Math.min((t - lastT) * 0.001, 0.1)
|
||||
lastT = t
|
||||
elapsed += delta
|
||||
u.iTime.value = elapsed
|
||||
const res = u.uCardRes.value as Float32Array
|
||||
const m = u.uMouse.value as Float32Array
|
||||
m[0] = mouse.x * res[0]
|
||||
m[1] = (1 - mouse.y) * res[1]
|
||||
u.uMouseActive.value = mouse.active
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="ctnDom" class="relative size-full overflow-hidden rounded-[inherit]" />
|
||||
</template>
|
||||
Reference in New Issue
Block a user