@bbki.ng/site 5.4.26 → 5.4.27
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/CHANGELOG.md +8 -0
- package/package.json +2 -2
- package/src/blog/components/effect-layer/EffectContextProvider.tsx +1 -0
- package/src/blog/components/effect-layer/effects/spiral.frag +93 -0
- package/src/blog/components/effect-layer/hooks/useRender.ts +51 -1
- package/src/blog/components/effect-layer/main.frag +4 -0
- package/src/blog/components/effect-layer/uniforms.ts +12 -0
- package/src/blog/pages/streaming/index.tsx +1 -5
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.27",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"react-dom": "^18.0.0",
|
|
15
15
|
"react-router-dom": "6",
|
|
16
16
|
"swr": "^2.2.5",
|
|
17
|
-
"@bbki.ng/ui": "0.1.
|
|
17
|
+
"@bbki.ng/ui": "0.1.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@eslint/compat": "^1.0.0",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
uniform float uLoading;
|
|
2
|
+
uniform float uSpiralProgress;
|
|
3
|
+
uniform float uSpiralOpacity;
|
|
4
|
+
|
|
5
|
+
const float PI2 = 3.141592653589793 * 2.0;
|
|
6
|
+
|
|
7
|
+
vec3 spiralCurve(float _percent) {
|
|
8
|
+
const float _length = 0.3;
|
|
9
|
+
const float radius = 0.056;
|
|
10
|
+
float t = mod(_percent, 0.25) / 0.25;
|
|
11
|
+
t = mod(_percent, 0.25) - (2.0 * (1.0 - t) * t * -0.0185 + t * t * 0.25);
|
|
12
|
+
float x = _length * sin(PI2 * _percent);
|
|
13
|
+
float y = radius * cos(PI2 * 3.0 * _percent);
|
|
14
|
+
|
|
15
|
+
if (
|
|
16
|
+
floor(_percent / 0.25) == 0.0
|
|
17
|
+
|| floor(_percent / 0.25) == 2.0
|
|
18
|
+
) {
|
|
19
|
+
t = t * -1.0;
|
|
20
|
+
}
|
|
21
|
+
float z = radius * sin(PI2 * 2.0 * (_percent - t));
|
|
22
|
+
return vec3(x, y, z);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
vec3 rotateXVec3(vec3 v, float angle) {
|
|
26
|
+
float c = cos(angle);
|
|
27
|
+
float s = sin(angle);
|
|
28
|
+
return vec3(
|
|
29
|
+
v.x,
|
|
30
|
+
v.y * c - v.z * s,
|
|
31
|
+
v.y * s + v.z * c
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void drawSpiral(vec2 uv) {
|
|
36
|
+
if (uLoading < 0.5) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
float aspect = uResolution.x / uResolution.y;
|
|
41
|
+
vec2 center = vec2(0.5, 0.6);
|
|
42
|
+
vec2 p = uv - center;
|
|
43
|
+
p.x *= aspect;
|
|
44
|
+
|
|
45
|
+
float scale = 4.0;
|
|
46
|
+
p *= scale;
|
|
47
|
+
|
|
48
|
+
// early exit: spiral fits within radius ~0.35 in curve space
|
|
49
|
+
if (length(p) > 0.5) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
float minDist = 1.0;
|
|
54
|
+
|
|
55
|
+
const int SAMPLES = 80;
|
|
56
|
+
vec2 prevProjected;
|
|
57
|
+
for (int i = 0; i < SAMPLES; i++) {
|
|
58
|
+
float pct = float(i) / float(SAMPLES);
|
|
59
|
+
vec3 pos3d = spiralCurve(pct);
|
|
60
|
+
vec3 rotated = rotateXVec3(pos3d, uSpiralProgress);
|
|
61
|
+
vec2 projected = rotated.xy;
|
|
62
|
+
|
|
63
|
+
if (i > 0) {
|
|
64
|
+
// distance from point to line segment
|
|
65
|
+
vec2 ab = projected - prevProjected;
|
|
66
|
+
vec2 ap = p - prevProjected;
|
|
67
|
+
float t = clamp(dot(ap, ab) / dot(ab, ab), 0.0, 1.0);
|
|
68
|
+
vec2 closest = prevProjected + t * ab;
|
|
69
|
+
float d = distance(p, closest);
|
|
70
|
+
minDist = min(minDist, d);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
prevProjected = projected;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// close the loop: connect last sample back to first
|
|
77
|
+
vec3 firstPos = spiralCurve(0.0);
|
|
78
|
+
vec3 firstRotated = rotateXVec3(firstPos, uSpiralProgress);
|
|
79
|
+
vec2 firstProjected = firstRotated.xy;
|
|
80
|
+
vec2 ab = firstProjected - prevProjected;
|
|
81
|
+
vec2 ap = p - prevProjected;
|
|
82
|
+
float tc = clamp(dot(ap, ab) / dot(ab, ab), 0.0, 1.0);
|
|
83
|
+
vec2 closest = prevProjected + tc * ab;
|
|
84
|
+
float dc = distance(p, closest);
|
|
85
|
+
minDist = min(minDist, dc);
|
|
86
|
+
|
|
87
|
+
float lineWidth = 0.002;
|
|
88
|
+
float alpha = 1.0 - smoothstep(0.0, lineWidth, minDist);
|
|
89
|
+
|
|
90
|
+
float spiralAlpha = alpha * 0.8 * uSpiralOpacity;
|
|
91
|
+
gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.0), spiralAlpha);
|
|
92
|
+
gl_FragColor.a = max(gl_FragColor.a, spiralAlpha);
|
|
93
|
+
}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useContext, useRef } from 'react';
|
|
2
2
|
import { useMousePosition } from '@/hooks/use_mouse_position';
|
|
3
3
|
import { useResolution } from '@/components/effect-layer/hooks/useResolution';
|
|
4
|
+
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
5
|
+
|
|
6
|
+
const SPIRAL_ACCEL = 0.005;
|
|
7
|
+
const SPIRAL_MAX_SPEED = 0.2;
|
|
8
|
+
const FADE_SPEED = 0.04; // ~0→1 in 25 frames (~400ms at 60fps)
|
|
9
|
+
const MIN_DURATION = 800;
|
|
4
10
|
|
|
5
11
|
export const useRender = () => {
|
|
6
12
|
const pos = useMousePosition();
|
|
7
13
|
const resolution = useResolution();
|
|
14
|
+
const { isLoading, isFontLoading } = useContext(GlobalLoadingContext);
|
|
15
|
+
const loadingRef = useRef(false);
|
|
16
|
+
loadingRef.current = isLoading || isFontLoading;
|
|
17
|
+
|
|
18
|
+
const spiralSpeedRef = useRef(0);
|
|
19
|
+
const spiralOpacityRef = useRef(0);
|
|
20
|
+
const loadingStartRef = useRef(0);
|
|
21
|
+
const wasLoadingRef = useRef(false);
|
|
8
22
|
|
|
9
23
|
const onRender = useCallback((inst: any) => {
|
|
10
24
|
if (inst == null) {
|
|
@@ -16,6 +30,42 @@ export const useRender = () => {
|
|
|
16
30
|
|
|
17
31
|
inst.uniforms.uMouse.value[0] = pos.current.x;
|
|
18
32
|
inst.uniforms.uMouse.value[1] = pos.current.y;
|
|
33
|
+
|
|
34
|
+
const now = performance.now();
|
|
35
|
+
const loading = loadingRef.current;
|
|
36
|
+
|
|
37
|
+
// track when loading starts
|
|
38
|
+
if (loading && !wasLoadingRef.current) {
|
|
39
|
+
loadingStartRef.current = now;
|
|
40
|
+
}
|
|
41
|
+
wasLoadingRef.current = loading;
|
|
42
|
+
|
|
43
|
+
// determine if spiral should be visible (loading OR within min duration)
|
|
44
|
+
const elapsed = now - loadingStartRef.current;
|
|
45
|
+
const inMinDuration = !loading && loadingStartRef.current > 0 && elapsed < MIN_DURATION;
|
|
46
|
+
const shouldShow = loading || inMinDuration;
|
|
47
|
+
|
|
48
|
+
// fade in/out
|
|
49
|
+
if (shouldShow) {
|
|
50
|
+
spiralOpacityRef.current = Math.min(1, spiralOpacityRef.current + FADE_SPEED);
|
|
51
|
+
} else {
|
|
52
|
+
spiralOpacityRef.current = Math.max(0, spiralOpacityRef.current - FADE_SPEED);
|
|
53
|
+
if (spiralOpacityRef.current === 0) {
|
|
54
|
+
loadingStartRef.current = 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
inst.uniforms.uLoading.value[0] = spiralOpacityRef.current > 0 ? 1.0 : 0.0;
|
|
59
|
+
inst.uniforms.uSpiralOpacity.value[0] = spiralOpacityRef.current;
|
|
60
|
+
|
|
61
|
+
if (spiralOpacityRef.current > 0) {
|
|
62
|
+
// accelerate to max speed before fade out
|
|
63
|
+
const accel = inMinDuration ? SPIRAL_ACCEL * 4 : SPIRAL_ACCEL;
|
|
64
|
+
spiralSpeedRef.current = Math.min(SPIRAL_MAX_SPEED, spiralSpeedRef.current + accel);
|
|
65
|
+
} else {
|
|
66
|
+
spiralSpeedRef.current = 0;
|
|
67
|
+
}
|
|
68
|
+
inst.uniforms.uSpiralProgress.value[0] += spiralSpeedRef.current;
|
|
19
69
|
}, []);
|
|
20
70
|
|
|
21
71
|
return { onRender };
|
|
@@ -7,6 +7,7 @@ uniform float uDevicePixelRatio;
|
|
|
7
7
|
#define DefaultColor vec4(0.0, 0.0, 0.0, 0.0)
|
|
8
8
|
|
|
9
9
|
#include "effects/grain.frag"
|
|
10
|
+
#include "effects/spiral.frag"
|
|
10
11
|
//#include "shapes/circle.frag"
|
|
11
12
|
|
|
12
13
|
|
|
@@ -21,4 +22,7 @@ void main() {
|
|
|
21
22
|
|
|
22
23
|
// draw grain on nav
|
|
23
24
|
drawGrainOnNav(uv);
|
|
25
|
+
|
|
26
|
+
// draw loading spiral
|
|
27
|
+
drawSpiral(uv);
|
|
24
28
|
}
|