@anglefeint/astro-theme 0.1.13 → 0.1.15

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.
@@ -0,0 +1,253 @@
1
+ export function initHeroCanvas(prefersReducedMotion) {
2
+ var shell = document.querySelector('.hero-shell');
3
+ if (!shell) return;
4
+
5
+ var canvas = shell.querySelector('.hero-canvas');
6
+ var wrap = shell.querySelector('.hero-canvas-wrap');
7
+ if (!canvas || !wrap) return;
8
+
9
+ var src = canvas.getAttribute('data-hero-src');
10
+ if (!src) return;
11
+
12
+ var heroStart = 0;
13
+ var heroRaf = 0;
14
+ var baseCanvas = document.createElement('canvas');
15
+ var baseCtx = baseCanvas.getContext('2d');
16
+ var pixelCanvas = document.createElement('canvas');
17
+ var pixelCtx = pixelCanvas.getContext('2d');
18
+ var noiseCanvas = document.createElement('canvas');
19
+ var noiseCtx = noiseCanvas.getContext('2d');
20
+ var edgeCanvas = document.createElement('canvas');
21
+ var edgeCtx = edgeCanvas.getContext('2d');
22
+ var edgeReady = false;
23
+
24
+ var EDGE_PHASE = 1.8;
25
+ var REVEAL_PHASE = 2.5;
26
+ var INTRO_END = EDGE_PHASE + REVEAL_PHASE;
27
+
28
+ function sizeCanvas() {
29
+ var rect = shell.querySelector('.hero-stack').getBoundingClientRect();
30
+ var dpr = Math.min(window.devicePixelRatio || 1, 2);
31
+ canvas.width = Math.max(2, Math.round(rect.width * dpr));
32
+ canvas.height = Math.max(2, Math.round(rect.height * dpr));
33
+ canvas.style.width = rect.width + 'px';
34
+ canvas.style.height = rect.height + 'px';
35
+ noiseCanvas.width = canvas.width;
36
+ noiseCanvas.height = 64;
37
+ }
38
+
39
+ function drawBase(ctx, img, w, h) {
40
+ var iw = img.width;
41
+ var ih = img.height;
42
+ var scale = Math.max(w / iw, h / ih);
43
+ var sw = w / scale;
44
+ var sh = h / scale;
45
+ var sx = (iw - sw) / 2;
46
+ var sy = (ih - sh) / 2;
47
+ ctx.drawImage(img, sx, sy, sw, sh, 0, 0, w, h);
48
+ }
49
+
50
+ function buildEdge(img) {
51
+ var w = canvas.width;
52
+ var h = canvas.height;
53
+ edgeCanvas.width = w;
54
+ edgeCanvas.height = h;
55
+ baseCanvas.width = w;
56
+ baseCanvas.height = h;
57
+ drawBase(baseCtx, img, w, h);
58
+ drawBase(edgeCtx, img, w, h);
59
+
60
+ var srcImage = edgeCtx.getImageData(0, 0, w, h);
61
+ var d = srcImage.data;
62
+ var out = edgeCtx.createImageData(w, h);
63
+ var od = out.data;
64
+
65
+ for (var y = 1; y < h - 1; y++) {
66
+ for (var x = 1; x < w - 1; x++) {
67
+ var idx = function(px, py) {
68
+ return ((py * w) + px) * 4;
69
+ };
70
+ var i = idx(x, y);
71
+ function luma(px, py) {
72
+ var j = idx(px, py);
73
+ return d[j] * 0.299 + d[j + 1] * 0.587 + d[j + 2] * 0.114;
74
+ }
75
+
76
+ var gx = -luma(x - 1, y - 1) - 2 * luma(x - 1, y) - luma(x - 1, y + 1)
77
+ + luma(x + 1, y - 1) + 2 * luma(x + 1, y) + luma(x + 1, y + 1);
78
+ var gy = -luma(x - 1, y - 1) - 2 * luma(x, y - 1) - luma(x + 1, y - 1)
79
+ + luma(x - 1, y + 1) + 2 * luma(x, y + 1) + luma(x + 1, y + 1);
80
+ var mag = Math.min(255, Math.sqrt(gx * gx + gy * gy));
81
+
82
+ od[i] = Math.min(255, mag * 0.4);
83
+ od[i + 1] = Math.min(255, mag * 0.85);
84
+ od[i + 2] = Math.min(255, mag * 1.0);
85
+ od[i + 3] = mag > 20 ? Math.min(255, mag * 1.5) : 0;
86
+ }
87
+ }
88
+
89
+ edgeCtx.putImageData(out, 0, 0);
90
+ edgeReady = true;
91
+ }
92
+
93
+ function heroRender(t) {
94
+ if (!heroStart) heroStart = t;
95
+ var elapsed = (t - heroStart) * 0.001;
96
+ var ctx = canvas.getContext('2d');
97
+ if (!ctx || !canvas.img) {
98
+ heroRaf = requestAnimationFrame(heroRender);
99
+ return;
100
+ }
101
+
102
+ var w = canvas.width;
103
+ var h = canvas.height;
104
+ ctx.clearRect(0, 0, w, h);
105
+
106
+ if (elapsed < EDGE_PHASE && edgeReady) {
107
+ var edgeFade = Math.min(1, elapsed / 0.5);
108
+ ctx.fillStyle = 'rgba(8, 16, 28, 1)';
109
+ ctx.fillRect(0, 0, w, h);
110
+ ctx.globalAlpha = edgeFade;
111
+ ctx.drawImage(edgeCanvas, 0, 0);
112
+ ctx.globalAlpha = 1;
113
+
114
+ var scanY = (elapsed / EDGE_PHASE) * h;
115
+ ctx.fillStyle = 'rgba(120, 220, 255, 0.3)';
116
+ ctx.fillRect(0, scanY - 1, w, 2);
117
+ var scanGlow = ctx.createLinearGradient(0, scanY - 30, 0, scanY + 30);
118
+ scanGlow.addColorStop(0, 'rgba(120, 220, 255, 0)');
119
+ scanGlow.addColorStop(0.5, 'rgba(120, 220, 255, 0.15)');
120
+ scanGlow.addColorStop(1, 'rgba(120, 220, 255, 0)');
121
+ ctx.fillStyle = scanGlow;
122
+ ctx.fillRect(0, scanY - 30, w, 60);
123
+ } else if (elapsed < INTRO_END) {
124
+ var revealT = (elapsed - EDGE_PHASE) / REVEAL_PHASE;
125
+ var maxBlock = 32;
126
+ var blockSize = Math.max(1, Math.round(maxBlock * (1 - revealT * revealT)));
127
+
128
+ if (blockSize > 1) {
129
+ var smallW = Math.max(1, Math.ceil(w / blockSize));
130
+ var smallH = Math.max(1, Math.ceil(h / blockSize));
131
+ if (pixelCanvas.width !== smallW || pixelCanvas.height !== smallH) {
132
+ pixelCanvas.width = smallW;
133
+ pixelCanvas.height = smallH;
134
+ }
135
+ pixelCtx.clearRect(0, 0, smallW, smallH);
136
+ pixelCtx.drawImage(baseCanvas, 0, 0, smallW, smallH);
137
+ ctx.imageSmoothingEnabled = false;
138
+ ctx.drawImage(pixelCanvas, 0, 0, smallW, smallH, 0, 0, w, h);
139
+ ctx.imageSmoothingEnabled = true;
140
+ } else {
141
+ ctx.drawImage(baseCanvas, 0, 0);
142
+ }
143
+
144
+ var tintAlpha = 0.18 * (1 - revealT);
145
+ ctx.globalCompositeOperation = 'screen';
146
+ ctx.fillStyle = 'rgba(100, 200, 255, ' + tintAlpha + ')';
147
+ ctx.fillRect(0, 0, w, h);
148
+ ctx.globalCompositeOperation = 'source-over';
149
+ } else {
150
+ ctx.drawImage(baseCanvas, 0, 0);
151
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.03)';
152
+ for (var i = 0; i < h; i += 3) {
153
+ ctx.fillRect(0, i, w, 1);
154
+ }
155
+
156
+ var scanPos = ((elapsed * 40) % (h + 60)) - 30;
157
+ var barGrad = ctx.createLinearGradient(0, scanPos - 30, 0, scanPos + 30);
158
+ barGrad.addColorStop(0, 'rgba(120, 220, 255, 0)');
159
+ barGrad.addColorStop(0.5, 'rgba(120, 220, 255, 0.06)');
160
+ barGrad.addColorStop(1, 'rgba(120, 220, 255, 0)');
161
+ ctx.fillStyle = barGrad;
162
+ ctx.fillRect(0, scanPos - 30, w, 60);
163
+
164
+ if (Math.random() < 0.08) {
165
+ var glitchY = Math.random() * h;
166
+ var glitchH = 2 + Math.random() * 12;
167
+ var shiftX = (Math.random() - 0.5) * 12;
168
+ ctx.save();
169
+ ctx.globalAlpha = 0.22;
170
+ ctx.drawImage(baseCanvas, 0, Math.floor(glitchY), w, Math.ceil(glitchH), Math.round(shiftX), Math.floor(glitchY), w, Math.ceil(glitchH));
171
+ ctx.restore();
172
+ }
173
+
174
+ if (elapsed >= 6 && Math.random() < 0.025) {
175
+ var dropoutY = Math.floor(Math.random() * h);
176
+ var dropoutH = 2 + Math.floor(Math.random() * 2);
177
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.85)';
178
+ ctx.fillRect(0, dropoutY, w, dropoutH);
179
+ }
180
+
181
+ if (Math.random() < 0.03) {
182
+ var burstY = Math.random() * h * 0.8;
183
+ var burstH = 4 + Math.random() * 20;
184
+ if (noiseCanvas.width !== w) {
185
+ noiseCanvas.width = w;
186
+ noiseCanvas.height = 64;
187
+ }
188
+
189
+ noiseCtx.clearRect(0, 0, noiseCanvas.width, noiseCanvas.height);
190
+ for (var n = 0; n < 180; n++) {
191
+ var nx = Math.random() * noiseCanvas.width;
192
+ var ny = Math.random() * noiseCanvas.height;
193
+ var nw = 1 + Math.random() * 3;
194
+ var nh = 1 + Math.random() * 2;
195
+ var alpha = 0.08 + Math.random() * 0.18;
196
+ noiseCtx.fillStyle = 'rgba(160,220,255,' + alpha.toFixed(3) + ')';
197
+ noiseCtx.fillRect(nx, ny, nw, nh);
198
+ }
199
+
200
+ ctx.drawImage(
201
+ noiseCanvas,
202
+ 0,
203
+ 0,
204
+ w,
205
+ Math.ceil(Math.min(burstH, noiseCanvas.height)),
206
+ 0,
207
+ Math.floor(burstY),
208
+ w,
209
+ Math.ceil(burstH)
210
+ );
211
+ }
212
+ }
213
+
214
+ heroRaf = requestAnimationFrame(heroRender);
215
+ }
216
+
217
+ var img = new Image();
218
+ img.onload = function() {
219
+ canvas.img = img;
220
+ sizeCanvas();
221
+ buildEdge(img);
222
+ wrap.classList.add('ready');
223
+ if (prefersReducedMotion) {
224
+ var staticCtx = canvas.getContext('2d');
225
+ if (staticCtx) staticCtx.drawImage(baseCanvas, 0, 0);
226
+ return;
227
+ }
228
+ heroRaf = requestAnimationFrame(heroRender);
229
+ };
230
+ img.src = new URL(src, window.location.href).href;
231
+
232
+ window.addEventListener('resize', function() {
233
+ if (canvas.img) {
234
+ sizeCanvas();
235
+ buildEdge(canvas.img);
236
+ }
237
+ }, { passive: true });
238
+
239
+ function onHeroVisibilityChange() {
240
+ if (prefersReducedMotion) return;
241
+ if (document.hidden) {
242
+ if (heroRaf) cancelAnimationFrame(heroRaf);
243
+ heroRaf = 0;
244
+ } else if (canvas.img && !heroRaf) {
245
+ heroRaf = requestAnimationFrame(heroRender);
246
+ }
247
+ }
248
+
249
+ document.addEventListener('visibilitychange', onHeroVisibilityChange);
250
+ window.addEventListener('beforeunload', function() {
251
+ cancelAnimationFrame(heroRaf);
252
+ }, { once: true });
253
+ }
@@ -0,0 +1,73 @@
1
+ export function initPostInteractions(prefersReducedMotion) {
2
+ var glow = document.querySelector('.ai-mouse-glow');
3
+ if (glow) {
4
+ var raf;
5
+ var x = 0;
6
+ var y = 0;
7
+ document.addEventListener('mousemove', function(e) {
8
+ x = e.clientX;
9
+ y = e.clientY;
10
+ if (!raf) {
11
+ raf = requestAnimationFrame(function() {
12
+ glow.style.setProperty('--mouse-x', x + 'px');
13
+ glow.style.setProperty('--mouse-y', y + 'px');
14
+ raf = 0;
15
+ });
16
+ }
17
+ });
18
+ }
19
+
20
+ document.querySelectorAll('.ai-prose-body a[href]').forEach(function(a) {
21
+ var href = a.getAttribute('href') || '';
22
+ if (!href || href.startsWith('#')) return;
23
+ a.classList.add('ai-link-preview');
24
+ try {
25
+ a.setAttribute('data-preview', href.startsWith('http') ? new URL(href, location.origin).hostname : href);
26
+ } catch (_err) {
27
+ a.setAttribute('data-preview', href);
28
+ }
29
+ });
30
+
31
+ var paras = document.querySelectorAll('.ai-prose-body p, .ai-prose-body h2, .ai-prose-body h3, .ai-prose-body pre, .ai-prose-body blockquote, .ai-prose-body ul, .ai-prose-body ol');
32
+ if (window.IntersectionObserver) {
33
+ var io = new IntersectionObserver(function(entries) {
34
+ entries.forEach(function(entry) {
35
+ if (entry.isIntersecting) {
36
+ entry.target.classList.add('ai-para-visible');
37
+ io.unobserve(entry.target);
38
+ }
39
+ });
40
+ }, { rootMargin: '0px 0px -60px 0px', threshold: 0.1 });
41
+
42
+ paras.forEach(function(p) {
43
+ io.observe(p);
44
+ });
45
+ } else {
46
+ paras.forEach(function(p) {
47
+ p.classList.add('ai-para-visible');
48
+ });
49
+ }
50
+
51
+ var regen = document.querySelector('.ai-regenerate');
52
+ var article = document.querySelector('.ai-article');
53
+ var scan = document.querySelector('.ai-load-scan');
54
+ if (regen && article) {
55
+ regen.addEventListener('click', function() {
56
+ regen.disabled = true;
57
+ regen.classList.add('ai-regenerating');
58
+ article.classList.add('ai-regenerate-flash');
59
+ if (scan) {
60
+ scan.style.animation = 'none';
61
+ scan.offsetHeight;
62
+ scan.style.animation = 'ai-scan 0.8s ease-out forwards';
63
+ scan.style.top = '0';
64
+ scan.style.opacity = '1';
65
+ }
66
+ setTimeout(function() {
67
+ article.classList.remove('ai-regenerate-flash');
68
+ regen.classList.remove('ai-regenerating');
69
+ regen.disabled = false;
70
+ }, prefersReducedMotion ? 120 : 1200);
71
+ });
72
+ }
73
+ }
@@ -0,0 +1,117 @@
1
+ export function initNetworkCanvas(prefersReducedMotion) {
2
+ var canvas = document.querySelector('.ai-network-canvas');
3
+ if (!canvas) return;
4
+
5
+ var ctx = canvas.getContext('2d');
6
+ if (!ctx) return;
7
+
8
+ var MAX_DPR = 2;
9
+ var rafId = 0;
10
+ var start = 0;
11
+ var last = 0;
12
+ var fps = prefersReducedMotion ? 1 : 30;
13
+ var frameMs = 1000 / fps;
14
+ var points = [];
15
+ var edges = [];
16
+
17
+ function seededRandom(seed) {
18
+ var s = seed >>> 0;
19
+ return function() {
20
+ s = (1664525 * s + 1013904223) >>> 0;
21
+ return s / 4294967296;
22
+ };
23
+ }
24
+
25
+ function resize() {
26
+ var rect = canvas.getBoundingClientRect();
27
+ var dpr = Math.min(MAX_DPR, window.devicePixelRatio || 1);
28
+ canvas.width = Math.max(2, Math.round(rect.width * dpr));
29
+ canvas.height = Math.max(2, Math.round(rect.height * dpr));
30
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
31
+
32
+ var w = rect.width;
33
+ var h = rect.height;
34
+ var rand = seededRandom(0xA13F09);
35
+ var count = Math.max(20, Math.min(36, Math.round((w * h) / 32000)));
36
+ var connectDist = Math.min(160, Math.max(90, Math.min(w, h) * 0.18));
37
+ var maxEdges = 120;
38
+ points = [];
39
+
40
+ for (var i = 0; i < count; i++) {
41
+ points.push({
42
+ x: 20 + rand() * Math.max(20, w - 40),
43
+ y: 20 + rand() * Math.max(20, h - 40),
44
+ r: 1 + rand() * 1.6,
45
+ p: rand() * Math.PI * 2,
46
+ a: 0.5 + rand() * 0.5,
47
+ });
48
+ }
49
+
50
+ edges = [];
51
+ for (var a = 0; a < points.length; a++) {
52
+ for (var b = a + 1; b < points.length; b++) {
53
+ if (edges.length >= maxEdges) break;
54
+ var dx = points[a].x - points[b].x;
55
+ var dy = points[a].y - points[b].y;
56
+ var d = Math.sqrt(dx * dx + dy * dy);
57
+ if (d < connectDist) edges.push([a, b, d / connectDist]);
58
+ }
59
+ if (edges.length >= maxEdges) break;
60
+ }
61
+ }
62
+
63
+ function render(ts) {
64
+ if (!start) start = ts;
65
+ if (!prefersReducedMotion && ts - last < frameMs) {
66
+ rafId = requestAnimationFrame(render);
67
+ return;
68
+ }
69
+
70
+ last = ts;
71
+ var t = (ts - start) * 0.001;
72
+ var w = canvas.clientWidth;
73
+ var h = canvas.clientHeight;
74
+ ctx.clearRect(0, 0, w, h);
75
+
76
+ for (var i = 0; i < edges.length; i++) {
77
+ var e = edges[i];
78
+ var p1 = points[e[0]];
79
+ var p2 = points[e[1]];
80
+ var alpha = (1 - e[2]) * (prefersReducedMotion ? 0.2 : (0.18 + 0.06 * Math.sin(t * 0.9 + i)));
81
+ ctx.strokeStyle = 'rgba(190, 236, 255,' + Math.max(0.06, alpha).toFixed(3) + ')';
82
+ ctx.lineWidth = 0.6;
83
+ ctx.beginPath();
84
+ ctx.moveTo(p1.x, p1.y);
85
+ ctx.lineTo(p2.x, p2.y);
86
+ ctx.stroke();
87
+ }
88
+
89
+ for (var j = 0; j < points.length; j++) {
90
+ var p = points[j];
91
+ var pulse = prefersReducedMotion ? 1 : (1 + 0.18 * Math.sin(t * 1.5 + p.p));
92
+ ctx.fillStyle = 'rgba(228, 251, 255,' + (0.58 * p.a).toFixed(3) + ')';
93
+ ctx.beginPath();
94
+ ctx.arc(p.x, p.y, p.r * pulse, 0, Math.PI * 2);
95
+ ctx.fill();
96
+ }
97
+
98
+ if (!prefersReducedMotion) rafId = requestAnimationFrame(render);
99
+ }
100
+
101
+ function stop() {
102
+ if (!rafId) return;
103
+ cancelAnimationFrame(rafId);
104
+ rafId = 0;
105
+ }
106
+
107
+ resize();
108
+ render(performance.now());
109
+
110
+ window.addEventListener('resize', resize, { passive: true });
111
+ document.addEventListener('visibilitychange', function() {
112
+ if (prefersReducedMotion) return;
113
+ if (document.hidden) stop();
114
+ else if (!rafId) rafId = requestAnimationFrame(render);
115
+ });
116
+ window.addEventListener('beforeunload', stop, { once: true });
117
+ }
@@ -0,0 +1,52 @@
1
+ export function initReadProgressAndBackToTop(prefersReducedMotion) {
2
+ var progress = document.querySelector('.ai-read-progress');
3
+ var toast = document.querySelector('.ai-stage-toast');
4
+ var stageSeen = { p30: false, p60: false, p90: false };
5
+ var toastTimer = 0;
6
+ var hasScrolled = false;
7
+
8
+ function showStageToast(msg) {
9
+ if (!toast) return;
10
+ toast.textContent = msg;
11
+ toast.classList.add('visible');
12
+ clearTimeout(toastTimer);
13
+ toastTimer = setTimeout(function() {
14
+ toast.classList.remove('visible');
15
+ }, 900);
16
+ }
17
+
18
+ if (progress) {
19
+ function onScroll() {
20
+ var scrollTop = window.scrollY || document.documentElement.scrollTop;
21
+ var scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
22
+ var p = scrollHeight > 0 ? Math.min(1, scrollTop / scrollHeight) : 1;
23
+ progress.style.setProperty('--read-progress', String(p));
24
+ var btn = document.querySelector('.ai-back-to-top');
25
+ if (btn) btn.classList.toggle('visible', scrollTop > 400);
26
+ if (!hasScrolled && scrollTop > 6) hasScrolled = true;
27
+ if (!hasScrolled) return;
28
+ if (!stageSeen.p30 && p >= 0.3) {
29
+ stageSeen.p30 = true;
30
+ showStageToast('context parsed');
31
+ }
32
+ if (!stageSeen.p60 && p >= 0.6) {
33
+ stageSeen.p60 = true;
34
+ showStageToast('inference stable');
35
+ }
36
+ if (!stageSeen.p90 && p >= 0.9) {
37
+ stageSeen.p90 = true;
38
+ showStageToast('output finalized');
39
+ }
40
+ }
41
+
42
+ onScroll();
43
+ window.addEventListener('scroll', onScroll, { passive: true });
44
+ }
45
+
46
+ var backTop = document.querySelector('.ai-back-to-top');
47
+ if (backTop) {
48
+ backTop.addEventListener('click', function() {
49
+ window.scrollTo({ top: 0, behavior: prefersReducedMotion ? 'auto' : 'smooth' });
50
+ });
51
+ }
52
+ }