Component Boom

This commit is contained in:
David Haz
2025-07-10 15:36:38 +03:00
parent a4982577ad
commit 9b3465b04d
135 changed files with 16697 additions and 60 deletions

View File

@@ -0,0 +1,232 @@
<template>
<div ref="containerRef" :class="className" :style="style" class="w-full h-full"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, type CSSProperties } from 'vue'
import { Renderer, Program, Mesh, Plane, Camera } from 'ogl'
interface SilkProps {
speed?: number
scale?: number
color?: string
noiseIntensity?: number
rotation?: number
className?: string
style?: CSSProperties
}
const props = withDefaults(defineProps<SilkProps>(), {
speed: 5,
scale: 1,
color: '#7B7481',
noiseIntensity: 1.5,
rotation: 0,
className: '',
style: () => ({})
})
const containerRef = ref<HTMLDivElement>()
const hexToNormalizedRGB = (hex: string): [number, number, number] => {
const clean = hex.replace('#', '')
const r = parseInt(clean.slice(0, 2), 16) / 255
const g = parseInt(clean.slice(2, 4), 16) / 255
const b = parseInt(clean.slice(4, 6), 16) / 255
return [r, g, b]
}
const vertexShader = `
attribute vec2 uv;
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec2 vUv;
varying vec3 vPosition;
void main() {
vPosition = position;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const fragmentShader = `
precision highp float;
varying vec2 vUv;
varying vec3 vPosition;
uniform float uTime;
uniform vec3 uColor;
uniform float uSpeed;
uniform float uScale;
uniform float uRotation;
uniform float uNoiseIntensity;
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;
}
void main() {
float rnd = noise(gl_FragCoord.xy);
vec2 uv = rotateUvs(vUv * 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;
col.a = 1.0;
gl_FragColor = col;
}
`
let renderer: Renderer | null = null
let mesh: Mesh | null = null
let program: Program | null = null
let camera: Camera | null = null
let animateId = 0
const initSilk = () => {
const container = containerRef.value
if (!container) return
renderer = new Renderer({
alpha: true,
antialias: true,
})
const gl = renderer.gl
gl.clearColor(0, 0, 0, 0)
gl.canvas.style.backgroundColor = 'transparent'
camera = new Camera(gl, { fov: 75 })
camera.position.z = 1
const resize = () => {
if (!container || !camera) return
const width = container.offsetWidth
const height = container.offsetHeight
renderer!.setSize(width, height)
camera.perspective({ aspect: width / height })
if (mesh) {
const distance = camera.position.z
const fov = camera.fov * (Math.PI / 180)
const height2 = 2 * Math.tan(fov / 2) * distance
const width2 = height2 * (width / height)
mesh.scale.set(width2, height2, 1)
}
}
window.addEventListener('resize', resize)
const geometry = new Plane(gl, {
width: 1,
height: 1,
})
const colorRGB = hexToNormalizedRGB(props.color)
program = new Program(gl, {
vertex: vertexShader,
fragment: fragmentShader,
uniforms: {
uSpeed: { value: props.speed },
uScale: { value: props.scale },
uNoiseIntensity: { value: props.noiseIntensity },
uColor: { value: colorRGB },
uRotation: { value: props.rotation },
uTime: { value: 0 },
},
})
mesh = new Mesh(gl, { geometry, program })
container.appendChild(gl.canvas)
gl.canvas.style.width = '100%'
gl.canvas.style.height = '100%'
gl.canvas.style.display = 'block'
let lastTime = 0
const update = (t: number) => {
animateId = requestAnimationFrame(update)
const deltaTime = (t - lastTime) / 1000
lastTime = t
if (program && mesh && camera) {
program.uniforms.uTime.value += 0.1 * deltaTime
program.uniforms.uSpeed.value = props.speed
program.uniforms.uScale.value = props.scale
program.uniforms.uNoiseIntensity.value = props.noiseIntensity
program.uniforms.uColor.value = hexToNormalizedRGB(props.color)
program.uniforms.uRotation.value = props.rotation
renderer!.render({ scene: mesh, camera })
}
}
animateId = requestAnimationFrame(update)
resize()
return () => {
cancelAnimationFrame(animateId)
window.removeEventListener('resize', resize)
if (container && gl.canvas.parentNode === container) {
container.removeChild(gl.canvas)
}
gl.getExtension('WEBGL_lose_context')?.loseContext()
}
}
const cleanup = () => {
if (animateId) {
cancelAnimationFrame(animateId)
}
if (renderer) {
const gl = renderer.gl
const container = containerRef.value
if (container && gl.canvas.parentNode === container) {
container.removeChild(gl.canvas)
}
gl.getExtension('WEBGL_lose_context')?.loseContext()
}
renderer = null
mesh = null
camera = null
program = null
}
onMounted(() => {
initSilk()
})
onUnmounted(() => {
cleanup()
})
watch(
() => [props.speed, props.scale, props.color, props.noiseIntensity, props.rotation],
() => {}
)
</script>