forked from BRETT/BRETT
Initial Commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
<script setup lang="ts">
|
||||
import { hexToRgbTuple } from '@/lib/color'
|
||||
|
||||
// Portiert aus Vue Bits (DavidHDev/vue-bits), Plane+Camera auf Fullscreen-Triangle
|
||||
// vereinfacht, nur color-Prop
|
||||
const props = withDefaults(defineProps<{ color?: string }>(), {
|
||||
color: '#6366f1',
|
||||
})
|
||||
|
||||
const VERT = `
|
||||
attribute vec2 uv;
|
||||
attribute vec2 position;
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
`
|
||||
|
||||
const FRAG = `
|
||||
precision highp float;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec3 uColor;
|
||||
uniform float uSpeed;
|
||||
uniform float uScale;
|
||||
uniform float uRotation;
|
||||
uniform float uNoiseIntensity;
|
||||
uniform vec2 uCardRes;
|
||||
uniform float uRadius;
|
||||
|
||||
const float e = 2.71828182845904523536;
|
||||
|
||||
float noise(vec2 texCoord) {
|
||||
float G = e;
|
||||
vec2 r = (G * sin(G * texCoord));
|
||||
return fract(r.x * r.y * (1.0 + texCoord.x));
|
||||
}
|
||||
|
||||
vec2 rotateUvs(vec2 uv, float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
mat2 rot = mat2(c, -s, s, c);
|
||||
return rot * uv;
|
||||
}
|
||||
|
||||
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() {
|
||||
float rnd = noise(gl_FragCoord.xy);
|
||||
// Pixelkonsistent: Muster-Koordinaten auf eine Referenzgröße von 180px
|
||||
// normieren, damit flache Container den Effekt nicht vertikal stauchen
|
||||
vec2 suv = vUv * (uCardRes / 180.0);
|
||||
vec2 uv = rotateUvs(suv * uScale, uRotation);
|
||||
vec2 tex = uv * uScale;
|
||||
float tOffset = uSpeed * uTime;
|
||||
|
||||
tex.y += 0.03 * sin(8.0 * tex.x - tOffset);
|
||||
|
||||
float pattern = 0.6 +
|
||||
0.4 * sin(5.0 * (tex.x + tex.y +
|
||||
cos(3.0 * tex.x + 5.0 * tex.y) +
|
||||
0.02 * tOffset) +
|
||||
sin(20.0 * (tex.x + tex.y - 0.1 * tOffset)));
|
||||
|
||||
vec4 col = vec4(uColor, 1.0) * vec4(pattern) - rnd / 15.0 * uNoiseIntensity;
|
||||
|
||||
float m = cardMask(gl_FragCoord.xy);
|
||||
float a = clamp(pattern * 0.45, 0.0, 1.0) * m;
|
||||
gl_FragColor = vec4(col.rgb * a, a);
|
||||
}
|
||||
`
|
||||
|
||||
const ctnDom = ref<HTMLDivElement | null>(null)
|
||||
|
||||
let elapsed = 0
|
||||
let lastT = 0
|
||||
|
||||
useCardShader(ctnDom, {
|
||||
vertex: VERT,
|
||||
fragment: FRAG,
|
||||
uniforms: {
|
||||
uTime: { value: 0 },
|
||||
uColor: { value: new Float32Array(hexToRgbTuple(props.color)) },
|
||||
uSpeed: { value: 5 },
|
||||
uScale: { value: 1 },
|
||||
uNoiseIntensity: { value: 1.5 },
|
||||
uRotation: { value: 0 },
|
||||
},
|
||||
color: () => props.color,
|
||||
colorUniforms: { uColor: 0 },
|
||||
frame: ({ t, program }) => {
|
||||
const delta = Math.min((t - lastT) * 0.001, 0.1)
|
||||
lastT = t
|
||||
elapsed += 0.1 * delta
|
||||
program.uniforms.uTime.value = elapsed
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="ctnDom" class="relative size-full overflow-hidden rounded-[inherit]" />
|
||||
</template>
|
||||
Reference in New Issue
Block a user