Files
front/components/AnimatedBackground.vue
T
legonzaur 0669619543
release-tag / release-image (push) Successful in 51s
Chore : attempt to reduce loading times
2024-07-31 10:20:48 +02:00

177 lines
3.6 KiB
Vue

<script setup lang="ts">
const settingsStore = useSettingsStore();
import gsap from "gsap";
import ShaderWorker from "~/assets/workers/ShaderWorker?worker";
const emit = defineEmits<{
ready: [];
}>();
let worker: Worker;
const canvas = ref<HTMLCanvasElement | null>(null);
const canvas_resize_temp = ref<HTMLCanvasElement | null>(null);
export interface Props {
isTurn?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
isTurn: () => false,
});
const _colorStart = reactive([0, 0.3, 0]);
const _colorEnd = reactive([0, 1, 0]);
if (props.isTurn) {
Object.assign(_colorStart, [0, 0.3, 0]);
Object.assign(_colorEnd, [0, 1, 0]);
} else {
Object.assign(_colorStart, [0, 0.2, 0.3]);
Object.assign(_colorEnd, [0, 1, 1]);
}
function initShader() {
return new Promise<void>((resolve, reject) => {
if (!canvas.value) {
reject("canvas is null");
return;
}
const offscreen = canvas.value?.transferControlToOffscreen();
worker.postMessage(
{
command: "initShader",
canvas: offscreen,
screen: {
height: window.innerHeight * devicePixelRatio,
width: window.innerWidth * devicePixelRatio,
devicePixelRatio,
},
shaderOptions: {
quality: settingsStore.shaderQuality,
framerate: settingsStore.shaderFramerate,
},
},
[offscreen]
);
if (settingsStore.shaderFramerate == 0) {
killShader();
}
resizeShader();
worker.onmessage = (e) => {
if (e.data == "ready") {
resolve();
}
};
});
}
function recolorShader() {
worker.postMessage({
command: "recolorShader",
colorStart: [..._colorStart],
colorEnd: [..._colorEnd],
});
}
function resizeShader() {
worker.postMessage({
command: "resizeShader",
screen: {
height: window.innerHeight * devicePixelRatio,
width: window.innerWidth * devicePixelRatio,
devicePixelRatio,
},
shaderOptions: {
quality: settingsStore.shaderQuality,
framerate: settingsStore.shaderFramerate,
},
});
}
function killShader() {
worker.postMessage({
command: "killShader",
});
}
function resumeShader() {
worker.postMessage({
command: "resumeShader",
shaderOptions: {
quality: settingsStore.shaderQuality,
framerate: settingsStore.shaderFramerate,
},
});
}
watch(
() => [settingsStore.shaderFramerate],
() => {
if (settingsStore.shaderFramerate == 0) {
killShader();
return;
}
resumeShader();
}
);
watch(
() => [settingsStore.shaderQuality],
() => {
resizeShader();
}
);
watch(
() => [props.isTurn],
() => {
if (props.isTurn) {
gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: 0.3, 2: 0 });
gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 0 });
} else {
gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: 0.2, 2: 0.3 });
gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 1 });
}
}
);
watch([_colorEnd, _colorStart], () => {
recolorShader();
});
onMounted(() => {
worker = new ShaderWorker();
recolorShader();
initShader().then(() => {
emit("ready");
});
window.addEventListener("resize", resizeShader, true);
});
onUnmounted(() => {
window.removeEventListener("resize", resizeShader);
killShader();
});
</script>
<template>
<canvas ref="canvas" id="background" :class="{ pixelated: settingsStore.shaderPixelated }" width="480"
height="270"></canvas>
</template>
<style scoped>
#background {
left: 0;
position: fixed;
height: 100%;
width: 100%;
z-index: -999999;
}
#background.pixelated {
image-rendering: pixelated;
}
</style>