@bbki.ng/site 5.4.39 → 5.4.41
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 +16 -0
- package/index.d.ts +2 -0
- package/index.html +1 -1
- package/package.json +2 -2
- package/src/blog/app.tsx +3 -0
- package/src/blog/components/effect-layer/effects/watermark.frag +112 -0
- package/src/blog/components/effect-layer/hooks/useRender.ts +5 -0
- package/src/blog/components/effect-layer/hooks/useWatermarkHover.ts +45 -0
- package/src/blog/components/effect-layer/main.frag +4 -1
- package/src/blog/components/effect-layer/uniforms.ts +15 -0
- package/src/blog/main.css +3 -0
- package/tsconfig.json +1 -1
- package/vite.config.js +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @bbki.ng/site
|
|
2
2
|
|
|
3
|
+
## 5.4.41
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9b6dfe7: fix safaarea style
|
|
8
|
+
- Updated dependencies [9b6dfe7]
|
|
9
|
+
- @bbki.ng/ui@0.1.15
|
|
10
|
+
|
|
11
|
+
## 5.4.40
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 55e9ad2: add water mark
|
|
16
|
+
- Updated dependencies [55e9ad2]
|
|
17
|
+
- @bbki.ng/ui@0.1.14
|
|
18
|
+
|
|
3
19
|
## 5.4.39
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/index.d.ts
CHANGED
package/index.html
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<html lang="en" class="h-full no-scrollbar">
|
|
3
3
|
<head>
|
|
4
4
|
<title>bbki.ng</title>
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<meta name="description" content="baby king" />
|
|
7
7
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
8
8
|
<link
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.41",
|
|
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.15"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@eslint/compat": "^1.0.0",
|
package/src/blog/app.tsx
CHANGED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Bitmap-font watermark — 4×5 pixel hex glyphs (0-9, a-f)
|
|
2
|
+
// Rendered at the bottom-left corner; meant to be drawn BEFORE grain
|
|
3
|
+
// so that film-grain noise is composited on top of the text.
|
|
4
|
+
|
|
5
|
+
uniform vec4 uHashChars; // hex digit values for chars 0–3 (each 0.0–15.0)
|
|
6
|
+
uniform vec4 uHashChars2; // hex digit values for chars 4–6 (.w unused)
|
|
7
|
+
uniform float uWatermarkHover; // 0.0 = idle (#f1f1f1), 1.0 = hovered (black)
|
|
8
|
+
|
|
9
|
+
// Each glyph is a 4-wide × 5-tall bitmap packed into 20 bits of a float.
|
|
10
|
+
// Bit layout (MSB → LSB): row0-col0 … row0-col3, row1-col0 … row4-col3
|
|
11
|
+
// Row 0 = top of glyph. Requires highp for exact integer representation.
|
|
12
|
+
|
|
13
|
+
highp float charBitmap(float c) {
|
|
14
|
+
// .##. #..# #..# #..# .##.
|
|
15
|
+
if (c < 0.5) return 432534.0; // 0
|
|
16
|
+
// .#.. ##.. .#.. .#.. ###.
|
|
17
|
+
if (c < 1.5) return 312398.0; // 1
|
|
18
|
+
// .##. #..# ..#. .#.. ####
|
|
19
|
+
if (c < 2.5) return 430671.0; // 2
|
|
20
|
+
// ###. ...# .##. ...# ###.
|
|
21
|
+
if (c < 3.5) return 923166.0; // 3
|
|
22
|
+
// #..# #..# #### ...# ...#
|
|
23
|
+
if (c < 4.5) return 630545.0; // 4
|
|
24
|
+
// #### #... ###. ...# ###.
|
|
25
|
+
if (c < 5.5) return 1019422.0; // 5
|
|
26
|
+
// .##. #... ###. #..# .##.
|
|
27
|
+
if (c < 6.5) return 429718.0; // 6
|
|
28
|
+
// #### ...# ..#. .#.. .#..
|
|
29
|
+
if (c < 7.5) return 987716.0; // 7
|
|
30
|
+
// .##. #..# .##. #..# .##.
|
|
31
|
+
if (c < 8.5) return 431766.0; // 8
|
|
32
|
+
// .##. #..# .### ...# .##.
|
|
33
|
+
if (c < 9.5) return 431894.0; // 9
|
|
34
|
+
// .##. #..# #### #..# #..#
|
|
35
|
+
if (c < 10.5) return 434073.0; // a
|
|
36
|
+
// ###. #..# ###. #..# ###.
|
|
37
|
+
if (c < 11.5) return 958110.0; // b
|
|
38
|
+
// .### #... #... #... .###
|
|
39
|
+
if (c < 12.5) return 493703.0; // c
|
|
40
|
+
// ###. #..# #..# #..# ###.
|
|
41
|
+
if (c < 13.5) return 956830.0; // d
|
|
42
|
+
// #### #... ###. #... ####
|
|
43
|
+
if (c < 14.5) return 1019535.0; // e
|
|
44
|
+
// #### #... ###. #... #...
|
|
45
|
+
return 1019528.0; // f
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
float sampleChar(float c, vec2 p) {
|
|
49
|
+
// p in bitmap-pixel coords: x ∈ [0,4), y ∈ [0,5), origin = bottom-left
|
|
50
|
+
if (p.x < 0.0 || p.x >= 4.0 || p.y < 0.0 || p.y >= 5.0) return 0.0;
|
|
51
|
+
|
|
52
|
+
highp float bits = charBitmap(c);
|
|
53
|
+
float col = floor(p.x); // 0 = left
|
|
54
|
+
float row = floor(p.y); // 0 = bottom (screen coords)
|
|
55
|
+
// Map to bit position: row 0 (bottom) → bits 3-0, row 4 (top) → bits 19-16
|
|
56
|
+
highp float idx = row * 4.0 + (3.0 - col);
|
|
57
|
+
return mod(floor(bits / exp2(idx)), 2.0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
float getHashChar(float i) {
|
|
61
|
+
if (i < 0.5) return uHashChars.x;
|
|
62
|
+
if (i < 1.5) return uHashChars.y;
|
|
63
|
+
if (i < 2.5) return uHashChars.z;
|
|
64
|
+
if (i < 3.5) return uHashChars.w;
|
|
65
|
+
if (i < 4.5) return uHashChars2.x;
|
|
66
|
+
if (i < 5.5) return uHashChars2.y;
|
|
67
|
+
return uHashChars2.z;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
void drawWatermark(vec2 uv) {
|
|
71
|
+
// Work in CSS (logical) pixels
|
|
72
|
+
vec2 pixel = gl_FragCoord.xy / uDevicePixelRatio;
|
|
73
|
+
|
|
74
|
+
float scale = 2.0; // each bitmap pixel = 2 CSS px
|
|
75
|
+
float charW = 4.0 * scale; // 8 px per glyph
|
|
76
|
+
float charH = 5.0 * scale; // 10 px per glyph (≈ 12 px visual)
|
|
77
|
+
float gap = 3.0; // 3 px gap between glyphs
|
|
78
|
+
float cellW = charW + gap; // 11 px per cell
|
|
79
|
+
float nChars = 7.0;
|
|
80
|
+
|
|
81
|
+
// Padding from the bottom-left corner of the viewport
|
|
82
|
+
float padX = 16.0;
|
|
83
|
+
float padY = 16.0;
|
|
84
|
+
|
|
85
|
+
vec2 pos = pixel - vec2(padX, padY);
|
|
86
|
+
|
|
87
|
+
// Early-exit bounding box
|
|
88
|
+
float totalW = nChars * cellW - gap;
|
|
89
|
+
if (pos.x < 0.0 || pos.x >= totalW || pos.y < 0.0 || pos.y >= charH) return;
|
|
90
|
+
|
|
91
|
+
// Which character slot?
|
|
92
|
+
float ci = floor(pos.x / cellW);
|
|
93
|
+
if (ci >= nChars) return;
|
|
94
|
+
|
|
95
|
+
// Local x within character cell; skip the inter-glyph gap
|
|
96
|
+
float localX = pos.x - ci * cellW;
|
|
97
|
+
if (localX >= charW) return;
|
|
98
|
+
|
|
99
|
+
// Convert to bitmap-pixel coordinates
|
|
100
|
+
vec2 bp = vec2(localX, pos.y) / scale;
|
|
101
|
+
|
|
102
|
+
float charCode = getHashChar(ci);
|
|
103
|
+
float on = sampleChar(charCode, bp);
|
|
104
|
+
|
|
105
|
+
if (on > 0.5) {
|
|
106
|
+
// Idle: #f1f1f1 (0.945) → Hovered: black (0.0)
|
|
107
|
+
float a = 0.4;
|
|
108
|
+
vec3 col = mix(vec3(0.945), vec3(0.0), uWatermarkHover);
|
|
109
|
+
// Standard alpha-blend (pre-multiplied style)
|
|
110
|
+
gl_FragColor = vec4(col * a, a) + gl_FragColor * (1.0 - a);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
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 { useWatermarkHover } from '@/components/effect-layer/hooks/useWatermarkHover';
|
|
4
5
|
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
5
6
|
|
|
6
7
|
const SPIRAL_ACCEL = 0.005;
|
|
@@ -20,6 +21,8 @@ export const useRender = () => {
|
|
|
20
21
|
const loadingStartRef = useRef(0);
|
|
21
22
|
const wasLoadingRef = useRef(false);
|
|
22
23
|
|
|
24
|
+
const { updateWatermarkHover } = useWatermarkHover();
|
|
25
|
+
|
|
23
26
|
const onRender = useCallback((inst: any) => {
|
|
24
27
|
if (inst == null) {
|
|
25
28
|
return;
|
|
@@ -66,6 +69,8 @@ export const useRender = () => {
|
|
|
66
69
|
spiralSpeedRef.current = 0;
|
|
67
70
|
}
|
|
68
71
|
inst.uniforms.uSpiralProgress.value[0] += spiralSpeedRef.current;
|
|
72
|
+
|
|
73
|
+
updateWatermarkHover(inst);
|
|
69
74
|
}, []);
|
|
70
75
|
|
|
71
76
|
return { onRender };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import { useMousePosition } from '@/hooks/use_mouse_position';
|
|
3
|
+
|
|
4
|
+
// Watermark layout constants (must match watermark.frag)
|
|
5
|
+
const WM_PAD_X = 16;
|
|
6
|
+
const WM_PAD_Y = 16;
|
|
7
|
+
const WM_SCALE = 2;
|
|
8
|
+
const WM_CHAR_W = 4 * WM_SCALE; // 8
|
|
9
|
+
const WM_CHAR_H = 5 * WM_SCALE; // 10
|
|
10
|
+
const WM_GAP = 3;
|
|
11
|
+
const WM_CELL_W = WM_CHAR_W + WM_GAP; // 11
|
|
12
|
+
const WM_N_CHARS = 7;
|
|
13
|
+
const WM_TOTAL_W = WM_N_CHARS * WM_CELL_W - WM_GAP; // 74
|
|
14
|
+
const WM_HOVER_PADDING = 4; // extra hit-area padding (px)
|
|
15
|
+
const WM_HOVER_SPEED = 0.06; // ~0→1 in 17 frames (~280ms at 60fps)
|
|
16
|
+
|
|
17
|
+
export const useWatermarkHover = () => {
|
|
18
|
+
const pos = useMousePosition();
|
|
19
|
+
const hoverRef = useRef(0);
|
|
20
|
+
|
|
21
|
+
const updateWatermarkHover = (inst: any) => {
|
|
22
|
+
// Detect mouse inside watermark bounding box (CSS pixels)
|
|
23
|
+
const viewportH = inst.gl.canvas.height / window.devicePixelRatio;
|
|
24
|
+
const mx = pos.current.x;
|
|
25
|
+
const my = pos.current.y;
|
|
26
|
+
// Convert clientY (top-down) to GL-style bottom-up for comparison
|
|
27
|
+
const myFromBottom = viewportH - my;
|
|
28
|
+
|
|
29
|
+
const inWatermark =
|
|
30
|
+
mx >= WM_PAD_X - WM_HOVER_PADDING &&
|
|
31
|
+
mx <= WM_PAD_X + WM_TOTAL_W + WM_HOVER_PADDING &&
|
|
32
|
+
myFromBottom >= WM_PAD_Y - WM_HOVER_PADDING &&
|
|
33
|
+
myFromBottom <= WM_PAD_Y + WM_CHAR_H + WM_HOVER_PADDING;
|
|
34
|
+
|
|
35
|
+
if (inWatermark) {
|
|
36
|
+
hoverRef.current = Math.min(1, hoverRef.current + WM_HOVER_SPEED);
|
|
37
|
+
} else {
|
|
38
|
+
hoverRef.current = Math.max(0, hoverRef.current - WM_HOVER_SPEED);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
inst.uniforms.uWatermarkHover.value[0] = hoverRef.current;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return { updateWatermarkHover };
|
|
45
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
precision
|
|
1
|
+
precision highp float;
|
|
2
2
|
|
|
3
3
|
uniform vec2 uResolution;
|
|
4
4
|
uniform float uProgress;
|
|
@@ -9,6 +9,7 @@ uniform float uDevicePixelRatio;
|
|
|
9
9
|
#include "effects/grain.frag"
|
|
10
10
|
#include "effects/paper.frag"
|
|
11
11
|
#include "effects/spiral.frag"
|
|
12
|
+
#include "effects/watermark.frag"
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
void main() {
|
|
@@ -16,6 +17,8 @@ void main() {
|
|
|
16
17
|
|
|
17
18
|
gl_FragColor = DefaultColor;
|
|
18
19
|
|
|
20
|
+
drawWatermark(uv);
|
|
21
|
+
|
|
19
22
|
drawPaperTexture(uv);
|
|
20
23
|
|
|
21
24
|
drawGrain(uv);
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
const hashStr: string = typeof GLOBAL_COMMIT_HASH === 'string' ? GLOBAL_COMMIT_HASH : '0000000';
|
|
2
|
+
const hc = [...hashStr].map(c => parseInt(c, 16) || 0);
|
|
3
|
+
|
|
1
4
|
export default {
|
|
2
5
|
uResolution: {
|
|
3
6
|
type: 'vec2',
|
|
@@ -27,4 +30,16 @@ export default {
|
|
|
27
30
|
type: 'float',
|
|
28
31
|
value: [0.0],
|
|
29
32
|
},
|
|
33
|
+
uHashChars: {
|
|
34
|
+
type: 'vec4',
|
|
35
|
+
value: [hc[0] ?? 0, hc[1] ?? 0, hc[2] ?? 0, hc[3] ?? 0],
|
|
36
|
+
},
|
|
37
|
+
uHashChars2: {
|
|
38
|
+
type: 'vec4',
|
|
39
|
+
value: [hc[4] ?? 0, hc[5] ?? 0, hc[6] ?? 0, 0],
|
|
40
|
+
},
|
|
41
|
+
uWatermarkHover: {
|
|
42
|
+
type: 'float',
|
|
43
|
+
value: [0.0],
|
|
44
|
+
},
|
|
30
45
|
};
|
package/src/blog/main.css
CHANGED
|
@@ -61,6 +61,9 @@ body {
|
|
|
61
61
|
overflow: auto;
|
|
62
62
|
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
|
63
63
|
scrollbar-width: none;
|
|
64
|
+
padding-top: env(safe-area-inset-top);
|
|
65
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
66
|
+
box-sizing: border-box;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
#blog::-webkit-scrollbar {
|
package/tsconfig.json
CHANGED
package/vite.config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
2
3
|
import { defineConfig } from 'vite';
|
|
3
4
|
import { VitePWA } from 'vite-plugin-pwa';
|
|
4
5
|
import mdx from '@mdx-js/rollup';
|
|
@@ -59,6 +60,9 @@ export default defineConfig({
|
|
|
59
60
|
},
|
|
60
61
|
define: {
|
|
61
62
|
GLOBAL_BBKING_VERSION: JSON.stringify(process.env.npm_package_version),
|
|
63
|
+
GLOBAL_COMMIT_HASH: JSON.stringify(
|
|
64
|
+
(process.env.GITHUB_SHA || execSync('git rev-parse HEAD').toString().trim()).slice(0, 7)
|
|
65
|
+
),
|
|
62
66
|
},
|
|
63
67
|
esbuild: {
|
|
64
68
|
logOverride: { 'this-is-undefined-in-esm': 'silent' },
|