@canvas3/nuxt 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/module.d.mts +5 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +32 -0
- package/dist/runtime/components/canvas3-image.vue +71 -0
- package/dist/runtime/components/canvas3-image.vue.d.ts +5 -0
- package/dist/runtime/components/canvas3-text.vue +95 -0
- package/dist/runtime/components/canvas3-text.vue.d.ts +11 -0
- package/dist/runtime/constants/default-canvas3-options.d.ts +40 -0
- package/dist/runtime/constants/default-canvas3-options.js +40 -0
- package/dist/runtime/constants/shaders/TextBlurFragment.glsl +126 -0
- package/dist/runtime/constants/shaders/TextBlurVertex.glsl +10 -0
- package/dist/runtime/constants/shaders/projectBlurFragment.glsl +143 -0
- package/dist/runtime/constants/shaders/projectBlurVertex.glsl +11 -0
- package/dist/runtime/constants/shaders/scrollFragment.glsl +7 -0
- package/dist/runtime/constants/shaders/scrollVertex.glsl +8 -0
- package/dist/runtime/directives/action-on-scroll.d.ts +2 -0
- package/dist/runtime/directives/action-on-scroll.js +42 -0
- package/dist/runtime/directives/canvas3-image-directive.client.d.ts +6 -0
- package/dist/runtime/directives/canvas3-image-directive.client.js +104 -0
- package/dist/runtime/directives/set-data-attributes.d.ts +3 -0
- package/dist/runtime/directives/set-data-attributes.js +34 -0
- package/dist/runtime/layouts/canvas3-layout.vue +44 -0
- package/dist/runtime/layouts/canvas3-layout.vue.d.ts +11 -0
- package/dist/runtime/plugin.d.ts +2 -0
- package/dist/runtime/plugin.js +3 -0
- package/dist/runtime/plugins/directives.d.ts +2 -0
- package/dist/runtime/plugins/directives.js +9 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/types/shaders.d.ts +4 -0
- package/dist/runtime/types/three-msdf-text-utils.d.ts +36 -0
- package/dist/runtime/types/types.d.ts +71 -0
- package/dist/runtime/types/types.js +0 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/TextLayout.d.ts +1 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/TextLayout.js +0 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/createIndices.d.ts +1 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/createIndices.js +0 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/index.d.ts +1 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/index.js +0 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/utils.d.ts +1 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/utils.js +0 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/vertices.d.ts +1 -0
- package/dist/runtime/utils/MSDFFont/MSDFTextGeometry/vertices.js +0 -0
- package/dist/runtime/utils/canvas3/canvas3.d.ts +65 -0
- package/dist/runtime/utils/canvas3/canvas3.js +512 -0
- package/dist/runtime/utils/canvas3/helpers.d.ts +12 -0
- package/dist/runtime/utils/canvas3/helpers.js +96 -0
- package/dist/runtime/utils/canvas3/scroll.d.ts +37 -0
- package/dist/runtime/utils/canvas3/scroll.js +191 -0
- package/dist/runtime/utils/exports.d.ts +10 -0
- package/dist/runtime/utils/exports.js +14 -0
- package/dist/types.d.mts +7 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Get your module up and running quickly.
|
|
3
|
+
|
|
4
|
+
Find and replace all on all files (CMD+SHIFT+F):
|
|
5
|
+
- Name: My Module
|
|
6
|
+
- Package name: my-module
|
|
7
|
+
- Description: My new Nuxt module
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
# Canvas3 Nuxt Module
|
|
11
|
+
|
|
12
|
+
Nuxt module for ThreeJS integration and additional features
|
|
13
|
+
|
|
14
|
+
[//]: # (- [✨ Release Notes](/CHANGELOG.md))
|
|
15
|
+
|
|
16
|
+
[//]: # ( - [🏀 Online playground](https://stackblitz.com/github/your-org/my-module?file=playground%2Fapp.vue))
|
|
17
|
+
|
|
18
|
+
[//]: # ( - [📖 Documentation](https://example.com))
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
[✨ Example use cases](https://canvas3.vercel.app/)
|
|
23
|
+
|
|
24
|
+
<!-- Highlight some of the features your module provide here -->
|
|
25
|
+
|
|
26
|
+
[//]: # (- ⛰ Foo)
|
|
27
|
+
|
|
28
|
+
[//]: # (- 🚠 Bar)
|
|
29
|
+
|
|
30
|
+
[//]: # (- 🌲 Baz)
|
|
31
|
+
|
|
32
|
+
## Quick Setup
|
|
33
|
+
|
|
34
|
+
Install the module to your Nuxt application with one command:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx nuxi module add canvas3-nuxt
|
|
38
|
+
```
|
|
39
|
+
That's it! You can now use Canvas3 module in your Nuxt app ✨
|
|
40
|
+
|
|
41
|
+
## Contribution
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>Local development</summary>
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install dependencies
|
|
48
|
+
npm install
|
|
49
|
+
|
|
50
|
+
# Generate type stubs
|
|
51
|
+
npm run dev:prepare
|
|
52
|
+
|
|
53
|
+
# Develop with the playground
|
|
54
|
+
npm run dev
|
|
55
|
+
|
|
56
|
+
# Build the playground
|
|
57
|
+
npm run dev:build
|
|
58
|
+
|
|
59
|
+
# Run ESLint
|
|
60
|
+
npm run lint
|
|
61
|
+
|
|
62
|
+
# Run Vitest
|
|
63
|
+
npm run test
|
|
64
|
+
npm run test:watch
|
|
65
|
+
|
|
66
|
+
# Release new version
|
|
67
|
+
npm run release
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
</details>
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addTemplate, addLayout, addComponent, addPlugin, addImports } from '@nuxt/kit';
|
|
2
|
+
|
|
3
|
+
const module = defineNuxtModule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "canvas-nuxt-layout",
|
|
6
|
+
configKey: "canvas3Layout"
|
|
7
|
+
},
|
|
8
|
+
setup(_, nuxt) {
|
|
9
|
+
const { resolve } = createResolver(import.meta.url);
|
|
10
|
+
const canvas3Layout = addTemplate({
|
|
11
|
+
src: resolve("./runtime/layouts/canvas3-layout.vue"),
|
|
12
|
+
filename: "layout.vue",
|
|
13
|
+
write: true
|
|
14
|
+
});
|
|
15
|
+
addLayout(canvas3Layout, "canvas3");
|
|
16
|
+
addComponent({
|
|
17
|
+
name: "Canvas3Image",
|
|
18
|
+
filePath: resolve("./runtime/components/canvas3-image.vue"),
|
|
19
|
+
global: true
|
|
20
|
+
});
|
|
21
|
+
addPlugin(resolve("./runtime/plugins/directives"));
|
|
22
|
+
addImports([
|
|
23
|
+
{
|
|
24
|
+
name: "Canvas3",
|
|
25
|
+
from: resolve("./runtime/utils/exports")
|
|
26
|
+
}
|
|
27
|
+
]);
|
|
28
|
+
nuxt.options.alias["#canvas3-nuxt"] = resolve("./runtime");
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export { module as default };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="webgl-img-wrapper">
|
|
3
|
+
<img
|
|
4
|
+
ref="image"
|
|
5
|
+
class="webgl-img"
|
|
6
|
+
:class="{ 'reduced-motion': reducedMotion ?? null }"
|
|
7
|
+
:alt="props.options.alt"
|
|
8
|
+
:src="props.options.src"
|
|
9
|
+
:loading="props.options.loadStrategy"
|
|
10
|
+
@load="addImageToCanvas"
|
|
11
|
+
>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup>
|
|
16
|
+
import { ref, computed, watch, onMounted, nextTick, onBeforeUnmount } from "vue";
|
|
17
|
+
import { Canvas3 } from "#canvas3-nuxt/utils/canvas3/canvas3";
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
options: {
|
|
20
|
+
type: Object,
|
|
21
|
+
default: () => ({
|
|
22
|
+
alt: "",
|
|
23
|
+
src: "",
|
|
24
|
+
loadStrategy: "lazy",
|
|
25
|
+
shaderName: void 0,
|
|
26
|
+
uniforms: {},
|
|
27
|
+
activateMeshUniforms: {}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const reducedMotion = computed(() => Canvas3.options?.disabled ?? null);
|
|
32
|
+
const image = ref(null);
|
|
33
|
+
const generatedMeshId = "image_" + crypto.randomUUID();
|
|
34
|
+
const imgAddedToCanvas = ref(false);
|
|
35
|
+
const addImageToCanvas = async () => {
|
|
36
|
+
await nextTick();
|
|
37
|
+
if (!image.value || Canvas3.canvasInitiated.value === false || Canvas3.options?.disabled || imgAddedToCanvas.value) return;
|
|
38
|
+
if (image.value.naturalWidth === 0) return;
|
|
39
|
+
image.value.dataset.meshId = generatedMeshId;
|
|
40
|
+
Canvas3.addImageAsMesh(
|
|
41
|
+
image.value,
|
|
42
|
+
props.options.shaderName,
|
|
43
|
+
generatedMeshId,
|
|
44
|
+
props.options.uniforms,
|
|
45
|
+
props.options.activateMeshUniforms
|
|
46
|
+
);
|
|
47
|
+
imgAddedToCanvas.value = true;
|
|
48
|
+
};
|
|
49
|
+
watch(() => Canvas3.canvasInitiated.value, (ready) => {
|
|
50
|
+
if (ready) addImageToCanvas();
|
|
51
|
+
});
|
|
52
|
+
watch(() => props.options.uniforms, (u) => {
|
|
53
|
+
Canvas3.meshUniformsUpdate(generatedMeshId, u);
|
|
54
|
+
}, { deep: true });
|
|
55
|
+
watch(() => props.options.src, () => {
|
|
56
|
+
imgAddedToCanvas.value = false;
|
|
57
|
+
nextTick(() => {
|
|
58
|
+
if (image.value?.complete) addImageToCanvas();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
onMounted(() => {
|
|
62
|
+
if (image.value?.complete) addImageToCanvas();
|
|
63
|
+
});
|
|
64
|
+
onBeforeUnmount(() => {
|
|
65
|
+
Canvas3.removeMesh(generatedMeshId);
|
|
66
|
+
});
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<style scoped>
|
|
70
|
+
.webgl-img{max-height:100%;max-width:100%;opacity:0}.webgl-img.reduced-motion{height:100%;-o-object-fit:cover;object-fit:cover;opacity:1;width:100%}
|
|
71
|
+
</style>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
+
options: Record<string, any>;
|
|
3
|
+
$props: any;
|
|
4
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
5
|
+
export default _default;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span
|
|
3
|
+
ref="htmlEl"
|
|
4
|
+
class="text-wrapper"
|
|
5
|
+
:class="{ 'reduced-motion': reducedMotion }"
|
|
6
|
+
>
|
|
7
|
+
<slot />
|
|
8
|
+
</span>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
import { ref, watch, onMounted, onBeforeUnmount, defineProps, computed } from "vue";
|
|
13
|
+
import { Canvas3 } from "#canvas3-nuxt/utils/canvas3/canvas3";
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
options: {
|
|
16
|
+
type: {
|
|
17
|
+
shaderName: {
|
|
18
|
+
type: String,
|
|
19
|
+
default: null
|
|
20
|
+
},
|
|
21
|
+
theme: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: "dark"
|
|
24
|
+
},
|
|
25
|
+
uniforms: {
|
|
26
|
+
type: Object,
|
|
27
|
+
default: () => {
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
activateMeshUniforms: {
|
|
31
|
+
type: Object,
|
|
32
|
+
default: () => {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
default: () => ({
|
|
37
|
+
uniforms: {},
|
|
38
|
+
activateMeshUniforms: {}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const reducedMotion = computed(() => {
|
|
43
|
+
return Canvas3.options?.disabled ?? null;
|
|
44
|
+
});
|
|
45
|
+
const htmlEl = ref("htmlEl");
|
|
46
|
+
const meshId = "text" + crypto.randomUUID();
|
|
47
|
+
const getTrimmedText = () => {
|
|
48
|
+
let innerHTML = htmlEl.value.innerHTML;
|
|
49
|
+
if (innerHTML.includes("<!--]-->")) {
|
|
50
|
+
const start = innerHTML.indexOf("<!--[-->") + 8;
|
|
51
|
+
const end = innerHTML.indexOf("<!--]-->");
|
|
52
|
+
innerHTML = innerHTML.slice(start, end);
|
|
53
|
+
}
|
|
54
|
+
return innerHTML;
|
|
55
|
+
};
|
|
56
|
+
watch(
|
|
57
|
+
() => props.options.uniforms,
|
|
58
|
+
(uniforms) => {
|
|
59
|
+
if (Canvas3.options?.disabled)
|
|
60
|
+
return;
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
Canvas3.meshUniformsUpdate(meshId, uniforms);
|
|
63
|
+
}, 0);
|
|
64
|
+
},
|
|
65
|
+
{ deep: true }
|
|
66
|
+
);
|
|
67
|
+
onMounted(() => {
|
|
68
|
+
htmlEl.value.dataset.meshId = meshId;
|
|
69
|
+
});
|
|
70
|
+
onBeforeUnmount(() => {
|
|
71
|
+
Canvas3.removeMesh(meshId);
|
|
72
|
+
});
|
|
73
|
+
watch(
|
|
74
|
+
() => Canvas3.canvasInitiated.value,
|
|
75
|
+
(newVal) => {
|
|
76
|
+
if (Canvas3.options?.disabled || !newVal)
|
|
77
|
+
return;
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
Canvas3.addTextAsMSDF(
|
|
80
|
+
props.options.shaderName,
|
|
81
|
+
meshId,
|
|
82
|
+
htmlEl.value,
|
|
83
|
+
getTrimmedText(),
|
|
84
|
+
props.options.theme,
|
|
85
|
+
props.options.uniforms,
|
|
86
|
+
props.options.activateMeshUniforms
|
|
87
|
+
);
|
|
88
|
+
}, 0);
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<style scoped>
|
|
94
|
+
.text-wrapper{display:inline-block;opacity:0}.text-wrapper.reduced-motion{opacity:1}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
2
|
+
export default _default;
|
|
3
|
+
type __VLS_WithSlots<T, S> = T & (new () => {
|
|
4
|
+
$slots: S;
|
|
5
|
+
});
|
|
6
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {
|
|
7
|
+
$props: any;
|
|
8
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
9
|
+
type __VLS_Slots = {
|
|
10
|
+
default?: ((props: {}) => any) | undefined;
|
|
11
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const defaultCanvas3Options: {
|
|
2
|
+
font: {
|
|
3
|
+
fnt: string;
|
|
4
|
+
atlas: string;
|
|
5
|
+
};
|
|
6
|
+
shaders: {
|
|
7
|
+
scroll: {
|
|
8
|
+
fragmentShader: any;
|
|
9
|
+
vertexShader: any;
|
|
10
|
+
};
|
|
11
|
+
default: {
|
|
12
|
+
fragmentShader: any;
|
|
13
|
+
vertexShader: any;
|
|
14
|
+
textFragment: any;
|
|
15
|
+
textVertex: any;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
activateMeshOptions: {
|
|
19
|
+
image: {
|
|
20
|
+
uAniInImage: {
|
|
21
|
+
value: number;
|
|
22
|
+
duration: number;
|
|
23
|
+
ease: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
text: {
|
|
27
|
+
uAniInText: {
|
|
28
|
+
value: number;
|
|
29
|
+
duration: number;
|
|
30
|
+
ease: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
canvasElement: {
|
|
35
|
+
zIndex: number;
|
|
36
|
+
};
|
|
37
|
+
prefersReducedMotion: boolean;
|
|
38
|
+
isMobile: boolean;
|
|
39
|
+
disabled: boolean;
|
|
40
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import scrollFragment from "./shaders/scrollFragment.glsl";
|
|
2
|
+
import scrollVertex from "./shaders/scrollVertex.glsl";
|
|
3
|
+
import projectBlurFragment from "./shaders/projectBlurFragment.glsl";
|
|
4
|
+
import projectBlurVertex from "./shaders/projectBlurVertex.glsl";
|
|
5
|
+
import TextBlurFragment from "./shaders/TextBlurFragment.glsl";
|
|
6
|
+
import TextBlurVertex from "./shaders/TextBlurVertex.glsl";
|
|
7
|
+
export const defaultCanvas3Options = {
|
|
8
|
+
font: {
|
|
9
|
+
fnt: "./font/PPFormula-CondensedBlack.fnt",
|
|
10
|
+
atlas: "./font/PPFormula-CondensedBlack.png"
|
|
11
|
+
// fnt: '',
|
|
12
|
+
// atlas: '',
|
|
13
|
+
},
|
|
14
|
+
shaders: {
|
|
15
|
+
scroll: {
|
|
16
|
+
fragmentShader: scrollFragment,
|
|
17
|
+
vertexShader: scrollVertex
|
|
18
|
+
},
|
|
19
|
+
default: {
|
|
20
|
+
fragmentShader: projectBlurFragment,
|
|
21
|
+
vertexShader: projectBlurVertex,
|
|
22
|
+
textFragment: TextBlurFragment,
|
|
23
|
+
textVertex: TextBlurVertex
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
activateMeshOptions: {
|
|
27
|
+
image: {
|
|
28
|
+
uAniInImage: { value: 0, duration: 1, ease: "power1.inOut" }
|
|
29
|
+
},
|
|
30
|
+
text: {
|
|
31
|
+
uAniInText: { value: 0, duration: 1.5, ease: "power2.out" }
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
canvasElement: {
|
|
35
|
+
zIndex: -1
|
|
36
|
+
},
|
|
37
|
+
prefersReducedMotion: false,
|
|
38
|
+
isMobile: false,
|
|
39
|
+
disabled: false
|
|
40
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Varyings
|
|
2
|
+
varying vec2 vUv;
|
|
3
|
+
|
|
4
|
+
// Uniforms: Common
|
|
5
|
+
uniform float uThreshold;
|
|
6
|
+
uniform float uAlphaTest;
|
|
7
|
+
uniform vec3 uColor;
|
|
8
|
+
uniform sampler2D uMap;
|
|
9
|
+
|
|
10
|
+
varying float vNoise;
|
|
11
|
+
|
|
12
|
+
// Generic uniforms
|
|
13
|
+
uniform float uTime;
|
|
14
|
+
uniform float uAniInText;
|
|
15
|
+
uniform float uDevicePixelRatio;
|
|
16
|
+
uniform vec2 uViewport;
|
|
17
|
+
uniform vec2 uMouse;
|
|
18
|
+
uniform vec2 uMouseMovement;
|
|
19
|
+
uniform vec2 uFooterGameBall;
|
|
20
|
+
uniform vec2 uMeshSize;
|
|
21
|
+
uniform float devicePixelRatio;
|
|
22
|
+
|
|
23
|
+
uniform sampler2D gradientMap;
|
|
24
|
+
|
|
25
|
+
float DISTANCE_COEF = 0.5;
|
|
26
|
+
float uBlurStrength;
|
|
27
|
+
|
|
28
|
+
float median(float r, float g, float b) {
|
|
29
|
+
return max(min(r, g), min(max(r, g), b));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
float createCircleTrail(float radius, vec2 mousePoint) {
|
|
33
|
+
vec2 viewportUv = gl_FragCoord.xy / uViewport / uDevicePixelRatio;
|
|
34
|
+
float viewportAspect = uViewport.x / uViewport.y;
|
|
35
|
+
|
|
36
|
+
vec2 shapeUvTrail = viewportUv - mousePoint;
|
|
37
|
+
shapeUvTrail /= vec2(1.0, viewportAspect);
|
|
38
|
+
shapeUvTrail += mousePoint;
|
|
39
|
+
float distTail = distance(shapeUvTrail, mousePoint);
|
|
40
|
+
|
|
41
|
+
float circleRadius = max(0.0, radius / uViewport.x);
|
|
42
|
+
float dist = smoothstep(circleRadius, circleRadius + 0.05, distTail);
|
|
43
|
+
return dist;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
float createDraggedTrail(
|
|
47
|
+
vec2 mousePoint,
|
|
48
|
+
vec2 mousePointPrev,
|
|
49
|
+
float radiusStart,
|
|
50
|
+
float radiusEnd
|
|
51
|
+
) {
|
|
52
|
+
vec2 viewportUv = gl_FragCoord.xy / uViewport / uDevicePixelRatio;
|
|
53
|
+
float viewportAspect = uViewport.x / uViewport.y;
|
|
54
|
+
|
|
55
|
+
// Adjust UV coordinates for aspect ratio
|
|
56
|
+
vec2 adjustedUv = viewportUv;
|
|
57
|
+
adjustedUv.y /= viewportAspect;
|
|
58
|
+
vec2 adjustedMousePoint = vec2(mousePoint.x, mousePoint.y / viewportAspect);
|
|
59
|
+
vec2 adjustedMousePointPrev = vec2(
|
|
60
|
+
mousePointPrev.x,
|
|
61
|
+
mousePointPrev.y / viewportAspect
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Compute distances to current and previous mouse points
|
|
65
|
+
float distToCurrent = distance(adjustedUv, adjustedMousePoint);
|
|
66
|
+
float distToPrev = distance(adjustedUv, adjustedMousePointPrev);
|
|
67
|
+
|
|
68
|
+
// Interpolate radius based on proximity to current or previous point
|
|
69
|
+
float interpFactor = distToCurrent / (distToCurrent + distToPrev + 0.0001);
|
|
70
|
+
float circleRadius = mix(radiusStart, radiusEnd, interpFactor) / uViewport.x;
|
|
71
|
+
|
|
72
|
+
// Compute minimum distance to the line segment between points
|
|
73
|
+
vec2 lineDir = adjustedMousePointPrev - adjustedMousePoint;
|
|
74
|
+
float lineLength = length(lineDir);
|
|
75
|
+
vec2 lineDirNorm = lineDir / (lineLength + 0.0001);
|
|
76
|
+
float proj = clamp(
|
|
77
|
+
dot(adjustedUv - adjustedMousePoint, lineDirNorm),
|
|
78
|
+
0.0,
|
|
79
|
+
lineLength
|
|
80
|
+
);
|
|
81
|
+
vec2 closestPoint = adjustedMousePoint + lineDirNorm * proj;
|
|
82
|
+
float distToLine = distance(adjustedUv, closestPoint);
|
|
83
|
+
|
|
84
|
+
// Smoothly fade out the trail based on distance
|
|
85
|
+
float trail = smoothstep(circleRadius, circleRadius + 0.02, distToLine);
|
|
86
|
+
return trail;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
float createOverlay(float activeOverlay) {
|
|
90
|
+
vec2 viewportUv =
|
|
91
|
+
gl_FragCoord.xy / uViewport * uDevicePixelRatio * (1.0 - activeOverlay);
|
|
92
|
+
float progress = smoothstep(
|
|
93
|
+
activeOverlay,
|
|
94
|
+
activeOverlay - 1.0,
|
|
95
|
+
viewportUv.x - vUv.x
|
|
96
|
+
);
|
|
97
|
+
return progress;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
void main() {
|
|
101
|
+
vec2 mousePoint = vec2(uMouse.x, 1.0 - uMouse.y);
|
|
102
|
+
vec2 mousePointPrev = vec2(uMouseMovement.x, 1.0 - uMouseMovement.y);
|
|
103
|
+
vec2 ballPoint = vec2(uFooterGameBall.x, 1.0 - uFooterGameBall.y);
|
|
104
|
+
|
|
105
|
+
float circleTrail = createDraggedTrail(mousePoint, mousePointPrev, 35.0, 1.0);
|
|
106
|
+
|
|
107
|
+
float ballTrail = createCircleTrail(10.0, ballPoint);
|
|
108
|
+
|
|
109
|
+
float overlayOpacity = createOverlay(uAniInText);
|
|
110
|
+
vec2 newUv = vUv;
|
|
111
|
+
|
|
112
|
+
vec3 mySample = texture2D(uMap, newUv).rgb;
|
|
113
|
+
vec3 mySampleRGB = mySample.rgb;
|
|
114
|
+
|
|
115
|
+
float aniInDistance = mix(0.5, 1.0, uAniInText * overlayOpacity);
|
|
116
|
+
|
|
117
|
+
float sigDist =
|
|
118
|
+
median(mySampleRGB.r, mySampleRGB.g, mySampleRGB.b) -
|
|
119
|
+
DISTANCE_COEF / aniInDistance / ballTrail / circleTrail;
|
|
120
|
+
float fill = clamp(sigDist / fwidth(sigDist) + DISTANCE_COEF, 0.0, 1.0);
|
|
121
|
+
|
|
122
|
+
float finalAlpha = fill * overlayOpacity * ballTrail * circleTrail;
|
|
123
|
+
|
|
124
|
+
gl_FragColor = vec4(uColor, finalAlpha);
|
|
125
|
+
if (finalAlpha < uAlphaTest) discard;
|
|
126
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying vec2 vUv;
|
|
4
|
+
uniform sampler2D uImage;
|
|
5
|
+
|
|
6
|
+
uniform float uHover;
|
|
7
|
+
uniform vec2 uMouse;
|
|
8
|
+
uniform float uAniInImage;
|
|
9
|
+
|
|
10
|
+
uniform vec2 uMeshSize; // The size of the mesh (width, height)
|
|
11
|
+
uniform vec2 uTextureSize; // The size of the texture (width, height)
|
|
12
|
+
uniform vec2 uViewport;
|
|
13
|
+
uniform float uDevicePixelRatio;
|
|
14
|
+
|
|
15
|
+
vec3 draw(sampler2D image, vec2 uv) {
|
|
16
|
+
return texture2D(image, vec2(uv.x, uv.y)).rgb;
|
|
17
|
+
}
|
|
18
|
+
float rand(vec2 co) {
|
|
19
|
+
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
vec3 blur(vec2 uv, sampler2D image, float blurAmount, float blurStrength) {
|
|
23
|
+
vec3 blurredImage = vec3(0.0);
|
|
24
|
+
float gradient =
|
|
25
|
+
smoothstep(0.8, 0.0, 3.4 - gl_FragCoord.y / uViewport.y / uViewport.y) *
|
|
26
|
+
blurStrength +
|
|
27
|
+
smoothstep(0.8, 0.0, gl_FragCoord.y / uViewport.y / uViewport.y) *
|
|
28
|
+
blurStrength;
|
|
29
|
+
#define repeats (40.0)
|
|
30
|
+
for (float i = 0.0; i < repeats; i++) {
|
|
31
|
+
vec2 q =
|
|
32
|
+
vec2(
|
|
33
|
+
cos(degrees(i / repeats * 360.0)),
|
|
34
|
+
sin(degrees(i / repeats * 360.0))
|
|
35
|
+
) *
|
|
36
|
+
(rand(vec2(i, uv.x + uv.y)) + blurAmount);
|
|
37
|
+
vec2 uv2 = uv + q * blurAmount * gradient;
|
|
38
|
+
blurredImage += draw(image, uv2) / 2.0;
|
|
39
|
+
q =
|
|
40
|
+
vec2(
|
|
41
|
+
cos(degrees(i / repeats * 360.0)),
|
|
42
|
+
sin(degrees(i / repeats * 360.0))
|
|
43
|
+
) *
|
|
44
|
+
(rand(vec2(i + 2.0, uv.x + uv.y + 24.0)) + blurAmount);
|
|
45
|
+
uv2 = uv + q * blurAmount * gradient;
|
|
46
|
+
blurredImage += draw(image, uv2) / 2.0;
|
|
47
|
+
}
|
|
48
|
+
return blurredImage / repeats;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
float DISTANCE_COEF = 0.5;
|
|
52
|
+
|
|
53
|
+
float createCircle(float radius) {
|
|
54
|
+
vec2 viewportUv = gl_FragCoord.xy / uViewport / uDevicePixelRatio;
|
|
55
|
+
float viewportAspect = uViewport.x / uViewport.y;
|
|
56
|
+
|
|
57
|
+
vec2 mousePoint = vec2(uMouse.x, 1.0 - uMouse.y);
|
|
58
|
+
|
|
59
|
+
vec2 shapeUv = viewportUv - mousePoint;
|
|
60
|
+
shapeUv /= vec2(1.0, viewportAspect);
|
|
61
|
+
shapeUv += mousePoint;
|
|
62
|
+
float dist = distance(shapeUv, mousePoint);
|
|
63
|
+
|
|
64
|
+
float circleRadius = max(0.0, radius / uViewport.x);
|
|
65
|
+
|
|
66
|
+
dist = smoothstep(circleRadius, circleRadius + 0.05, dist);
|
|
67
|
+
return dist;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
float createOverlayBlur(float activeOverlay) {
|
|
71
|
+
vec2 viewportUv = gl_FragCoord.xy / uViewport / uDevicePixelRatio;
|
|
72
|
+
float progress = smoothstep(
|
|
73
|
+
activeOverlay - 1.0, // -1 0
|
|
74
|
+
activeOverlay, // 0 1
|
|
75
|
+
viewportUv.y - vUv.y
|
|
76
|
+
);
|
|
77
|
+
return progress;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
float createOverlayOpacity(float activeOverlay) {
|
|
81
|
+
vec2 viewportUv =
|
|
82
|
+
uMeshSize.y / uViewport * uDevicePixelRatio * (1.0 - activeOverlay);
|
|
83
|
+
float progress = smoothstep(
|
|
84
|
+
activeOverlay,
|
|
85
|
+
activeOverlay - 1.0,
|
|
86
|
+
viewportUv.y - vUv.y
|
|
87
|
+
);
|
|
88
|
+
return progress;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Function to apply a sepia tone to a given RGB color
|
|
92
|
+
vec3 applySepia(vec3 color) {
|
|
93
|
+
float r = color.r;
|
|
94
|
+
float g = color.g;
|
|
95
|
+
float b = color.b;
|
|
96
|
+
|
|
97
|
+
vec3 sepiaColor = vec3(
|
|
98
|
+
clamp(r * 0.358 + g * 0.704 + b * 0.138, 0.0, 1.0),
|
|
99
|
+
clamp(r * 0.357 + g * 0.705 + b * 0.141, 0.0, 1.0),
|
|
100
|
+
clamp(r * 0.3 + g * 0.497 + b * 0.203, 0.0, 1.0)
|
|
101
|
+
);
|
|
102
|
+
return mix(sepiaColor, vec3(0.5), 0.5);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
void main() {
|
|
106
|
+
float overlayBlur = createOverlayBlur(uHover);
|
|
107
|
+
float circle = createCircle(105.0);
|
|
108
|
+
|
|
109
|
+
// Calculate the aspect ratios
|
|
110
|
+
float meshAspect = uMeshSize.x / uMeshSize.y;
|
|
111
|
+
float textureAspect = uTextureSize.x / uTextureSize.y;
|
|
112
|
+
|
|
113
|
+
// Adjust UV coordinates to maintain aspect ratio
|
|
114
|
+
vec2 uv = vUv;
|
|
115
|
+
if (meshAspect > textureAspect) {
|
|
116
|
+
// Mesh is wider than the texture
|
|
117
|
+
float scale = textureAspect / meshAspect;
|
|
118
|
+
uv.y = uv.y * scale + (1.0 - scale) / 2.0; // Center the texture vertically
|
|
119
|
+
} else {
|
|
120
|
+
// Mesh is taller than the texture
|
|
121
|
+
float scale = meshAspect / textureAspect;
|
|
122
|
+
uv.x = uv.x * scale + (1.0 - scale) / 2.0; // Center the texture horizontally
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
float overlayOpacity = createOverlayOpacity(uAniInImage);
|
|
127
|
+
|
|
128
|
+
// Apply sepia to the texture color
|
|
129
|
+
float blurStrength = 1.0 * circle * overlayBlur;
|
|
130
|
+
float blurAmount = 0.025;
|
|
131
|
+
|
|
132
|
+
vec3 originalColor = blur(uv, uImage, blurAmount, blurStrength);
|
|
133
|
+
vec3 sepiaColor = mix(
|
|
134
|
+
originalColor,
|
|
135
|
+
applySepia(originalColor),
|
|
136
|
+
circle
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
vec4 final = vec4(sepiaColor, overlayOpacity);
|
|
140
|
+
|
|
141
|
+
gl_FragColor = final;
|
|
142
|
+
|
|
143
|
+
}
|