@rizom/site-rizom 0.2.0-alpha.142
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/dist/index.d.ts +135 -0
- package/dist/index.js +31089 -0
- package/dist/index.js.map +259 -0
- package/package.json +54 -0
- package/src/content.ts +9 -0
- package/src/contracts.ts +157 -0
- package/src/create-site.ts +108 -0
- package/src/index.ts +63 -0
- package/src/runtime/base-site.ts +13 -0
- package/src/runtime/boot/boot.boot.d.ts +2 -0
- package/src/runtime/boot/boot.boot.js +83 -0
- package/src/runtime/canvases/constellation.canvas.d.ts +2 -0
- package/src/runtime/canvases/constellation.canvas.js +307 -0
- package/src/runtime/canvases/prelude.canvas.d.ts +2 -0
- package/src/runtime/canvases/prelude.canvas.js +193 -0
- package/src/runtime/canvases/products.canvas.d.ts +2 -0
- package/src/runtime/canvases/roots.canvas.d.ts +2 -0
- package/src/runtime/canvases/roots.canvas.js +358 -0
- package/src/runtime/canvases/tree.canvas.d.ts +2 -0
- package/src/runtime/canvases/tree.canvas.js +544 -0
- package/src/runtime/default-layout.tsx +10 -0
- package/src/runtime/index.ts +8 -0
- package/src/runtime/plugin.ts +147 -0
- package/src/ui/Badge.tsx +14 -0
- package/src/ui/Button.tsx +56 -0
- package/src/ui/Divider.tsx +12 -0
- package/src/ui/Footer.tsx +76 -0
- package/src/ui/Header.tsx +45 -0
- package/src/ui/Section.tsx +22 -0
- package/src/ui/SideNav.tsx +22 -0
- package/src/ui/cn.ts +1 -0
- package/src/ui/external-link.ts +8 -0
- package/src/ui/frame.tsx +28 -0
- package/src/ui/highlighted-text.tsx +45 -0
- package/src/ui/index.ts +21 -0
- package/src/ui/site-info-links.ts +24 -0
- package/src/ui/types.ts +6 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
const canvas = document.getElementById("heroCanvas");
|
|
3
|
+
if (!canvas) return;
|
|
4
|
+
const W = window.innerWidth;
|
|
5
|
+
const H = window.innerHeight;
|
|
6
|
+
canvas.width = W * dpr;
|
|
7
|
+
canvas.height = H * dpr;
|
|
8
|
+
canvas.style.width = "100%";
|
|
9
|
+
canvas.style.height = "100%";
|
|
10
|
+
const ctx = canvas.getContext("2d");
|
|
11
|
+
ctx.scale(dpr, dpr);
|
|
12
|
+
|
|
13
|
+
const docH = Math.max(document.body.scrollHeight, 5000);
|
|
14
|
+
const stripH = Math.min(docH, 8000);
|
|
15
|
+
let staticCanvas = document.createElement("canvas");
|
|
16
|
+
staticCanvas.width = canvas.width;
|
|
17
|
+
staticCanvas.height = stripH * dpr;
|
|
18
|
+
|
|
19
|
+
let nodes = [];
|
|
20
|
+
let seedPoints = [];
|
|
21
|
+
let builtTheme = null;
|
|
22
|
+
|
|
23
|
+
function buildStatic() {
|
|
24
|
+
const light = isLightMode();
|
|
25
|
+
if (builtTheme === light) return;
|
|
26
|
+
builtTheme = light;
|
|
27
|
+
nodes = [];
|
|
28
|
+
seedPoints = [];
|
|
29
|
+
const rng = createRand(133);
|
|
30
|
+
|
|
31
|
+
staticCanvas = document.createElement("canvas");
|
|
32
|
+
staticCanvas.width = canvas.width;
|
|
33
|
+
staticCanvas.height = stripH * dpr;
|
|
34
|
+
const sctx = staticCanvas.getContext("2d");
|
|
35
|
+
sctx.scale(dpr, dpr);
|
|
36
|
+
|
|
37
|
+
// Ambient subterranean glows scattered throughout the full strip
|
|
38
|
+
const ambientCount = Math.max(6, Math.floor(stripH / 900));
|
|
39
|
+
for (let i = 0; i < ambientCount; i++) {
|
|
40
|
+
const ax = rng.range(W * 0.1, W * 0.9);
|
|
41
|
+
const ay = rng.range(stripH * 0.04, stripH * 0.96);
|
|
42
|
+
const ar = rng.range(W * 0.25, W * 0.55);
|
|
43
|
+
const ag = sctx.createRadialGradient(ax, ay, 0, ax, ay, ar);
|
|
44
|
+
if (!light) {
|
|
45
|
+
ag.addColorStop(0, rgba(C.PURPLE, 0.06));
|
|
46
|
+
ag.addColorStop(0.5, rgba(C.AMBER, 0.018));
|
|
47
|
+
ag.addColorStop(1, rgba(C.BG_DEEP, 0));
|
|
48
|
+
} else {
|
|
49
|
+
ag.addColorStop(0, rgba(C.PURPLE, 0.04));
|
|
50
|
+
ag.addColorStop(1, rgba(C.PURPLE, 0));
|
|
51
|
+
}
|
|
52
|
+
sctx.fillStyle = ag;
|
|
53
|
+
sctx.fillRect(ax - ar, ay - ar, ar * 2, ar * 2);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Recursive root branch — gentle downward bias but can grow in any direction
|
|
57
|
+
function root(x, y, angle, len, w, depth, color, op) {
|
|
58
|
+
if (depth <= 0 || w < 0.18 || len < 4) return;
|
|
59
|
+
const j = rng.range(-0.12, 0.12);
|
|
60
|
+
const downBias = 0.1; // gentle gravity preference
|
|
61
|
+
const ex = x + Math.cos(angle + j) * len;
|
|
62
|
+
const ey = y + Math.sin(angle + j) * len + downBias * len;
|
|
63
|
+
const c1x = x + Math.cos(angle + rng.range(-0.3, 0.3)) * len * 0.35;
|
|
64
|
+
const c1y =
|
|
65
|
+
y +
|
|
66
|
+
Math.sin(angle + rng.range(-0.3, 0.3)) * len * 0.35 +
|
|
67
|
+
downBias * len * 0.3;
|
|
68
|
+
const c2x = x + Math.cos(angle + rng.range(-0.2, 0.2)) * len * 0.7;
|
|
69
|
+
const c2y =
|
|
70
|
+
y +
|
|
71
|
+
Math.sin(angle + rng.range(-0.2, 0.2)) * len * 0.7 +
|
|
72
|
+
downBias * len * 0.6;
|
|
73
|
+
drawGlowBezier(
|
|
74
|
+
sctx,
|
|
75
|
+
[x, y, c1x, c1y, c2x, c2y, ex, ey],
|
|
76
|
+
color,
|
|
77
|
+
w,
|
|
78
|
+
Math.max(2, w * 3),
|
|
79
|
+
op,
|
|
80
|
+
light,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (depth <= 2 || rng.next() < 0.35) {
|
|
84
|
+
const nr = Math.max(0.6, w * 0.5);
|
|
85
|
+
drawGlowNode(sctx, ex, ey, nr, color, op * 0.5, light);
|
|
86
|
+
nodes.push({
|
|
87
|
+
x: ex,
|
|
88
|
+
y: ey,
|
|
89
|
+
r: nr,
|
|
90
|
+
color,
|
|
91
|
+
op: op * 0.5,
|
|
92
|
+
phase: rng.next() * Math.PI * 2,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const nb =
|
|
97
|
+
depth > 3 ? Math.floor(rng.range(1, 3)) : Math.floor(rng.range(1, 2));
|
|
98
|
+
for (let i = 0; i < nb; i++) {
|
|
99
|
+
const spread = depth > 3 ? rng.range(0.5, 1.2) : rng.range(0.6, 1.5);
|
|
100
|
+
const newAngle = angle + rng.range(-spread, spread);
|
|
101
|
+
let nc = color;
|
|
102
|
+
if (depth <= 3 && rng.next() < 0.22) nc = C.AMBER_LT;
|
|
103
|
+
else if (rng.next() < 0.3)
|
|
104
|
+
nc = nc === C.PURPLE ? C.PURPLE_LT : C.PURPLE;
|
|
105
|
+
root(
|
|
106
|
+
ex,
|
|
107
|
+
ey,
|
|
108
|
+
newAngle,
|
|
109
|
+
len * rng.range(0.5, 0.78),
|
|
110
|
+
w * rng.range(0.52, 0.74),
|
|
111
|
+
depth - 1,
|
|
112
|
+
nc,
|
|
113
|
+
op * rng.range(0.55, 0.82),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Distribute seed bulbs across the FULL strip via jittered grid.
|
|
119
|
+
// Cols scale with viewport width (mobile floors at 3); desktop also
|
|
120
|
+
// gets shorter rows so the network feels rich top to bottom.
|
|
121
|
+
const cols = Math.max(3, Math.round(W / 220));
|
|
122
|
+
const cellW = W / cols;
|
|
123
|
+
const cellH = W < 768 ? 480 : 380;
|
|
124
|
+
const rows = Math.ceil(stripH / cellH);
|
|
125
|
+
for (let r = 0; r < rows; r++) {
|
|
126
|
+
for (let c = 0; c < cols; c++) {
|
|
127
|
+
if (rng.next() < 0.25) continue; // sparse holes
|
|
128
|
+
const sx = c * cellW + rng.range(cellW * 0.1, cellW * 0.9);
|
|
129
|
+
const sy = r * cellH + rng.range(cellH * 0.15, cellH * 0.85);
|
|
130
|
+
if (sy > stripH - 20 || sy < 20) continue;
|
|
131
|
+
seedPoints.push({ x: sx, y: sy });
|
|
132
|
+
|
|
133
|
+
// Bioluminescent seed bulb
|
|
134
|
+
const bulbR = rng.range(2.8, 4.8);
|
|
135
|
+
drawGlowNode(
|
|
136
|
+
sctx,
|
|
137
|
+
sx,
|
|
138
|
+
sy,
|
|
139
|
+
bulbR,
|
|
140
|
+
C.AMBER_LT,
|
|
141
|
+
rng.range(0.55, 0.8),
|
|
142
|
+
light,
|
|
143
|
+
);
|
|
144
|
+
nodes.push({
|
|
145
|
+
x: sx,
|
|
146
|
+
y: sy,
|
|
147
|
+
r: bulbR,
|
|
148
|
+
color: C.AMBER_LT,
|
|
149
|
+
op: 0.72,
|
|
150
|
+
phase: rng.next() * Math.PI * 2,
|
|
151
|
+
isSeed: true,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Local root system from this seed — branches in any direction
|
|
155
|
+
const rootCount = Math.floor(rng.range(1, 3));
|
|
156
|
+
for (let p = 0; p < rootCount; p++) {
|
|
157
|
+
const angle = rng.range(0, Math.PI * 2);
|
|
158
|
+
const len = rng.range(60, 130);
|
|
159
|
+
const w = rng.range(1.2, 2.2);
|
|
160
|
+
root(sx, sy, angle, len, w, 4, C.PURPLE, rng.range(0.35, 0.55));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Lateral rhizomatic interconnects between nearby seeds (any pair, not just adjacent)
|
|
166
|
+
const maxConnect = 260;
|
|
167
|
+
const maxConnect2 = maxConnect * maxConnect;
|
|
168
|
+
for (let i = 0; i < seedPoints.length; i++) {
|
|
169
|
+
const a = seedPoints[i];
|
|
170
|
+
for (let j = i + 1; j < seedPoints.length; j++) {
|
|
171
|
+
const b = seedPoints[j];
|
|
172
|
+
const dx = a.x - b.x;
|
|
173
|
+
const dy = a.y - b.y;
|
|
174
|
+
const d2 = dx * dx + dy * dy;
|
|
175
|
+
if (d2 > maxConnect2) continue;
|
|
176
|
+
if (rng.next() > 0.32) continue; // sparse interconnects
|
|
177
|
+
const midX = (a.x + b.x) / 2 + rng.range(-50, 50);
|
|
178
|
+
const midY = (a.y + b.y) / 2 + rng.range(-30, 70); // mild downward dip
|
|
179
|
+
drawGlowBezier(
|
|
180
|
+
sctx,
|
|
181
|
+
[
|
|
182
|
+
a.x,
|
|
183
|
+
a.y,
|
|
184
|
+
a.x + (midX - a.x) * 0.5,
|
|
185
|
+
a.y + (midY - a.y) * 0.4,
|
|
186
|
+
midX + (b.x - midX) * 0.4,
|
|
187
|
+
midY + (b.y - midY) * 0.5,
|
|
188
|
+
b.x,
|
|
189
|
+
b.y,
|
|
190
|
+
],
|
|
191
|
+
rng.next() < 0.7 ? C.PURPLE : C.PURPLE_LT,
|
|
192
|
+
rng.range(0.5, 1.1),
|
|
193
|
+
4,
|
|
194
|
+
rng.range(0.14, 0.26),
|
|
195
|
+
light,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Background capillary fibers — count tracks seed density so the
|
|
201
|
+
// ambient texture scales with viewport (not a fixed number)
|
|
202
|
+
const capCount = Math.floor(seedPoints.length * 2);
|
|
203
|
+
for (let i = 0; i < capCount; i++) {
|
|
204
|
+
const fx = rng.range(0, W);
|
|
205
|
+
const fy = rng.range(0, stripH);
|
|
206
|
+
const fAngle = rng.range(0, Math.PI * 2);
|
|
207
|
+
const fLen = rng.range(25, 70);
|
|
208
|
+
root(
|
|
209
|
+
fx,
|
|
210
|
+
fy,
|
|
211
|
+
fAngle,
|
|
212
|
+
fLen,
|
|
213
|
+
rng.range(0.4, 0.85),
|
|
214
|
+
3,
|
|
215
|
+
rng.next() < 0.6 ? C.PURPLE : C.PURPLE_LT,
|
|
216
|
+
rng.range(0.12, 0.22),
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Drifting spore particles — gentle ambient motion
|
|
222
|
+
const particles = [];
|
|
223
|
+
const rngP = createRand(211);
|
|
224
|
+
const dustC = [C.PURPLE_LT, C.PURPLE, C.AMBER_LT, C.GLOW];
|
|
225
|
+
for (let i = 0; i < 180; i++) {
|
|
226
|
+
particles.push({
|
|
227
|
+
x: rngP.range(0, W),
|
|
228
|
+
y: rngP.range(0, H),
|
|
229
|
+
r: rngP.range(0.3, 1.2),
|
|
230
|
+
vx: rngP.range(-0.04, 0.04),
|
|
231
|
+
vy: rngP.range(0.02, 0.1),
|
|
232
|
+
color: dustC[Math.floor(rngP.next() * dustC.length)],
|
|
233
|
+
alpha: rngP.range(0.04, 0.15),
|
|
234
|
+
phase: rngP.next() * Math.PI * 2,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
buildStatic();
|
|
239
|
+
window._heroRebuild = function () {
|
|
240
|
+
builtTheme = null;
|
|
241
|
+
buildStatic();
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Flowing nutrient pulses spawn at random seed bulbs throughout the strip
|
|
245
|
+
let flows = [];
|
|
246
|
+
let lastFlow = 0;
|
|
247
|
+
|
|
248
|
+
function spawnFlow() {
|
|
249
|
+
if (!seedPoints.length) return;
|
|
250
|
+
const seed = seedPoints[Math.floor(Math.random() * seedPoints.length)];
|
|
251
|
+
flows.push({
|
|
252
|
+
x: seed.x + (Math.random() - 0.5) * 14,
|
|
253
|
+
y: seed.y,
|
|
254
|
+
vy: 60 + Math.random() * 50,
|
|
255
|
+
vx: (Math.random() - 0.5) * 30,
|
|
256
|
+
life: 0,
|
|
257
|
+
maxLife: 5 + Math.random() * 4,
|
|
258
|
+
color: Math.random() < 0.72 ? C.AMBER_LT : C.PURPLE_LT,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let t = 0,
|
|
263
|
+
lastTime = 0;
|
|
264
|
+
function animate(timestamp) {
|
|
265
|
+
if (document.hidden) {
|
|
266
|
+
requestAnimationFrame(animate);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const dt = lastTime ? Math.min((timestamp - lastTime) / 1000, 0.05) : 0.016;
|
|
270
|
+
lastTime = timestamp;
|
|
271
|
+
t += dt;
|
|
272
|
+
|
|
273
|
+
const light = isLightMode();
|
|
274
|
+
const scrollY = window.scrollY || window.pageYOffset;
|
|
275
|
+
const scrollRatio = (scrollY * 0.7) / Math.max(1, docH - H);
|
|
276
|
+
const srcY = scrollRatio * (stripH - H);
|
|
277
|
+
|
|
278
|
+
ctx.clearRect(0, 0, W, H);
|
|
279
|
+
ctx.drawImage(staticCanvas, 0, srcY * dpr, W * dpr, H * dpr, 0, 0, W, H);
|
|
280
|
+
|
|
281
|
+
// Drifting spore particles (viewport-local)
|
|
282
|
+
particles.forEach((p) => {
|
|
283
|
+
p.x += p.vx;
|
|
284
|
+
p.y += p.vy;
|
|
285
|
+
if (p.x < 0) p.x = W;
|
|
286
|
+
if (p.x > W) p.x = 0;
|
|
287
|
+
if (p.y < 0) p.y = H;
|
|
288
|
+
if (p.y > H) p.y = 0;
|
|
289
|
+
const fl = 0.5 + 0.5 * Math.sin(t * 1.5 + p.phase);
|
|
290
|
+
ctx.fillStyle = rgba(p.color, p.alpha * 2 * fl);
|
|
291
|
+
ctx.beginPath();
|
|
292
|
+
ctx.arc(
|
|
293
|
+
p.x,
|
|
294
|
+
p.y,
|
|
295
|
+
p.r * (0.8 + 0.3 * Math.sin(t + p.phase)),
|
|
296
|
+
0,
|
|
297
|
+
Math.PI * 2,
|
|
298
|
+
);
|
|
299
|
+
ctx.fill();
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Spawn + animate flowing nutrients (world-space coords, drawn relative to srcY)
|
|
303
|
+
if (timestamp - lastFlow > 280 && flows.length < 60) {
|
|
304
|
+
lastFlow = timestamp;
|
|
305
|
+
spawnFlow();
|
|
306
|
+
if (Math.random() < 0.5) spawnFlow();
|
|
307
|
+
}
|
|
308
|
+
for (let i = flows.length - 1; i >= 0; i--) {
|
|
309
|
+
const f = flows[i];
|
|
310
|
+
f.x += f.vx * dt + Math.sin(t * 0.5 + i) * 0.4;
|
|
311
|
+
f.y += f.vy * dt;
|
|
312
|
+
f.life += dt;
|
|
313
|
+
if (f.life > f.maxLife || f.y > stripH) {
|
|
314
|
+
flows.splice(i, 1);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const screenY = f.y - srcY;
|
|
318
|
+
if (screenY < -20 || screenY > H + 20) continue;
|
|
319
|
+
const lr = f.life / f.maxLife;
|
|
320
|
+
const alpha = lr < 0.15 ? lr / 0.15 : lr > 0.85 ? (1 - lr) / 0.15 : 1;
|
|
321
|
+
ctx.fillStyle = rgba(f.color, alpha * 0.35);
|
|
322
|
+
ctx.beginPath();
|
|
323
|
+
ctx.arc(f.x, screenY, 6, 0, Math.PI * 2);
|
|
324
|
+
ctx.fill();
|
|
325
|
+
ctx.fillStyle = rgba(f.color, alpha * 0.55);
|
|
326
|
+
ctx.beginPath();
|
|
327
|
+
ctx.arc(f.x, screenY, 2.6, 0, Math.PI * 2);
|
|
328
|
+
ctx.fill();
|
|
329
|
+
ctx.fillStyle = rgba(light ? C.AMBER_DK : C.CORE, alpha * 0.9);
|
|
330
|
+
ctx.beginPath();
|
|
331
|
+
ctx.arc(f.x, screenY, 1.2, 0, Math.PI * 2);
|
|
332
|
+
ctx.fill();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Pulsing nodes — only those visible in current scroll window
|
|
336
|
+
nodes.forEach((n) => {
|
|
337
|
+
const screenY = n.y - srcY;
|
|
338
|
+
if (screenY < -100 || screenY > H + 100) return;
|
|
339
|
+
const pulse = 0.6 + 0.4 * Math.sin(t * 0.8 + n.phase);
|
|
340
|
+
const pr =
|
|
341
|
+
n.r *
|
|
342
|
+
(n.isSeed
|
|
343
|
+
? 1.4 + Math.sin(t * 0.6 + n.phase) * 0.3
|
|
344
|
+
: 2 + Math.sin(t * 0.7 + n.phase));
|
|
345
|
+
ctx.fillStyle = rgba(n.color, n.op * 0.1 * pulse);
|
|
346
|
+
ctx.beginPath();
|
|
347
|
+
ctx.arc(n.x, screenY, pr * 5, 0, Math.PI * 2);
|
|
348
|
+
ctx.fill();
|
|
349
|
+
ctx.fillStyle = rgba(C.GLOW, n.op * 0.12 * pulse);
|
|
350
|
+
ctx.beginPath();
|
|
351
|
+
ctx.arc(n.x, screenY, pr * 2, 0, Math.PI * 2);
|
|
352
|
+
ctx.fill();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
requestAnimationFrame(animate);
|
|
356
|
+
}
|
|
357
|
+
requestAnimationFrame(animate);
|
|
358
|
+
})();
|