mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-04-21 17:44:39 -06:00
feat: added <EvilEye /> background
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import code from '@content/Backgrounds/EvilEye/EvilEye.vue?raw';
|
||||
import { createCodeObject } from '../../../types/code';
|
||||
|
||||
export const evilEye = createCodeObject(code, 'Backgrounds/EvilEye', {
|
||||
installation: `npm install ogl`,
|
||||
usage: `<template>
|
||||
<div style="width: 100%; height: 600px; position: relative">
|
||||
<EvilEye
|
||||
eyeColor="#FF6F37"
|
||||
:intensity="1.5"
|
||||
:pupilSize="0.6"
|
||||
:irisWidth="0.25"
|
||||
:glowIntensity="0.35"
|
||||
:scale="0.8"
|
||||
:noiseScale="1"
|
||||
:pupilFollow="1"
|
||||
:flameSpeed="1"
|
||||
backgroundColor="#060010"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import EvilEye from './EvilEye.vue';
|
||||
</script>`
|
||||
});
|
||||
@@ -0,0 +1,303 @@
|
||||
<script setup lang="ts">
|
||||
import { Mesh, Program, Renderer, Texture, Triangle } from 'ogl';
|
||||
import { onBeforeUnmount, onMounted, useTemplateRef, watch } from 'vue';
|
||||
|
||||
interface EvilEyeProps {
|
||||
eyeColor?: string;
|
||||
intensity?: number;
|
||||
pupilSize?: number;
|
||||
irisWidth?: number;
|
||||
glowIntensity?: number;
|
||||
scale?: number;
|
||||
noiseScale?: number;
|
||||
pupilFollow?: number;
|
||||
flameSpeed?: number;
|
||||
backgroundColor?: string;
|
||||
}
|
||||
|
||||
function hexToVec3(hex: string): [number, number, number] {
|
||||
const h = hex.replace('#', '');
|
||||
return [parseInt(h.slice(0, 2), 16) / 255, parseInt(h.slice(2, 4), 16) / 255, parseInt(h.slice(4, 6), 16) / 255];
|
||||
}
|
||||
|
||||
function generateNoiseTexture(size = 256): Uint8Array {
|
||||
const data = new Uint8Array(size * size * 4);
|
||||
|
||||
function hash(x: number, y: number, s: number): number {
|
||||
let n = x * 374761393 + y * 668265263 + s * 1274126177;
|
||||
n = Math.imul(n ^ (n >>> 13), 1274126177);
|
||||
return ((n ^ (n >>> 16)) >>> 0) / 4294967296;
|
||||
}
|
||||
|
||||
function noise(px: number, py: number, freq: number, seed: number): number {
|
||||
const fx = (px / size) * freq;
|
||||
const fy = (py / size) * freq;
|
||||
const ix = Math.floor(fx);
|
||||
const iy = Math.floor(fy);
|
||||
const tx = fx - ix;
|
||||
const ty = fy - iy;
|
||||
const w = freq | 0;
|
||||
const v00 = hash(((ix % w) + w) % w, ((iy % w) + w) % w, seed);
|
||||
const v10 = hash((((ix + 1) % w) + w) % w, ((iy % w) + w) % w, seed);
|
||||
const v01 = hash(((ix % w) + w) % w, (((iy + 1) % w) + w) % w, seed);
|
||||
const v11 = hash((((ix + 1) % w) + w) % w, (((iy + 1) % w) + w) % w, seed);
|
||||
return v00 * (1 - tx) * (1 - ty) + v10 * tx * (1 - ty) + v01 * (1 - tx) * ty + v11 * tx * ty;
|
||||
}
|
||||
|
||||
for (let y = 0; y < size; y++) {
|
||||
for (let x = 0; x < size; x++) {
|
||||
let v = 0;
|
||||
let amp = 0.4;
|
||||
let totalAmp = 0;
|
||||
for (let o = 0; o < 8; o++) {
|
||||
const f = 32 * (1 << o);
|
||||
v += amp * noise(x, y, f, o * 31);
|
||||
totalAmp += amp;
|
||||
amp *= 0.65;
|
||||
}
|
||||
v /= totalAmp;
|
||||
v = (v - 0.5) * 2.2 + 0.5;
|
||||
v = Math.max(0, Math.min(1, v));
|
||||
const val = Math.round(v * 255);
|
||||
const i = (y * size + x) * 4;
|
||||
data[i] = val;
|
||||
data[i + 1] = val;
|
||||
data[i + 2] = val;
|
||||
data[i + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const vertexShader = `
|
||||
attribute vec2 uv;
|
||||
attribute vec2 position;
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = vec4(position, 0, 1);
|
||||
}
|
||||
`;
|
||||
|
||||
const fragmentShader = `
|
||||
precision highp float;
|
||||
|
||||
uniform float uTime;
|
||||
uniform vec3 uResolution;
|
||||
uniform sampler2D uNoiseTexture;
|
||||
uniform float uPupilSize;
|
||||
uniform float uIrisWidth;
|
||||
uniform float uGlowIntensity;
|
||||
uniform float uIntensity;
|
||||
uniform float uScale;
|
||||
uniform float uNoiseScale;
|
||||
uniform vec2 uMouse;
|
||||
uniform float uPupilFollow;
|
||||
uniform float uFlameSpeed;
|
||||
uniform vec3 uEyeColor;
|
||||
uniform vec3 uBgColor;
|
||||
|
||||
void main() {
|
||||
vec2 uv = (gl_FragCoord.xy * 2.0 - uResolution.xy) / uResolution.y;
|
||||
uv /= uScale;
|
||||
float ft = uTime * uFlameSpeed;
|
||||
|
||||
float polarRadius = length(uv) * 2.0;
|
||||
float polarAngle = (2.0 * atan(uv.x, uv.y)) / 6.28 * 0.3;
|
||||
vec2 polarUv = vec2(polarRadius, polarAngle);
|
||||
|
||||
vec4 noiseA = texture2D(uNoiseTexture, polarUv * vec2(0.2, 7.0) * uNoiseScale + vec2(-ft * 0.1, 0.0));
|
||||
vec4 noiseB = texture2D(uNoiseTexture, polarUv * vec2(0.3, 4.0) * uNoiseScale + vec2(-ft * 0.2, 0.0));
|
||||
vec4 noiseC = texture2D(uNoiseTexture, polarUv * vec2(0.1, 5.0) * uNoiseScale + vec2(-ft * 0.1, 0.0));
|
||||
|
||||
float distanceMask = 1.0 - length(uv);
|
||||
|
||||
// Inner ring
|
||||
float innerRing = clamp(-1.0 * ((distanceMask - 0.7) / uIrisWidth), 0.0, 1.0);
|
||||
innerRing = (innerRing * distanceMask - 0.2) / 0.28;
|
||||
innerRing += noiseA.r - 0.5;
|
||||
innerRing *= 1.3;
|
||||
innerRing = clamp(innerRing, 0.0, 1.0);
|
||||
|
||||
float outerRing = clamp(-1.0 * ((distanceMask - 0.5) / 0.2), 0.0, 1.0);
|
||||
outerRing = (outerRing * distanceMask - 0.1) / 0.38;
|
||||
outerRing += noiseC.r - 0.5;
|
||||
outerRing *= 1.3;
|
||||
outerRing = clamp(outerRing, 0.0, 1.0);
|
||||
|
||||
innerRing += outerRing;
|
||||
|
||||
// Inner eye
|
||||
float innerEye = distanceMask - 0.1 * 2.0;
|
||||
innerEye *= noiseB.r * 2.0;
|
||||
|
||||
// Pupil with cursor tracking
|
||||
vec2 pupilOffset = uMouse * uPupilFollow * 0.12;
|
||||
vec2 pupilUv = uv - pupilOffset;
|
||||
float pupil = 1.0 - length(pupilUv * vec2(9.0, 2.3));
|
||||
pupil *= uPupilSize;
|
||||
pupil = clamp(pupil, 0.0, 1.0);
|
||||
pupil /= 0.35;
|
||||
|
||||
// Outer eye
|
||||
float outerEyeGlow = 1.0 - length(uv * vec2(0.5, 1.5));
|
||||
outerEyeGlow = clamp(outerEyeGlow + 0.5, 0.0, 1.0);
|
||||
outerEyeGlow += noiseC.r - 0.5;
|
||||
float outerBgGlow = outerEyeGlow;
|
||||
outerEyeGlow = pow(outerEyeGlow, 2.0);
|
||||
outerEyeGlow += distanceMask;
|
||||
outerEyeGlow *= uGlowIntensity;
|
||||
outerEyeGlow = clamp(outerEyeGlow, 0.0, 1.0);
|
||||
outerEyeGlow *= pow(1.0 - distanceMask, 2.0) * 2.5;
|
||||
|
||||
// Outer eye bg glow
|
||||
outerBgGlow += distanceMask;
|
||||
outerBgGlow = pow(outerBgGlow, 0.5);
|
||||
outerBgGlow *= 0.15;
|
||||
|
||||
vec3 color = uEyeColor * uIntensity * clamp(max(innerRing + innerEye, outerEyeGlow + outerBgGlow) - pupil, 0.0, 3.0);
|
||||
color += uBgColor;
|
||||
|
||||
gl_FragColor = vec4(color, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const props = withDefaults(defineProps<EvilEyeProps>(), {
|
||||
eyeColor: '#FF6F37',
|
||||
intensity: 1.5,
|
||||
pupilSize: 0.6,
|
||||
irisWidth: 0.25,
|
||||
glowIntensity: 0.35,
|
||||
scale: 0.8,
|
||||
noiseScale: 1.0,
|
||||
pupilFollow: 1.0,
|
||||
flameSpeed: 1.0,
|
||||
backgroundColor: '#000000'
|
||||
});
|
||||
|
||||
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
|
||||
|
||||
let cleanup: (() => void) | null = null;
|
||||
const setup = () => {
|
||||
if (!containerRef.value) return;
|
||||
const container = containerRef.value;
|
||||
const renderer = new Renderer({ alpha: true, premultipliedAlpha: false });
|
||||
const gl = renderer.gl;
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
|
||||
const noiseData = generateNoiseTexture(256);
|
||||
const noiseTexture = new Texture(gl, {
|
||||
image: noiseData,
|
||||
width: 256,
|
||||
height: 256,
|
||||
generateMipmaps: false,
|
||||
flipY: false
|
||||
});
|
||||
noiseTexture.minFilter = gl.LINEAR;
|
||||
noiseTexture.magFilter = gl.LINEAR;
|
||||
noiseTexture.wrapS = gl.REPEAT;
|
||||
noiseTexture.wrapT = gl.REPEAT;
|
||||
|
||||
const mouse = { x: 0, y: 0, tx: 0, ty: 0 };
|
||||
|
||||
function onMouseMove(e: MouseEvent) {
|
||||
const rect = container.getBoundingClientRect();
|
||||
mouse.tx = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
mouse.ty = -(((e.clientY - rect.top) / rect.height) * 2 - 1);
|
||||
}
|
||||
|
||||
function onMouseLeave() {
|
||||
mouse.tx = 0;
|
||||
mouse.ty = 0;
|
||||
}
|
||||
|
||||
container.addEventListener('mousemove', onMouseMove);
|
||||
container.addEventListener('mouseleave', onMouseLeave);
|
||||
|
||||
renderer.setSize(container.offsetWidth, container.offsetHeight);
|
||||
|
||||
const geometry = new Triangle(gl);
|
||||
const program = new Program(gl, {
|
||||
vertex: vertexShader,
|
||||
fragment: fragmentShader,
|
||||
uniforms: {
|
||||
uTime: { value: 0 },
|
||||
uResolution: { value: [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height] },
|
||||
uNoiseTexture: { value: noiseTexture },
|
||||
uPupilSize: { value: props.pupilSize },
|
||||
uIrisWidth: { value: props.irisWidth },
|
||||
uGlowIntensity: { value: props.glowIntensity },
|
||||
uIntensity: { value: props.intensity },
|
||||
uScale: { value: props.scale },
|
||||
uNoiseScale: { value: props.noiseScale },
|
||||
uMouse: { value: [0, 0] },
|
||||
uPupilFollow: { value: props.pupilFollow },
|
||||
uFlameSpeed: { value: props.flameSpeed },
|
||||
uEyeColor: { value: hexToVec3(props.eyeColor) },
|
||||
uBgColor: { value: hexToVec3(props.backgroundColor) }
|
||||
}
|
||||
});
|
||||
|
||||
function resize() {
|
||||
renderer.setSize(container.offsetWidth, container.offsetHeight);
|
||||
program.uniforms.uResolution.value = [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height];
|
||||
}
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
const mesh = new Mesh(gl, { geometry, program });
|
||||
container.appendChild(gl.canvas);
|
||||
|
||||
let animationFrameId: number;
|
||||
|
||||
function update(time: number) {
|
||||
animationFrameId = requestAnimationFrame(update);
|
||||
mouse.x += (mouse.tx - mouse.x) * 0.05;
|
||||
mouse.y += (mouse.ty - mouse.y) * 0.05;
|
||||
program.uniforms.uMouse.value = [mouse.x, mouse.y];
|
||||
program.uniforms.uTime.value = time * 0.001;
|
||||
renderer.render({ scene: mesh });
|
||||
}
|
||||
animationFrameId = requestAnimationFrame(update);
|
||||
|
||||
cleanup = () => {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
window.removeEventListener('resize', resize);
|
||||
container.removeEventListener('mousemove', onMouseMove);
|
||||
container.removeEventListener('mouseleave', onMouseLeave);
|
||||
container.removeChild(gl.canvas);
|
||||
gl.getExtension('WEBGL_lose_context')?.loseContext();
|
||||
};
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
setup();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
cleanup?.();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [
|
||||
props.eyeColor,
|
||||
props.intensity,
|
||||
props.pupilSize,
|
||||
props.irisWidth,
|
||||
props.glowIntensity,
|
||||
props.scale,
|
||||
props.noiseScale,
|
||||
props.pupilFollow,
|
||||
props.flameSpeed,
|
||||
props.backgroundColor
|
||||
],
|
||||
() => {
|
||||
cleanup?.();
|
||||
setup();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="containerRef" class="w-full h-full" />
|
||||
</template>
|
||||
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<TabbedLayout>
|
||||
<template #preview>
|
||||
<div class="relative p-0 h-[600px] overflow-hidden demo-container">
|
||||
<EvilEye
|
||||
:eye-color="eyeColor"
|
||||
:intensity="intensity"
|
||||
:pupil-size="pupilSize"
|
||||
:iris-width="irisWidth"
|
||||
:glow-intensity="glowIntensity"
|
||||
:scale="scale"
|
||||
:noise-scale="noiseScale"
|
||||
:pupil-follow="pupilFollow"
|
||||
:flame-speed="flameSpeed"
|
||||
:background-color="backgroundColor"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Customize>
|
||||
<div class="flex items-center gap-4 mt-4">
|
||||
<PreviewColor title="Eye Color" v-model="eyeColor" />
|
||||
<PreviewColor title="Background" v-model="backgroundColor" />
|
||||
</div>
|
||||
|
||||
<PreviewSlider title="Intensity" :min="0.5" :max="5" :step="0.1" v-model="intensity" />
|
||||
<PreviewSlider title="Pupil Size" :min="0.1" :max="2" :step="0.05" v-model="pupilSize" />
|
||||
<PreviewSlider title="Iris Width" :min="0.1" :max="0.8" :step="0.05" v-model="irisWidth" />
|
||||
<PreviewSlider title="Glow Intensity" :min="0" :max="1.5" :step="0.05" v-model="glowIntensity" />
|
||||
<PreviewSlider title="Scale" :min="0.2" :max="3" :step="0.1" v-model="scale" />
|
||||
<PreviewSlider title="Noise Scale" :min="0.1" :max="3" :step="0.1" v-model="noiseScale" />
|
||||
<PreviewSlider title="Pupil Follow" :min="0" :max="2" :step="0.1" v-model="pupilFollow" />
|
||||
<PreviewSlider title="Flame Speed" :min="0.1" :max="5" :step="0.1" v-model="flameSpeed" />
|
||||
</Customize>
|
||||
|
||||
<PropTable :data="propData" />
|
||||
<Dependencies :dependency-list="['ogl']" />
|
||||
</template>
|
||||
|
||||
<template #code>
|
||||
<CodeExample :code-object="evilEye" />
|
||||
</template>
|
||||
|
||||
<template #cli>
|
||||
<CliInstallation :command="evilEye.cli" />
|
||||
</template>
|
||||
</TabbedLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import CliInstallation from '@/components/code/CliInstallation.vue';
|
||||
import CodeExample from '@/components/code/CodeExample.vue';
|
||||
import Dependencies from '@/components/code/Dependencies.vue';
|
||||
import Customize from '@/components/common/Customize.vue';
|
||||
import PreviewColor from '@/components/common/PreviewColor.vue';
|
||||
import PreviewSlider from '@/components/common/PreviewSlider.vue';
|
||||
import PropTable from '@/components/common/PropTable.vue';
|
||||
import TabbedLayout from '@/components/common/TabbedLayout.vue';
|
||||
import { evilEye } from '@/constants/code/Backgrounds/evilEyeCode';
|
||||
import EvilEye from '@/content/Backgrounds/EvilEye/EvilEye.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const eyeColor = ref('#FF6F37');
|
||||
const intensity = ref(1.5);
|
||||
const pupilSize = ref(0.6);
|
||||
const irisWidth = ref(0.25);
|
||||
const glowIntensity = ref(0.35);
|
||||
const scale = ref(0.8);
|
||||
const noiseScale = ref(1.0);
|
||||
const pupilFollow = ref(1.0);
|
||||
const flameSpeed = ref(1.0);
|
||||
const backgroundColor = ref('#060010');
|
||||
|
||||
const propData = [
|
||||
{
|
||||
name: 'eyeColor',
|
||||
type: 'string',
|
||||
default: '"#FF6F37"',
|
||||
description: 'Primary eye color in HEX format.'
|
||||
},
|
||||
{
|
||||
name: 'intensity',
|
||||
type: 'number',
|
||||
default: '1.5',
|
||||
description: 'Brightness / HDR intensity of the eye color.'
|
||||
},
|
||||
{
|
||||
name: 'pupilSize',
|
||||
type: 'number',
|
||||
default: '0.6',
|
||||
description: 'Size and darkness of the pupil slit.'
|
||||
},
|
||||
{
|
||||
name: 'irisWidth',
|
||||
type: 'number',
|
||||
default: '0.25',
|
||||
description: 'Width of the main iris ring.'
|
||||
},
|
||||
{
|
||||
name: 'glowIntensity',
|
||||
type: 'number',
|
||||
default: '0.35',
|
||||
description: 'Strength of the outer eye glow.'
|
||||
},
|
||||
{
|
||||
name: 'scale',
|
||||
type: 'number',
|
||||
default: '0.8',
|
||||
description: 'Zoom level of the eye. Values > 1 zoom in, < 1 zoom out.'
|
||||
},
|
||||
{
|
||||
name: 'noiseScale',
|
||||
type: 'number',
|
||||
default: '1.0',
|
||||
description: 'Scale of the fire/noise texture sampling.'
|
||||
},
|
||||
{
|
||||
name: 'pupilFollow',
|
||||
type: 'number',
|
||||
default: '1.0',
|
||||
description: 'Intensity of pupil cursor tracking. 0 disables it.'
|
||||
},
|
||||
{
|
||||
name: 'flameSpeed',
|
||||
type: 'number',
|
||||
default: '1.0',
|
||||
description: 'Independent flame flicker animation speed.'
|
||||
},
|
||||
{
|
||||
name: 'backgroundColor',
|
||||
type: 'string',
|
||||
default: '"#000000"',
|
||||
description: 'Background color in HEX format.'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
@@ -30,14 +30,14 @@
|
||||
|
||||
<PreviewSlider title="Speed" :min="0.1" :max="5" :step="0.1" v-model="speed" />
|
||||
<PreviewSlider title="Scale" :min="0.1" :max="3" :step="0.1" v-model="scale" />
|
||||
<PreviewSlider title="Brightness" :min="1" :max="30" :step="1" v-model="brightness" />
|
||||
<PreviewSlider title="Noise Frequency" :min="1" :max="36" :step="1" v-model="noiseFrequency" />
|
||||
<PreviewSlider title="Noise Amplitude" :min="0.01" :max="0.3" :step="0.01" v-model="noiseAmplitude" />
|
||||
<PreviewSlider title="Band Height" :min="0.01" :max="0.2" :step="0.01" v-model="bandHeight" />
|
||||
<PreviewSlider title="Band Spread" :min="0.1" :max="5" :step="0.1" v-model="bandSpread" />
|
||||
<PreviewSlider title="Octave Decay" :min="1" :max="20" :step="1" v-model="octaveDecay" />
|
||||
<PreviewSlider title="Layer Offset" :min="1" :max="6" :step="1" v-model="layerOffset" />
|
||||
<PreviewSlider title="Color Speed" :min="0.1" :max="3" :step="0.1" v-model="colorSpeed" />
|
||||
<PreviewSlider title="Brightness" :min="0.1" :max="3" :step="0.1" v-model="brightness" />
|
||||
<PreviewSlider title="Noise Frequency" :min="0.5" :max="10" :step="0.5" v-model="noiseFrequency" />
|
||||
<PreviewSlider title="Noise Amplitude" :min="0.5" :max="10" :step="0.5" v-model="noiseAmplitude" />
|
||||
<PreviewSlider title="Band Height" :min="0" :max="1" :step="0.05" v-model="bandHeight" />
|
||||
<PreviewSlider title="Band Spread" :min="0.1" :max="3" :step="0.1" v-model="bandSpread" />
|
||||
<PreviewSlider title="Octave Decay" :min="0.01" :max="0.5" :step="0.01" v-model="octaveDecay" />
|
||||
<PreviewSlider title="Layer Offset" :min="0" :max="1" :step="0.05" v-model="layerOffset" />
|
||||
<PreviewSlider title="Color Speed" :min="0.1" :max="5" :step="0.1" v-model="colorSpeed" />
|
||||
<PreviewSwitch title="Mouse Interaction" v-model="enableMouseInteraction" />
|
||||
<PreviewSlider
|
||||
v-if="enableMouseInteraction"
|
||||
@@ -54,11 +54,11 @@
|
||||
</template>
|
||||
|
||||
<template #code>
|
||||
<CodeExample :code-object="radar" />
|
||||
<CodeExample :code-object="softAurora" />
|
||||
</template>
|
||||
|
||||
<template #cli>
|
||||
<CliInstallation :command="radar.cli" />
|
||||
<CliInstallation :command="softAurora.cli" />
|
||||
</template>
|
||||
</TabbedLayout>
|
||||
</template>
|
||||
@@ -74,7 +74,7 @@ import PreviewSlider from '@/components/common/PreviewSlider.vue';
|
||||
import PreviewSwitch from '@/components/common/PreviewSwitch.vue';
|
||||
import PropTable from '@/components/common/PropTable.vue';
|
||||
import TabbedLayout from '@/components/common/TabbedLayout.vue';
|
||||
import { radar } from '@/constants/code/Backgrounds/radarCode';
|
||||
import { softAurora } from '@/constants/code/Backgrounds/softAuroraCode';
|
||||
import SoftAurora from '@/content/Backgrounds/SoftAurora/SoftAurora.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user